<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Eric Smalling</title>
    <description>The latest articles on Forem by Eric Smalling (@ericsmalling).</description>
    <link>https://forem.com/ericsmalling</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F941242%2Fa7849ec6-a174-43a1-9587-6b1397b94e66.jpeg</url>
      <title>Forem: Eric Smalling</title>
      <link>https://forem.com/ericsmalling</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ericsmalling"/>
    <language>en</language>
    <item>
      <title>The Docker project turns 10! Looking back at a decade of containers</title>
      <dc:creator>Eric Smalling</dc:creator>
      <pubDate>Fri, 17 Mar 2023 16:30:00 +0000</pubDate>
      <link>https://forem.com/snyk/the-docker-project-turns-10-looking-back-at-a-decade-of-containers-4pph</link>
      <guid>https://forem.com/snyk/the-docker-project-turns-10-looking-back-at-a-decade-of-containers-4pph</guid>
      <description>&lt;h2&gt;
  
  
  The Docker project turns 10! Looking back at a decade of containers
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F0%2A2otZAnGHsWQcFcG2" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F0%2A2otZAnGHsWQcFcG2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;March 15, 2023 marked the 10-year anniversary of &lt;strong&gt;&lt;a href="https://youtu.be/wW9CAH9nSLs" rel="noopener noreferrer"&gt;Solomon Hyke’s famous PyCon lightning talk&lt;/a&gt;&lt;/strong&gt;, when he introduced the world to Docker.&lt;/p&gt;

&lt;p&gt;Let’s look back at how much has changed and hear from some folks who have stories about blazing the trail toward the containerized world we live in today. I opened up my little black book of container and cloud-native contacts and asked them to share stories about their introduction to Docker, and any interesting tales from the trenches over the decade since we first met Moby and Molly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello wowrld!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3536%2F0%2ANDlv7b2QJ0YFQ3_B" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3536%2F0%2ANDlv7b2QJ0YFQ3_B"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Solomon Hykes speaking at PyCon 2013&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In 2013, the world was introduced to Docker. For many developers, it was our first experience with the concepts of c-groups, namespaces, and other Linux technologies used to “contain” processes. As the Docker folks are &lt;strong&gt;&lt;a href="https://www.docker.com/resources/what-container/" rel="noopener noreferrer"&gt;fond&lt;/a&gt;&lt;/strong&gt; of &lt;strong&gt;&lt;a href="https://www.docker.com/blog/introducing-the-moby-project/" rel="noopener noreferrer"&gt;saying&lt;/a&gt;&lt;/strong&gt;, they “democratized” container technology, making it simple to use without a degree in Linux systems administration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mind-blowing and Magical
&lt;/h2&gt;

&lt;p&gt;Some adjectives seemed to come up repeatedly when I asked people about their first experiences with Docker; words like magical, mind-blowing, and “ah-ha moment.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ARyESfhQcP8trx05M" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ARyESfhQcP8trx05M"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Nirmal Mehta speaking at DockerCon 2015&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Picture it! Portland Oregon, 2013, at the Oreilly OpenSource Conference. This was a few months after Docker open source came to life, and it was gaining popularity already within various IT communities: open source, cloud, devops etc. It was the last day of the conference and I attended a Friday early morning session about this new thing called Docker! Solomon Hykes was the speaker and he dove right into the container layer concepts, explaining the capabilities and underlying technologies. He then finished his presentation with a demo, where, if my memory serves me, he proceeded to spin up 5, 10, 15, 20! apache/httpd containers within seconds! Even to the small, bleary eyed crowd that morning and especially to me, it was mind blowing … I instantly had the feeling that I was witnessing the start of a paradigm shift and I wanted to know everything about it!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I know Docker wasn’t the first to pull the underlying technologies together to create isolated processes/containers, but the user experience demonstrated that day — and carried through to today — was magical.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Nirmal Mehta, Principal Specialist SA at AWS&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2356%2F0%2AIWeQlS-ET0pMQDZ0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2356%2F0%2AIWeQlS-ET0pMQDZ0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Brandon Mitchell bundled up with Docker swag&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I remember using Docker the first time, after going through the process to setup a VM to run nginx with tools like Ansible and Chef. I’d spend an hour coming up with a playbook, configure it for the VM that was spun up, and then wait for it to run the install. Then I ran the Docker command to start nginx, and less than 30 seconds later, it had started the process and run it in this magical isolated environment. That was my hook that started the adventure to discover what just happened and how Docker works.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Brandon Mitchell, Solutions Architect at BoxBoat, an IBM Company&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Discovering Docker was like discovering magical powers. This had happened when virtualization took the place of servers, giving me the power to pack VMs into physical infrastructure and get the most use out of it. Docker was like descending into another dream level — now I could pack applications into VMs and get even better use out of the hardware.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Adrian Goins, Retired Developer Advocate at Rancher/SUSE&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2700%2F0%2AbBiEggfygADD37M_" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2700%2F0%2AbBiEggfygADD37M_"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Andy Clemenko, early Docker adopter and field engineer&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In early 2015 I was asked by my employer to become a “Docker” expert. Knowing very little, other than a few Orange site posts, I started playing with it. As with everyone, I started with the classic Docker hello world example of Nginx. For me the “ah ha” moment was instant. Having been a long time system admin, I saw the process isolation as a massive leap forward. From that day forward I shifted my entire career focus towards containers. I was lucky to help the US Government start adopting containers across quite a number of agencies. After a year and a half I was fortunate to be able to continue the Docker journey by joining the company.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Andy Clemenko, Field Engineer at Rancher Government Solutions&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Doomsday scenario
&lt;/h2&gt;

