Product Docs
Open Source
Education
The Go images based on Wolfi and maintained by Chainguard provide distroless images that are suitable for building Go workloads.
Chainguard offers a minimal runtime image designed for running Go workloads, and a development image that contains a shell and the standard Go build tooling.
We’ll demonstrate two ways that you can build the Go image. The first example will show how to build the Go Chainguard Image with ko. ko enables you to build images from Go programs and push them to container registries without requiring a Dockerfile. The second example will show how to create a multi-stage Docker build that uses the glibc-dynamic runtime image along with the Go Chainguard Image.
If you would like to follow along with both examples, you’ll need both ko and Docker installed, which you can achieve by following the official installation guides for your setup:
Before building the image, follow the prerequisite step below to set up a demo application.
We’ll start by creating a basic command-line Go application to serve as a demo. This image will use the go-containerregistry library to print out the digest of the latest Go container image.
go-containerregistry
First, create a directory for your app. You can use any meaningful name and path for you, our example will use go-digester/.
go-digester/
mkdir ~/go-digester/ && cd $_
Next, initialize your app by creating a new module and installing dependencies.
go mod init go-digester go mod tidy go get github.com/google/go-containerregistry go get github.com/google/go-containerregistry/pkg/v1/remote go get github.com/google/go-containerregistry/pkg/name
With these in place, create a file to serve as the entrypoint. We’ll use main.go. You can edit this file in whatever code editor you would like. We’ll use Nano as an example.
main.go
nano main.go
The following Go code defines a light CLI app that prints the digest of the latest Go Chainguard Image:
package main import ( "fmt" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" ) func main() { image := "cgr.dev/chainguard/go" ref, err := name.ParseReference(image) if err != nil { panic(err) } desc, err := remote.Get(ref) if err != nil { panic(err) } fmt.Printf("The digest of %s is %s\n", image, desc.Digest) }
Save and close the file. Then, you can run the code with the go command to be sure you are satisfied with the functionality.
go
go run .
The output should be the printed digest of the latest Go Chainguard Image.
The digest of cgr.dev/chainguard/go is sha256:d4a845840e227b5454b67d00ee6ccdaaf2954eab88f47fa9ecac946011513db0
With the program running as expected, you’re ready to move onto either or both examples of building the image.
In this example, we’ll build a distroless Go Chainguard Image with ko from the demo app we created in the prerequisite step.
ko offers fast container image builds for Go applications. It builds images by executing go build on your local machine, and because of this, you are not required to have Docker installed to build the image. Additionally, ko produces SBOMs by default, supporting a holistic approach to software security.
go build
First, you’ll need to set up the environment variable (KO_DOCKER_REPO) that identifies where ko should push images that it builds. This is usually a remote registry like GitHub Container registry or Docker Hub, but you can publish to your local machine for testing and demonstration purposes.
KO_DOCKER_REPO
export KO_DOCKER_REPO=ko.local
Next, ensuring that you are in the same directory as your main.go file, build the image with ko:
ko build .
Once you run this command, you’ll receive output similar to the following.
2023/03/05 17:44:03 Using base distroless.dev/static:latest@sha256:4a5fda9b2aa55b49971d220cc4ba3d73998084e37e437f23721836112015c2d4 for go-digester ... 2023/03/05 17:44:05 Added tag latest ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:33523bfd5a136392f92905ffe5a076681baac3060d48c2b9ff2f787a7cc90dfd
At this point, your image is built. Because the output of ko build is an image reference, you can pass it to other tools like Docker. You can learn more about deployment with ko and Kubernetes integration by reading the respective documentation on the official site.
ko build
We’ll demonstrate running the above built image with Docker.
Note: To follow along, be sure that you copy and paste the last line of output from your last command that begins ko.local/go-digester-...
ko.local/go-digester-...
docker run --rm ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:33523bfd5a136392f92905ffe5a076681baac3060d48c2b9ff2f787a7cc90dfd
Here, you’ll expect to receive the same output as before that shows the digest of the image.
Now that you have built the Go Chainguard Image with ko, you can continue onto advanced usage, or you can complete the multistage setup in Example 2.
Because Go applications are compiled and the toolchain is not typically required in a runtime image, we suggest the usage of a multi-stage Docker build that uses the glibc-dynamic runtime image. In some cases, the static image may be used as well for an even smaller image, but extra care must be taken to ensure the Go binary is statically-compiled.
For this multi-stage build, we’ll use two FROM lines in our Dockerfile. To create this Dockerfile, you can use any code editor of your choice, we’ll use Nano for demonstation purposes.
FROM
nano Dockerfile
The following Dockerfile will:
go:latest
FROM cgr.dev/chainguard/go AS builder COPY ../reference/go /app RUN cd /app && go build -o go-digester . FROM cgr.dev/chainguard/glibc-dynamic COPY --from=builder /app/go-digester /usr/bin/ CMD ["/usr/bin/go-digester"]
Save the file when you’re finished.
You can now build the image with Docker. If you receive an error, try again with sudo.
sudo
docker build . -t digester
Once the build is finished, run the image.
docker run --rm digester
You should get output similar to what you got before.
You have successfully completed the multi-stage Go Chainguard Image. At this point, you can continue to advanced usage.
If your project requires a more specific set of packages that aren't included within the general-purpose Go Chainguard Image, you'll first need to check if the package you want is already available on the wolfi-os repository.
If the package is available, you can use the wolfi-base image in a Dockerfile and install what you need with apk, then use the resulting image as base for your app. Check the "Using the wolfi-base Image" section of our images quickstart guide for more information.
apk
If the packages you need are not available, you can build your own apks using melange. Please refer to this guide for more information.