
You don’t need a Dockerfile to build a Go Container
When onboarding and training new engineers at FlowUp, I started realizing how much time it takes to deeply understand how Dockerfiles work. Meanwhile, we were always maintaining that single “best-practice” Dockerfile for all of our projects. It suddenly made sense to get rid of Dockerfiles where possible.
We still use Dockerfiles for specific cases. However, I wanted to make sure, deep knowledge is not needed as a base knowledge to deploy to Cloud environments (Kubernetes, Cloud Run, or other container environments).
🐋 Making Dockerfiles Redundant
There’s a couple of projects that provide standard ways to build containers from languages or language frameworks. Basically, you don’t need to know what’s happening under the hood. If you use the standard way of using the language or framework, you’re good to go. Most notable are:
- ko, developed and maintained by Google. It helps to build as well as seamlessly deploy to Kubernetes environments.
- Buildpacks, a project that now resides under CNCF and there are multiple implementations for Go like heroku-buildpack-go, or GoogleCloudPlatform/buildpacks
I already made an article on NoOps Go on Cloud Run, you can check it below. It shows how we can build containers with ko.
🔧 Using Buildpacks
I am going to focus on using Buildpacks this time, to be precise, using the Google Cloud Buildpacks. First of all, you’ll need to install the pack
utility. The utility can then use buildpacks compatible with the standard.
In case you’re a Homebrew user:
brew install buildpacks/tap/pack
And for Arch Linux users not using Homebrew, use one of the following:
pack-cli
pack-cli-bin
If none of the above work for you, head into the Installation Page for Pack. There are plenty more options for installation.
📦 Building a Go App
Now to the fun part. Let’s build our app. If you’re using Go Modules (and I believe everyone should), the buildpack will search for the module in your directory, download dependencies, and build it. Moreover, it builds minimal image with root certificates.
pack build <app-name> --builder gcr.io/buildpacks/builder:v1
The resulting container can then be found under the <app-name>
you provided during the command above. You can run it as you would any Docker image.
What if I have multiple targets in a single repository/directory?
You can pass an environment variable GOOGLE_BUILDABLE
right to your main that you want to build. In case you don’t (and use a multi-target source), the build will fail and tell you there are multiple sources it can build.
pack build
--env GOOGLE_BUILDABLE=./cmd/service
--builder gcr.io/buildpacks/builder:v1
<app-name>
The command above will tell the buildpack that even though there are multiple targets in your directory, you want to build the one in ./cmd/service
.
Can I publish the image right into the container registry?
This one is easy. Just make sure you are providing the <app-name>
as the name of the image you want to publish. Next, you just add the --publish
flag and the buildpack will automatically push the image for you. For example, if I want to publish to the gcr
, I’d use this:
pack build
--env GOOGLE_BUILDABLE=./cmd/service
--builder gcr.io/buildpacks/builder:v1
--publish
gcr.io/<my-project>/<app-name>
This command will build and publish the container as well as make it available on your machine.
🚀 Bonus: Use the same code in the Cloud Build CI
I am attaching a simple build&publish script you can use directly in Cloud Build if you’re building your Go application on Google Cloud.
steps:
- name: 'gcr.io/k8s-skaffold/pack'
entrypoint: 'pack'
dir: 'user'
args: [
'build',
'--builder=gcr.io/buildpacks/builder',
'--env', 'GOOGLE_BUILDABLE=./cmd/service',
'--publish',
'gcr.io/<project>/<image>'
]
That’s it!
I hope I made your adventures in Go a bit simpler. In case you have any questions, please leave a comment here, message me on 🐦 Twitter, or ping me on 🔗 LinkedIn.
Cheers,