&lt;p&gt;David Flanagan, a year-one Docker adopter, quickly saw how it could revolutionize deployments at his company.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2An1q6-BzBB6yPRRpI" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2An1q6-BzBB6yPRRpI"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;David Flanagan, Founder Rawkode Academy and fun dad&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I first heard of Docker from Solomon’s PyCon demo in 2013. At the time I was working for a UK radio and magazine company as the Director of Development and trying to help them bring their business into the 21st century… digital transformation, right? Their biggest problem was scale, and we actually had a “doomsday” scenario of “How do we handle Lemmy from Motorhead dying?”. Our load was extremely predictable, until it wasn’t. You can’t predict the news and you have to scale in real-time as quickly as possible.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We had used Vagrant and VMs for a while, but scaling those quickly is painful. We had to over provision early and dial back fast when the “event” was over in-order to reduce costs. So when we saw Docker it was a light bulb moment. Except… Docker didn’t have “docker build” back then… However, it followed shortly after and they adopted the tag line still used today, “Build. Ship. Run”. They didn’t just solve the runtime problem, they made the DX of building container images incredibly simple AND provided distribution (ship). Kubernetes and Cloud Native owes the early dotCloud team a huge debt of gratitude, regardless of which container runtime we may be running today.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- David Flanagan, Founder, Rawkode Academy&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Stabilizing the grid
&lt;/h2&gt;

&lt;p&gt;I, too, have been using Docker since the very early days and — if I may be so bold — here’s how it went for me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2364%2F0%2A4n-itOC4jtK-vVXR" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2364%2F0%2A4n-itOC4jtK-vVXR"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;James Spurin’s twitter screenshot: himself, Eric Smalling, Bret Fisher, Chad Crowell, Kunal Kushwaha and Ramesh Kumar at Kubecon 2022&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I started playing with Docker in late 2013, using it in our CI pipelines where we were tasked with running hundreds of functional end-to-end tests against every commit of a large e-commerce web application. We often were running upwards of 2000 browser instances via VM-based *&lt;/em&gt;&lt;a href="https://www.selenium.dev/documentation/legacy/selenium_2/grid_2/" rel="noopener noreferrer"&gt;Selenium2 Grids&lt;/a&gt;** during the peak hours of the day, and the bane of our existence were flaky test results due to grid stability issues. We were constantly spinning up and down instances in the cloud and tried multiple different strategies over the years to improve start-up times, maintain stability, and minimize costs. We even dabbled with spot instances and got into bidding wars in various regions!*&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We had already been experimenting with using Docker for running the web app and test suite controllers, but the lightbulb moment for me was when I realized that I could build an image with the browser and xvfb in it and start it instantly. This allowed us to run stable Selenium grids with as many browsers as we could fit onto a single node! (Our grid stability issues usually stemmed from the node’s inability to scale up many browsers per node, thus requiring many small nodes with small numbers of browsers each.) This was so successful that we largely were able to abandon the cloud-based instances and use just a few local VMs for these grids, saving thousands of dollars per week.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Eric Smalling, Sr. Developer Advocate at Snyk&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Convincing the masses
&lt;/h2&gt;

&lt;p&gt;To anyone new to enterprise software development, the advantages of containers and the ecosystem that evolved around them might seem a forgone conclusion, but for the first 5 or 6 years, Docker’s future was far from certain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results speak for themselves
&lt;/h2&gt;

&lt;p&gt;Change is often hard for humans, but Docker’s demonstrable benefits sold it easily:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I had a history of bringing in new shiny tech, so there was always an air of frustration when “Dave’s got another toy,” and the majority of my team were Mac users, so they definitely hated me!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But Docker was mostly server-side for us, there wasn’t boot2docker, yet so the team continued with Vagrant for dev, and we brought it into that environment eventually when the story kind of told itself. The team saw how it simplified our deployment pipeline, and it won them over.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It was hard to argue against when our deploys went from 40 minutes to about approximately 3!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- David Flanagan&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2AZvfOUstOodKXvurZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2AZvfOUstOodKXvurZ"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sevi Karakula making shift happen!&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When I first encountered Docker, I had been working as a software developer long enough to know how hard it can be to get a new member onboarded to the team with all of the tools they needed. Also, whenever we had tried to introduce new frameworks and languages into the development environment — to make everything eventually a bit lighter — it was often a pain because the usual reaction from most of the developers would be an eye-roll.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Docker made our lives so much easier because it was just this one magical tool to teach the team, and then they’d the benefits immediately without having to deal with all the complexity to install and configure them. It was such a big moment of developer liberation, not having to install every tool on your tightly monitored machine, not having to chase requests to get approved and not having to think about licensing. If there is an image, you were free to go.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Sevi Karakulak, Engineering Lead at Container Solutions&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Not “enterprise ready”
&lt;/h2&gt;

&lt;p&gt;The term “enterprise ready” is subjective, and can mean different things for every company you deal with. Matt Bentley recounts an interesting interpretation of when, as a Solutions Engineer for Docker, he had to address how “attractive” Docker was — or, in this case, wasn’t — in the early days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2Ax4ucXtslOncop2pu" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2Ax4ucXtslOncop2pu"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Matt Bentley at DockerCon 2019&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;… the customer loved Docker as a technology, [and] they loved the Docker Trusted Registry product, but until we had something that wasn’t just API and command line based, their leadership would never see it as being enterprise ready.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;They had a process where they needed to see the products demonstrated to them internally, and if they showed what I did with a CI/CD pipeline built in Jenkins to take code, build &amp;amp; test it in a container, deploy it, promote the image, they wouldn’t understand it because enterprise-ready solutions had pretty user interfaces.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Matt Bentley, Manager, Solutions Engineering at VMware&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A more common hesitancy heard often was about the relative immaturity of the project. Even though the underlying technologies had been around for many years, hitching your wagon to an open-source project spun out of a startup, with &lt;strong&gt;&lt;a href="https://twitter.com/Docker/status/1096109892471992320?lang=en" rel="noopener noreferrer"&gt;cartoon mascots&lt;/a&gt;&lt;/strong&gt; and a &lt;strong&gt;&lt;a href="https://twitter.com/gordonATortoise" rel="noopener noreferrer"&gt;pet turtle&lt;/a&gt;&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://github.com/GordonTheTurtle" rel="noopener noreferrer"&gt;doing deployments&lt;/a&gt;&lt;/strong&gt;, was a bridge too far for many.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2A31PTG_zz6t5mBh5z" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3000%2F0%2A31PTG_zz6t5mBh5z"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Rachel Leeken and Eric Smalling at Kubecon EU 2022&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I started learning about Docker in 2015 and based on the potential I saw, I proposed it might be worth looking into for modernization instead of an older, expensive vendor’s solution at the time. The customer didn’t go with it because they said there were not sure about container technology and if it would even be around for the 5 years of the contract.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Rachel LeeKin, Containers Specialist SA at AWS&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Self-inflicted wounds
&lt;/h2&gt;

&lt;p&gt;Sometimes getting a team to adopt containers was not the hardest task; it was coaching them to do it right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3696%2F0%2Aw163_QCAIvxgRll0" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3696%2F0%2Aw163_QCAIvxgRll0"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Adrian Goins and the Iron Condor, his paramotor quad&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In the beginning, it was hard to convince my clients to do it… Those who did get the idea didn’t always get the benefits or how to leverage a container. I remember one client who had containers that they would shell into, where they’d recompile their application or its dependencies and then commit the container like it was a code repository. Their operational containers were huge and probably more fragile than their original non-container infrastructure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Adrian Goins&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Interest grows
&lt;/h2&gt;

&lt;p&gt;As the years went on, more and more people started to see the potential containers provided, especially as orchestrators matured — although they brought challenges of their own. &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/adrianmouat/" rel="noopener noreferrer"&gt;Adrian Mouat&lt;/a&gt;&lt;/strong&gt; (&lt;strong&gt;&lt;a href="https://twitter.com/adrianmouat" rel="noopener noreferrer"&gt;@adrianmouat&lt;/a&gt;&lt;/strong&gt; | &lt;strong&gt;&lt;a href="https://hachyderm.io/@adrianmouat" rel="noopener noreferrer"&gt;@adrianmouat@hachyderm.io&lt;/a&gt;&lt;/strong&gt;), &lt;strong&gt;&lt;a href="https://www.oreilly.com/library/view/using-docker/9781491915752/" rel="noopener noreferrer"&gt;author&lt;/a&gt;&lt;/strong&gt; and another OG Docker Captain, recalls the experience of the early DockerCon conferences and the flurry of activity as more and more people started to dip their toe in the water and companies started offering solutions to address their needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3998%2F0%2A9Zf7C15ZThvQlUmH" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3998%2F0%2A9Zf7C15ZThvQlUmH"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Adrian Mouat with Betty Junod, Eric Smalling, and Matt Jarvis at KubeCon NA 2022&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;One thing I really remember is how speakers (myself included) would ask, “Who’s using Docker?” in 2014. A forest of hands would go up. “Who’s using Docker in production?“ Pretty much all the hands would go down.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Having said that, the number of people using Docker in prod before it even went 1.0 (Oct 2014) and declared production ready was astounding.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We used to use shipping metaphors and talk about how it solved the “but it works on my machine problem” — unfortunately, k8s came along and recreated that one.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When I was at Container Solutions, we helped organize the first *&lt;/em&gt;&lt;a href="https://web.archive.org/web/20170426193127/http://europe-2014.dockercon.com/" rel="noopener noreferrer"&gt;Docker Con EU&lt;/a&gt;** at the NEMO Science Center. The buzz was pretty amazing; everyone knew they were at the start of something big. CoreOS were there (&lt;strong&gt;&lt;a href="https://web.archive.org/web/20141201181834/https://coreos.com/blog/rocket/" rel="noopener noreferrer"&gt;launching Rocket&lt;/a&gt;&lt;/strong&gt;!), Alexis Richardson was pushing Weave networking, Luke Marsden was running ClusterHQ and the flocker data manager, Timo Derstappen was doing amazing stuff with Giant Swarm. Enterprise companies were everywhere just trying to figure out what the hell was going on.*&lt;br&gt;
 &lt;strong&gt;&lt;em&gt;- Adrian Mouat, Product Manager at Chainguar&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3998%2F0%2Ajwh-n0VLGfhjjC2a" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3998%2F0%2Ajwh-n0VLGfhjjC2a"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Bret Fisher wins “Tip of the Captains Hat” at DockerCon 18 Europe&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I saw Solomon’s PyCon 2013 talk and tried docker to improve our Node.js testing in 2014, and I just didn’t get it. I kept trying to shove a whole server in a container image (and failing), and the networking was complete voodoo to me. It was such a huge stack of new automation magic and concepts that I gave up and returned six months later. This time, it clicked and hit me like a train. The 1–2–3 combo of building images, storing them in registries, and running containers from them blew my mind, and I never looked back.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Bret Fisher, DevOps dude &amp;amp; creator of Docker Mastery&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The orchestrators
&lt;/h2&gt;

&lt;p&gt;If Docker’s announcement at PyCon 2013 is the spark that lit the fire, the advent of container orchestration platforms are the winds that ignited the forest. Mesosphere, Rancher, Swarm, Nomad, and Kubernetes were the “killer apps” that really pushed containers over the edge. Volumes have been written about the pros and cons of each platform, but it can’t be overstated how important they have been to the mass adoption of containers.&lt;/p&gt;

&lt;p&gt;Kubernetes is the dominant platform today but there is still a very loyal community of Swarm users, and Nomad has its pockets of popularity too. Mesos predates Docker, and I’m sure it still has a fair number of users as well. For some, Kubernetes seemed overly complex but as its market share bears out, most people came around to adopting it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When Kubernetes came along, I hated it. It was another layer of abstraction that didn’t provide a lot of additional benefit…until it did. Then I loved it because now I could take those servers, with their VMs, and their containers, and make a little mini datacenter out of it. The fact that a process existed to babysit the thing 24x7 meant that I was free to go do something else.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Adrian Goins&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While Kubernetes is now the de facto standard way to deploy containers, it is interesting to see the evolution of the space and how there are so many abstractions being created around it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;When it became clear that orchestrators were going to be key to container adoption at scale, I thought that there would be room for multiple major orchestrators to be successful. Each was good as it’s own thing and I saw each as having ideal use cases. The thing I loved about Swarm was that I could take someone who understood simple docker run commands or could put together an easy to understand Docker Compose file and get a Swarm service deployed in minutes. The simplicity of the docker CLI and tools like Docker Compose were brilliant because if someone knew how to run containers on a single host with either, it wasn’t a big lift to get them orchestrating containers. Now the industry is working to abstract Kubernetes away from developers because it took too much focus away from developers developing and put it on orchestration. Time spent by developers on orchestration means less focus on delivering business value through the apps they’re working on.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Matt Bentley&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Career-changing and life-changing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2048%2F0%2AlJSankO6uLyvHhLC" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2048%2F0%2AlJSankO6uLyvHhLC"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Moby, the Whale at Docker’s former SFO office&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The common thread among everyone I reached out to for this article was how the Docker project and the community that has grown up around it have changed the careers and, indeed, livelihoods of so many people.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I knew it was the next evolution in infrastructure. I was obsessed and shifted my whole career to nothing but containers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Bret Fisher&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;From that day forward I shifted my entire career focus towards containers… To this day I am still on the mission of educating and leading the US Government on their container journey. It is amazing to see such a transformative technology last for 10 years.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Andy Clemenko&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The more I learned, the more I got hooked by the possibilities containerization offered. Eventually, I started teaching Docker and decided to make a pivot in my career towards containers and then Kubernetes. Looking back now, I can safely say that Docker changed my life.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;- Sevi Karakulak&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Snyk loves open source
&lt;/h2&gt;

&lt;p&gt;We applaud the Docker project for a decade of transformational work, as evidenced by the powerful testimonies of those quoted here as well as the millions of developers who build, ship, and run in containers around the world every day.&lt;/p&gt;

&lt;p&gt;Snyk was founded in 2015 with the goal of empowering developers to code and use open-source software securely — including the containers you put them in. Because we believe so strongly in the power and importance of the open-source development model, we have offered our scanning tools to individual developers free of charge from day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep your open source dependencies secure
&lt;/h2&gt;

&lt;p&gt;Snyk provides one-click fix PRs for vulnerable open source dependencies and their transitive dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[Start free with Github&lt;/strong&gt;](&lt;a href="https://app.snyk.io/auth/auth0/github" rel="noopener noreferrer"&gt;https://app.snyk.io/auth/auth0/github&lt;/a&gt;) | &lt;strong&gt;[Start free with Google&lt;/strong&gt;](&lt;a href="https://app.snyk.io/auth/auth0/google-oauth2" rel="noopener noreferrer"&gt;https://app.snyk.io/auth/auth0/google-oauth2&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;In addition, for open-source project maintainers we offer expanded capabilities. See &lt;a href="https://snyk.io/open-source-projects/" rel="noopener noreferrer"&gt;https://snyk.io/open-source-projects/&lt;/a&gt; for program details and to submit your projects for consideration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribution
&lt;/h2&gt;

&lt;p&gt;Thanks to all who contributed to this article!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Nirmal Mehta&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Principal Specialist Solutions Architect at AWS&lt;/li&gt;
&lt;li&gt;Docker Captain 2016 — Present.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/nirmalkmehta/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/normalfaults" rel="noopener noreferrer"&gt;@normalfaults&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hachyderm.io/@nirmal" rel="noopener noreferrer"&gt;hachyderm.io/@nirmal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Brandon Mitchell&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Solutions Architect at BoxBoat, an IBM Company&lt;/li&gt;
&lt;li&gt;Docker Captain 2018 — Present&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/opencontainers/image-spec" rel="noopener noreferrer"&gt;OCI image-spec&lt;/a&gt; maintainer.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/brandonhmitchell/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/sudo_bmitch" rel="noopener noreferrer"&gt;@sudo_bmitch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hachyderm.io/@bmitch@fosstodon.org" rel="noopener noreferrer"&gt;@bmitch@fosstodon.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Adrian Goins&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Retired Developer Advocate at Rancher/SUSE&lt;/li&gt;
&lt;li&gt;**&lt;a href="https://www.creatoraviator.com/" rel="noopener noreferrer"&gt;content creator and aviator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;long-term Rancher/SUSE Advocate&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/adrian-goins/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/creator_aviator" rel="noopener noreferrer"&gt;@creator_aviator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;David Flanagan&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Founder, **&lt;a href="https://rawkode.academy/" rel="noopener noreferrer"&gt;Rawkode Academy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;creator of **&lt;a href="https://kubehuddle.com/" rel="noopener noreferrer"&gt;KubeHuddle Conference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/rawkode/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/rawkode" rel="noopener noreferrer"&gt;@rawkode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Andy Clemenko&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Field Engineer at Rancher Government Solutions&lt;/li&gt;
&lt;li&gt;former Docker SA and SE&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/clemenko/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/clemenko" rel="noopener noreferrer"&gt;@clemenko&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hachyderm.io/@clemenko" rel="noopener noreferrer"&gt;@clemenko@hachyderm.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Sevi Karakulak&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Engineering Lead at Container Solutions&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/sevikarakulak/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/sevikarakulak" rel="noopener noreferrer"&gt;@sevikarakulak&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Matt Bentley&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Manager, Solutions Engineering at VMware&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/matthewbbentley/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/matthewbentley" rel="noopener noreferrer"&gt;@matthewbentley&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hachyderm.io/@mbentley" rel="noopener noreferrer"&gt;@mbentley@hachyderm.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rachel Leekin&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Containers Specialist Solutions Architect at AWS&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/rachel-leekin/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/Rachel_LeeKin" rel="noopener noreferrer"&gt;@Rachel_LeeKin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Adrian Mouat&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Product Manager at Chainguard&lt;/li&gt;
&lt;li&gt;Docker Captain 2016 — Present&lt;/li&gt;
&lt;li&gt;author: &lt;a href="https://www.oreilly.com/library/view/using-docker/9781491915752/" rel="noopener noreferrer"&gt;Using Docker&lt;/a&gt; (O’Reilly Media, 2016)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/adrianmouat/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/adrianmouat" rel="noopener noreferrer"&gt;@adrianmouat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hachyderm.io/@adrianmouat" rel="noopener noreferrer"&gt;@adrianmouat@hachyderm.io&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>containers</category>
      <category>docker</category>
      <category>opensource</category>
      <category>history</category>
    </item>
    <item>
      <title>Container images simplified with Ko</title>
      <dc:creator>Eric Smalling</dc:creator>
      <pubDate>Mon, 10 Oct 2022 14:24:49 +0000</pubDate>
      <link>https://forem.com/snyk/container-images-simplified-with-ko-2pa4</link>
      <guid>https://forem.com/snyk/container-images-simplified-with-ko-2pa4</guid>
      <description>&lt;p&gt;In a &lt;a href="https://snyk.io/blog/building-java-container-images-using-jib/"&gt;previous article&lt;/a&gt;, I wrote about how — &lt;em&gt;and why&lt;/em&gt; — you might want to use the Google Open Source group’s &lt;a href="https://github.com/GoogleContainerTools/jib"&gt;Jib&lt;/a&gt; tool to build your Java application container images. Jib builds slim, JVM-based, OCI-compliant images that follow best practice guidelines without the need for a container runtime like Docker, and it removes the need to write and manage Dockerfiles. What if you are building &lt;a href="https://go.dev/"&gt;Go&lt;/a&gt; applications, though? Well, there is another open source tool for Go that works similarly called &lt;a href="https://github.com/ko-build/ko"&gt;Ko&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During the drafting of this article, the Ko project was &lt;a href="https://github.com/ko-build/ko/issues/791"&gt;migrated&lt;/a&gt; from a Google owned GitHub repository to it’s own top-level organization, “&lt;a href="https://github.com/ko-build"&gt;ko-build&lt;/a&gt;“. We have updated verbiage in this post to reflect this but references to “Google Ko” may still be found online and in module names for a while, be assured that this is the same project. Congratulations to the Ko project for the success that merited this migration!&lt;/p&gt;

&lt;p&gt;In this article, we’ll look at using Ko to build container images without Dockerfiles, SBOMs, and integrating with Kubernetes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Ko?
&lt;/h2&gt;

&lt;p&gt;Ko is a single binary, command line tool that is designed to be used in your development process in place of where you run the &lt;code&gt;go&lt;/code&gt; compiler today. In addition to compiling your application, it will also generate an ultra slimmed-down container image that has your application installed in it. Like Jib, Ko will push the image to a registry or drop it into your local Docker image cache, depending on how you configure and/or run it.&lt;/p&gt;

&lt;p&gt;Ko also has a few additional tricks up its sleeve related to &lt;a href="https://snyk.io/learn/software-bill-of-materials/"&gt;software bill of materials (SBOM)&lt;/a&gt; construction as well as Kubernetes integration to help make iterative development and deployment processes super simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  What problems is Ko trying to solve?
&lt;/h2&gt;

&lt;p&gt;Many programmers, regardless of the language they work with, are new to container construction and often have a lot of questions about image building such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which base image should I use, and is it compliant with my organization’s policies?&lt;/li&gt;
&lt;li&gt;How do I best combine commands to minimize layer bloat?&lt;/li&gt;
&lt;li&gt;How much of my app should I copy into the image to run my application?&lt;/li&gt;
&lt;li&gt;What tooling do I need to learn to build the image? (Docker? Buildah? BuildKit?)&lt;/li&gt;
&lt;li&gt;Are there standard annotations I need to include per my organization’s requirements?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Application architects and leads also want to make governance and standards implementation easy for their teams to follow, but maintaining uniform practices can be challenging when every team has unique and organically crafted Dockerfile patterns.&lt;/p&gt;

&lt;p&gt;Security teams also care greatly about what goes into an image and the tooling used to construct it. For example, the practice of exposing the Docker engine — or the host machine’s &lt;code&gt;docker.sock&lt;/code&gt; — to a CI build node can give build environments elevated access levels on those nodes. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;“[The Docker] daemon… has a lot more capabilities beyond building and interacting with registries. Without additional security tooling, any user who can trigger a docker build on this machine can also perform a docker run to execute any command they like on the machine… Not only can they run any command they like, but also, if they use this privilege to perform a malicious action, it will be hard to track down who was responsible.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;—&lt;/em&gt; &lt;a href="https://learning.oreilly.com/library/view/container-security/9781492056690/ch06.html"&gt;&lt;em&gt;Container Security&lt;/em&gt;&lt;/a&gt; &lt;em&gt;by Liz Rice, Chapter 6&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, introducing new build tools can be complex and increase the learning curve for those in charge of the build systems. Ko aims to address each of these areas while providing a superior experience to the developers using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image building with and without Ko
&lt;/h2&gt;

&lt;p&gt;To describe how Ko addresses the above-listed challenges, let’s first look at an example of how it compares to existing Go + Docker build steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the image without Ko
&lt;/h3&gt;

&lt;p&gt;For this example, we will build the classic Go tutorial application, the “Hello World” web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; In an empty directory, create the following as &lt;code&gt;hello.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", HelloWebServer)
    http.ListenAndServe(":8080", nil)
}

func HelloWebServer(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; We will go ahead and build the binary as part of our Dockerfile as that is a common pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang AS build
WORKDIR /go/src
COPY . .
RUN GOOS=linux go build -ldflags "-linkmode external -extldflags -static" -a hello.go

FROM gcr.io/distroless/static:nonroot
USER nonroot:nonroot
COPY --from=build /go/src/hello .
EXPOSE 8080
CMD ["./hello"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;a href="https://docs.docker.com/build/building/multi-stage/"&gt;multi-stage build&lt;/a&gt;, with the first stage named &lt;code&gt;build&lt;/code&gt;, based on the &lt;code&gt;golang&lt;/code&gt; official image. In this stage, we copy the content of our app (which is simply the &lt;code&gt;hello.go&lt;/code&gt; file at the moment) to the image under &lt;code&gt;/go/src&lt;/code&gt; and simply run the &lt;code&gt;go build&lt;/code&gt; tool with the parameters needed to produce a static binary. &lt;/p&gt;

&lt;p&gt;In the second stage, we start from the &lt;a href="https://github.com/GoogleContainerTools/distroless/tree/main/base"&gt;Google Distroless project’s &lt;code&gt;static:nonroot&lt;/code&gt; base image&lt;/a&gt;, set the default user to &lt;code&gt;nonroot&lt;/code&gt;, copy the &lt;code&gt;hello&lt;/code&gt; binary from the &lt;code&gt;build&lt;/code&gt; stage into the top-level directory, set some metadata about the port we want to expose, and define that &lt;code&gt;./hello&lt;/code&gt; gets run by default at container startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why two stages?
&lt;/h3&gt;

&lt;p&gt;It is a common practice to do the build of your application in the Dockerfile as this guarantees that the right version of your compiler gets used both on a developer’s workstation and in any automated builds. A common error, though, is to deploy the same image that the build happened in. This is a security risk because you end up including not only extraneous tooling like the compiler, but also the source code of your application in that deployed image. If an attacker is able to exploit a vulnerability or get a copy of your image, they will have a lot of information and tools at their disposal to expand their attack. By starting from the &lt;code&gt;distroless/static:nonroot&lt;/code&gt; base image, we have an extremely minimal filesystem with a non-root default user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; With our Dockerfile sorted out, we now can use the &lt;code&gt;docker build&lt;/code&gt; command to construct a locally cached image and give it a tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t localhost:5000/hello-go:1.2.3 .
[+] Building 5.6s (12/12) FINISHED
 =&amp;gt; [internal] load build definition from Dockerfile
 =&amp;gt; =&amp;gt; transferring dockerfile: 298B
 =&amp;gt; [internal] load .dockerignore
 =&amp;gt; =&amp;gt; transferring context: 73B
 =&amp;gt; [internal] load metadata for gcr.io/distroless/static:nonroot
 =&amp;gt; [internal] load metadata for docker.io/library/golang:latest
 =&amp;gt; [stage-1 1/2] FROM gcr.io/distroless/static:nonroot
 =&amp;gt; CACHED [build 1/4] FROM docker.io/library/golang
 =&amp;gt; [internal] load build context
 =&amp;gt; =&amp;gt; transferring context: 5.15kB
 =&amp;gt; [build 2/4] WORKDIR /go/src
 =&amp;gt; [build 3/4] COPY . .
 =&amp;gt; [build 4/4] RUN GOOS=linux go build -ldflags "-linkmode external -extldflags -static" -a hello.go
 =&amp;gt; [stage-1 2/2] COPY --from=build /go/src/hello .
 =&amp;gt; exporting to image
 =&amp;gt; =&amp;gt; exporting layers
 =&amp;gt; =&amp;gt; writing image sha256:eb9735e61e1dec63bd557dd5c61d8789733f2f4456a0d01687816bd0d135a7bc
 =&amp;gt; =&amp;gt; naming to localhost:5000/hello-go:1.2.3

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost:5000/hello-go 1.2.3 eb9735e61e1d 11 minutes ago 9.23MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Your output may look a little different depending on which version of Docker you are running and if you have &lt;a href="https://docs.docker.com/develop/develop-images/build_enhancements/"&gt;BuildKit enhancements&lt;/a&gt; enabled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4.&lt;/strong&gt; For others to use this image, we need to push it to a registry repository. In this example, I’m running a local repository on my workstation at port 5000 via the &lt;a href="https://hub.docker.com/_/registry"&gt;&lt;code&gt;registry:2&lt;/code&gt;&lt;/a&gt; image from DockerHub. (This is why I tagged the image with the &lt;code&gt;localhost:5000/&lt;/code&gt; prefix.)&lt;/p&gt;

&lt;p&gt;Pushing to a registry with Docker is pretty straightforward using the &lt;code&gt;docker push&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker push localhost:5000/hello-go:1.2.3
The push refers to repository [localhost:5000/hello-go]
0ba424468cb9: Pushed
ca623f32e759: Pushed
1.2.3: digest: sha256:ddcabff499d90fdf6850ef0b7addb33db7def…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If this were a managed registry, I would have needed to authenticate to it with &lt;code&gt;docker login&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5.&lt;/strong&gt; Finally, to run our image, we could use &lt;code&gt;docker run&lt;/code&gt; or an appropriate &lt;code&gt;kubectl&lt;/code&gt; deployment.  For this simplicity’s sake, we’ll do the former:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --rm -d -p 8080:8080 localhost:5000/hello-go:1.2.3
Unable to find image 'localhost:5000/hello-go:1.2.3' locally
1.2.3: Pulling from hello-go
45e68f4d0d8c: Already exists
ce1a03145a01: Already exists
Digest: sha256:ddcabff499d90fdf6850ef0b7addb33db7defe4669f9af1079894e84ad407199
Status: Downloaded newer image for localhost:5000/hello-go:1.2.3
2ef3c3dc0363ad10e9bf21baa7e78c63ca4df904bcba1fdab3af7732fce3857d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we can test the app with a simple &lt;code&gt;curl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl http://localhost:8080/Patch
Hello, Patch!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we were to visualize the steps we just performed, it might look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GXxqxdAL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://snyk.io/wp-content/uploads/blog-building-go-containers-without-ko.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GXxqxdAL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://snyk.io/wp-content/uploads/blog-building-go-containers-without-ko.jpg" alt="" width="880" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s rewind back to the beginning and see how this would work with Ko.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the image with Ko
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; We’ll start with the same &lt;code&gt;hello.go&lt;/code&gt; file in an empty directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", HelloWebServer)
    http.ListenAndServe(":8080", nil)
}

func HelloWebServer(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Next, we set our image registry into an environmental variable and run &lt;code&gt;ko build&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export KO_DOCKER_REPO=localhost:5000
$ ko build hello.go
2022/09/19 14:12:37 No matching credentials were found, falling back on anonymous
2022/09/19 14:12:40 Using base gcr.io/distroless/static:nonroot@sha256:2a9e2b4fa771d31fe3346a873be845bfc2159695b9f90ca08e950497006ccc2e for hello.go
2022/09/19 14:12:40 Building hello.go for linux/amd64
2022/09/19 14:12:44 Publishing localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:latest
2022/09/19 14:12:44 existing blob: sha256:2952e4f69ebf4bea5cc557f73626f95649cb546424fd998481ba690a08d9db7f
2022/09/19 14:12:44 existing blob: sha256:a706af0bb599ee120bd57c0e6abca55f66fd714f9e74706d9c97a583fc79d37e
2022/09/19 14:12:44 localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:sha256-3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c.sbom: digest: sha256:7d444debc3cd2d5545e88606dc529fa7ed90b1bb581ff8ac30b0f475b68d4ec0 size: 367
2022/09/19 14:12:44 Published SBOM localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:sha256-3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c.sbom
2022/09/19 14:12:44 existing blob: sha256:5ec5232d47ab0ad088792a191b672fe6ec27db63b19daebd7322ad64a2cd8676
2022/09/19 14:12:44 existing blob: sha256:250c06f7c38e52dc77e5c7586c3e40280dc7ff9bb9007c396e06d96736cf8542
2022/09/19 14:12:45 pushed blob: sha256:2d23903e55394a021ba4936cfad8ccbec6998413164416fcae4f6bf888665fce
2022/09/19 14:12:45 pushed blob: sha256:1cd0595314a53d179ddaf68761c9f40c4d9d1bcd3f692d1c005938dac2993db6
2022/09/19 14:12:45 localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:latest: digest: sha256:3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c size: 750
2022/09/19 14:12:45 Published localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7@sha256:3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c
localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7@sha256:3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;compiled our application into a static binary&lt;/li&gt;
&lt;li&gt;put it into a well-formed image, and&lt;/li&gt;
&lt;li&gt;pushed it to my registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No Dockerfile or container runtime engine was required to do any of this. Additionally, you’ll notice references in the output about an SBOM being created and published; we’ll come back to that later.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The image tag here contains an md5 hash that, by default, is the import path of your go application. Since we don’t have a full Go module in this example, that hash is simply taken from &lt;code&gt;hello.go&lt;/code&gt;.  See the &lt;a href="https://github.com/ko-build/ko#naming-images"&gt;Ko documentation&lt;/a&gt; for more information on tags.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Now we will run the image via &lt;code&gt;docker run&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run --rm -d -p 8080:8080 localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:latest
Unable to find image 'localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:latest' locally
latest: Pulling from hello.go-7a204cfb24536a350234d9132276cae7
1cd0595314a5: Pull complete
250c06f7c38e: Pull complete
5ec5232d47ab: Pull complete
Digest: sha256:3925979ac92afb8cb89fc80438097873daf067195e4d0b9d2fd6f55d6201355c
Status: Downloaded newer image for localhost:5000/hello.go-7a204cfb24536a350234d9132276cae7:latest
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
70877dcd53d23c66873e8e1e5a2092b46740e699b214a545e386113e5e098d7c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;… and test with &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/ko
Hello, ko!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visualizing the Ko pipeline might look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MbnJfTKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://snyk.io/wp-content/uploads/blog-building-go-containers-with-ko-1240x610.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MbnJfTKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://snyk.io/wp-content/uploads/blog-building-go-containers-with-ko-1240x610.jpg" alt="" width="880" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By letting Ko do the heavy lifting of image authoring, creation, and pushing, we reduced the number of steps to perform, the dependence on the container runtime engine at build time, and the expertise and maintenance requirements that the Dockerfile required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart defaults, deterministic specializations
&lt;/h2&gt;

&lt;p&gt;Ko users benefit from the collective definition of best practices by the open source community, but what if your organization has custom standards that don’t comply? This is where Ko’s command line options and/or &lt;code&gt;ko.yaml&lt;/code&gt; configuration file comes in handy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom base image
&lt;/h3&gt;

&lt;p&gt;Let’s say, for example, that your company has a specific image from which all Go applications need to use as their base. Simply include &lt;code&gt;defaultBaseImage:&lt;/code&gt; line in a &lt;code&gt;ko.yaml&lt;/code&gt; file in the top level directory with that image as it’s value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defaultBaseImage: repo.mycorp.com/myteam/corp-approved-scratch:220923
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go compiler flags
&lt;/h3&gt;

&lt;p&gt;To explicitly specify the go compiler &lt;code&gt;-ldflags&lt;/code&gt; as we had in our original example, simply add a &lt;code&gt;builds:&lt;/code&gt; entry to the same &lt;code&gt;ko.yaml&lt;/code&gt; file with appropriate settings as specified in the &lt;a href="https://github.com/ko-build/ko#overriding-go-build-settings"&gt;Ko documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builds:
 - id: hello
   dir: .
   main: hello.go
   env:
     - GOOS=linux
     - CGO_ENABLED=0
   ldflags:
     - -extldflags "-static"
     - -linkmode external
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Docker labels
&lt;/h3&gt;

&lt;p&gt;Docker labels — a.k.a. OCI annotations — are a way to apply metadata to an image that is useful for referencing information such as the source repository it came from, CI build that created it, or any other data your team wants to embed. For more about image labels and when you might want to use them, check my blog on &lt;a href="https://snyk.io/blog/how-and-when-to-use-docker-labels-oci-container-annotations/"&gt;How and when to use Docker Labels&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ko supports adding labels via its command line &lt;code&gt;--image-label&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ko build hello.go --image-label foo=bar -L –image-label org.opencontainers.image.source=https://repo.mycorp.com/superteam/hello
…
ko.local/hello.go-7a204cfb24536a350234d9132276cae7:acf1dce794131205d488ed8fe4818866ebf509a61f4cf60aa07463e2b054d97d

$ docker image inspect ko.local/hello.go-7a204cfb24536a350234d9132276cae7:latest --format '{{json .Config.Labels}}'
{"foo":"bar","org.opencontainers.image.source":"https://repo.mycorp.com/superteam/hello"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As of the publishing of this article, there is no way to specify image labels from the &lt;code&gt;.ko.yaml&lt;/code&gt; configuration file but there is an open &lt;a href="https://github.com/ko-build/ko/issues/825"&gt;issue&lt;/a&gt; for adding that functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other interesting Ko features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Image SBOMs
&lt;/h3&gt;

&lt;p&gt;As we saw above, Ko will automatically generate and push an &lt;a href="https://snyk.io/learn/software-bill-of-materials/"&gt;SBOM&lt;/a&gt; for your new container image. By default, it will be in SPDX format, but CycloneDX is also available by passing the flag &lt;code&gt;--sbom=cyclonedx&lt;/code&gt; on the command line. You can also turn this feature off by passing &lt;code&gt;--sbom=none&lt;/code&gt;; these and other configuration details are in the &lt;a href="https://github.com/ko-build/ko#generating-sboms"&gt;Ko documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A full discussion of SBOMs and their role in creating a secure supply chain is out of the scope of this article but if you’d like to learn more, check out &lt;a href="https://snyk.io/blog/building-sbom-open-source-supply-chain-security/"&gt;Building SBOMs for open source supply chain security&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes integration
&lt;/h3&gt;

&lt;p&gt;If your image needs to be tested in the context of a Kubernetes cluster, you undoubtedly have run into the hassle of needing to manage a recurring cycle of steps like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build my image&lt;/li&gt;
&lt;li&gt;Deploy it to my registry (or otherwise load it into the Kubernetes cluster)&lt;/li&gt;
&lt;li&gt;Update my deployment YAML with the new image tag&lt;/li&gt;
&lt;li&gt;Redeploy via &lt;code&gt;kubectl&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ko can make this much easier by automating all of these steps into a single command: &lt;code&gt;ko apply&lt;/code&gt;. With a simple change to your deployment YAML, replacing the image tag with a specially formatted &lt;code&gt;ko://&lt;/code&gt; one, &lt;code&gt;ko apply&lt;/code&gt; will automatically perform all of the above steps for you, deploying to whatever cluster you have actively set in your &lt;code&gt;kubectl&lt;/code&gt; config context.&lt;/p&gt;

&lt;p&gt;For example, let’s imagine you have a sandbox or locally running Kubernetes cluster and need to iteratively deploy and test your work as you go. Here is a deployment manifest for our “hello” application to deploy there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
 name: hello-server
spec:
 selector:
   matchLabels:
     run: hello-server
 replicas: 2
 template:
   metadata:
     labels:
       run: hello-server
   spec:
     containers:
       - name: hello-server
         imagePullPolicy: IfNotPresent
         image: ko://github.com/myteam/hello
         ports:
           - containerPort: 8080
             name: http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the &lt;code&gt;image:&lt;/code&gt; line which contains &lt;code&gt;ko://&lt;/code&gt;, followed by the path to the Go module of our application in GitHub.&lt;/p&gt;

&lt;p&gt;Now, we simply run &lt;code&gt;ko apply&lt;/code&gt; and give it the YAML file in an &lt;code&gt;-f&lt;/code&gt; flag like we would with &lt;code&gt;kubectl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ko apply -f myfile.yaml
2022/09/27 14:35:51 Using base gcr.io/distroless/static:nonroot@sha256:2a9e2b4fa771d31fe3346a873be845bfc2159695b9f90ca08e950497006ccc2e for github.com/myteam/hello
2022/09/27 14:35:51 Building github.myteam/hello for linux/amd64
…
2022/09/27 14:35:56 Published myteam/golang-ea0a77f5cbe6ba6aea599ad83048ae7b@sha256:bd7eb1052cf5b8664890f23683930f07423aba0089150bb818a53e76ef2ebf68
deployment.apps/hello-server created

$ k get pods
NAME READY STATUS RESTARTS AGE
pod/hello-server-5b5cc95db4-gc9rn 1/1 Running 0 10s
pod/hello-server-5b5cc95db4-rhwnp 1/1 Running 0 10s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now can test our application, make a change and re-run &lt;code&gt;ko apply -f myfile.yaml&lt;/code&gt; as many times as we need and it will do all the heavy lifting for you!&lt;/p&gt;

&lt;p&gt;As you would expect, there are other Kubernetes commands that you likely would need, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;delete&lt;/code&gt; for removing your deployments, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resolve&lt;/code&gt; for generating YAML that you can feed into &lt;code&gt;kubectl&lt;/code&gt; or other tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See &lt;a href="https://github.com/ko-build/ko#kubernetes-integration"&gt;https://github.com/ko-build/ko#kubernetes-integration&lt;/a&gt; for full documentation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges to using Ko
&lt;/h2&gt;

&lt;p&gt;We’ve talked about all of the reasons why you might want to take the plunge and start using Ko in your workflows, but before you start, let’s talk about some of the challenges that you may face using Ko.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-platform concerns
&lt;/h3&gt;

&lt;p&gt;If you develop on a non-Linux based machine, the lack of a container runtime can, in some ways, make things a little harder. Having a container based build image allows you to encapsulate both the build tools as well as the OS and its libraries into a common base build image and effectively ignore the fact that your workstation platform may not match that of your production environment.&lt;/p&gt;

&lt;p&gt;Case in point: The Go+Docker part of the example above will work on just about any platform because, regardless of where you build it, the &lt;code&gt;golang&lt;/code&gt; base image provides the necessary Debian based, &lt;code&gt;glibc&lt;/code&gt; libraries available for the Go builder to create the static binary. If, however, you try to run the Ko example with the same &lt;code&gt;ldflags&lt;/code&gt; options on a MacOS machine, for example, you’ll get errors about missing libraries needed to do the static bindings. &lt;/p&gt;

&lt;p&gt;This is because MacOS/Darwin does not include the necessary libraries to do the cross-complication for a Linux static binary (at least not at the time I am writing this). Not to pick on Apple too much, similar issues can come up for disparate CPU architectures with Linux and Windows WLS workstations too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skillset atrophy
&lt;/h3&gt;

&lt;p&gt;The skills and knowledge leveraged to create and maintain well crafted container images is a valuable commodity and using tools which abstract or remove the need to have them can reduce the ability to deal with issues if something fails. In fact, the fewer the number of people on a team that understand container technologies, the greater the dependence is on those people with the needed experience when it comes to troubleshooting and maintenance at runtime. In extreme cases, this can lead to burnout, attrition, and/or outages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security complacency
&lt;/h3&gt;

&lt;p&gt;If the process of container image construction becomes completely automated away from the developers, compliance with processes like image vulnerability scanning may falter. Vulnerabilities in un-updated images, packages, libraries, etc. can creep in exposing your application to attack so make sure such scanning is still being done via other automated means such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build scriptings or Makefiles&lt;/li&gt;
&lt;li&gt;Git hooks&lt;/li&gt;
&lt;li&gt;CI build steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are not already doing image scanning, Snyk offers free container image scanning that finds vulnerabilities in images and provides simple, actionable remediation advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure your containers for free
&lt;/h2&gt;

&lt;p&gt;Create a free Snyk account for quick and easy image scanning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.snyk.io/login?cta=sign-up&amp;amp;loc=body&amp;amp;page=container-images-simplified-with-ko"&gt;Sign up for free&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplifying container images
&lt;/h2&gt;

&lt;p&gt;Ko — and other alternative image building tools — can greatly simplify your Go application container image construction tasks and help streamline and standardize the way your teams build images. One of the greatest benefits is to your CI tooling as you no longer need to expose a container runtime to your build environment, greatly reducing privileged access attack vectors in your SDLC. Regardless of whether you choose to use a build tool like Ko, be sure your teams are well versed in container technologies and the security ramifications of any processes and tools they use to build their images.&lt;/p&gt;

</description>
      <category>applicationsecurity</category>
      <category>dependencyhealth</category>
    </item>
  </channel>
</rss>
