Getting Started with the Go Chainguard Image
The Go Chainguard image is a container image suitable for building Go applications. The latest
variant is a distroless image without a package manager, while the latest-dev
variant offers additional building tools and the apk package manager.
In this guide, we’ll demonstrate how to build and execute Go applications using Chainguard Images, using three examples from our demos repository. In the first example, we’ll build a CLI application using a Docker multi-stage build. In the second example, we’ll build an application that’s accessible by HTTP server, also using a Docker multi-stage build to obtain an optimized runtime. The third example shows how to build an image using ko, a tool that enables you to build images from Go programs and push them to container registries without requiring a Dockerfile.
The examples in this guide recommend executing Go binaries from one of our runtime Chainguard Images, such as the glibc-dynamic
or static
Chainguard Images. That is possible because Go applications are compiled and the toolchain is not typically required in a runtime image.
What is distroless
Distroless images are minimalist container images containing only essential software required to build or execute an application. That means no package manager, no shell, and no bloat from software that only makes sense on bare metal servers.What is Wolfi
Wolfi is a community Linux undistro created specifically for containers. This brings distroless to a new level, including additional features targeted at securing the software supply chain of your application environment: comprehensive SBOMs, signatures, daily updates, and timely CVE fixes.Chainguard Images
Chainguard Images are a mix of distroless and development images based on Wolfi. Nightly builds make sure images are up-to-date with the latest package versions and patches from upstream Wolfi.Preparation
This tutorial requires Docker to be installed on your local machine. If you don’t have Docker installed, you can download and install it from the official Docker website. The third and optional example requires the installation of ko, which you can install by following the instructions on the official site.
Cloning the Demos Repository
Start by cloning the demos repository to your local machine:
git clone git@github.com:chainguard-dev/edu-images-demos.git
Access the go
folder in the repository:
cd edu-images-demos/go
Here you will find three folders, each with a different demo that we’ll cover in this guide.
Example 1: CLI Application in Multi-Stage Build
The following example demonstrates a command line application with support for flags and positional arguments. The application prints a modifiable greeting message and provides usage information if the wrong number of arguments are passed by a user or the user passes an unrecognized flag.
Start by accessing the go-greeter
folder in the demos repository:
cd go-greeter
For reference, here is the content of the Dockerfile
for this demo:
FROM cgr.dev/chainguard/go AS builder
COPY . /app
RUN cd /app && go build -o go-greeter .
FROM cgr.dev/chainguard/static
COPY --from=builder /app/go-greeter /usr/bin/
ENTRYPOINT ["/usr/bin/go-greeter"]
This Dockerfile will:
- Start a build stage based on the
go:latest
image and name itbuilder
; - Copy the application files to the
/app
directory in the image; - Build the application in the
/app
directory; - Start a new build stage based on the
static:latest
image; - Copy the built application from the
builder
stage to the/usr/bin
directory in the new image; - Set the entrypoint to the built application.
Run the following command to build the image, tagging it go-greeter
:
docker build . -t go-greeter
You can now run the image with:
docker run go-greeter
You should get output similar to the following:
Hello, Linky 🐙!
You can also pass in arguments that will be parsed by the Go CLI application:
docker run go-greeter -g Greetings "Chainguard user"
This will produce the following output:
Greetings, Chainguard user!
The application will also share usage instructions when prompted with the --help
flag or when invalid flags are passed.
Because we used the static
Chainguard Image as our runtime, the final image only requires a few megabytes on disk:
docker inspect go-greeter | jq -c 'first' | jq .Size | numfmt --to iec --format "%8.4f"
3.3009M
The final size, 3.309M
, is orders of magnitude smaller than it would be running the application using a Go image. However, if your application is dynamically linked to shared objects, consider using the glibc-dynamic
Chainguard Image for your runtime or take extra steps to build your Go binary statically. In the next example, we’ll build a web application and use the glibc-dynamic
Chainguard Image as runtime.
Example 2: Web Application
The second example demonstrates an application that’s accessible by HTTP server. The application renders a simple message that changes based on the URI.
Start by accessing the greet-server
folder in the Go demos repository:
cd greet-server
For reference, here is the content of the Dockerfile
for this demo:
FROM cgr.dev/chainguard/go AS builder
COPY . /app
RUN cd /app && go build
FROM cgr.dev/chainguard/glibc-dynamic
COPY --from=builder /app/greet-server /usr/bin/
EXPOSE 8080
ENTRYPOINT ["/usr/bin/greet-server"]
Use the following command to build the image, tagging it greet-server
:
docker build . -t greet-server
Now you can run the image with the following command:
docker run -p 8080:8080 greet-server
Visit http://0.0.0.0:8080/
using a web browser on your host machine. You should get a greeting message:
Hello, Linky 🐙!
Changes to the URI will be routed to the application. Try visiting http://0.0.0.0:8080/Chainguard%20Customer. You should see the following output:
Hello, Chainguard Customer!
The application will also share version information at http://0.0.0.0:8080/version.
Example 3: Minimal Go Chainguard Image Built with ko
In this example, we’ll build a distroless Go Chainguard Image with ko. ko offers fast container image builds for Go applications without requiring a Dockerfile. Additionally, ko produces SBOMs by default, supporting a holistic approach to software security.
Start by accessing the go-digester
folder in the Go demos repository:
cd go-digester
The go-digester
demo uses the go-containerregistry
library to print out the digest of the latest build of a Chainguard image, using go
as the default image to pull the digest from, and with an optional parameter to specify a different image name. If you have Go installed locally, you can run the application with:
go run main.go
You should obtain output similar to this:
The latest digest of the go Chainguard Image is sha256:86178b42db2e32763304e37f4cf3c6ec25b7bb83660dcb985ab603e3726a65a6
We’ll now use ko to build an image that is suitable to run the application defined in main.go
. By default, ko uses the cgr.dev/chainguard/static
image as the base image for the build. You can override this by setting the KO_DEFAULTBASEIMAGE
environment variable to a different base image.
Before building the image, you’ll need to set up the environment variable KO_DOCKER_REPO
. This environment variable identifies where ko should push images that it builds. This is usually a remote registry like the GitHub Container registry or Docker Hub, but you can publish to your local machine for testing and demonstration purposes.
Run the following command to set the KO_DOCKER_REPO
environment variable to your local machine:
export KO_DOCKER_REPO=ko.local
Next, ensuring that you are in the same directory as your main.go
file, run the following command to build the image with ko:
ko build .
Once you run this command, you’ll receive output similar to the following.
2024/12/06 13:03:14 Using base cgr.dev/chainguard/static:latest@sha256:5ff428f8a48241b93a4174dbbc135a4ffb2381a9e10bdbbc5b9db145645886d5 for go-digester
2024/12/06 13:03:15 git doesn't contain any tags. Tag info will not be available
2024/12/06 13:03:15 Building go-digester for linux/amd64
2024/12/06 13:03:20 Loading ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:0914a85d803988ab10964323c0cd7b4bf89aed2603f6e8e276f798491c731336
2024/12/06 13:03:20 Loaded ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:0914a85d803988ab10964323c0cd7b4bf89aed2603f6e8e276f798491c731336
2024/12/06 13:03:20 Adding tag latest
2024/12/06 13:03:20 Added tag latest
ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:0914a85d803988ab10964323c0cd7b4bf89aed2603f6e8e276f798491c731336
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.
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-...
docker run --rm ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:0914a85d803988ab10964323c0cd7b4bf89aed2603f6e8e276f798491c731336
Here, you’ll expect to receive the same output as before that shows the digest of the Go image.
The latest digest of the go Chainguard Image is sha256:86178b42db2e32763304e37f4cf3c6ec25b7bb83660dcb985ab603e3726a65a6
You can also pass in an optional argument to specify which Chainguard Image to pull the latest digest from:
docker run --rm ko.local/go-digester-edc0ed689c7fb820a565f76425bed013:0914a85d803988ab10964323c0cd7b4bf89aed2603f6e8e276f798491c731336 mariadb
The latest digest of the mariadb Chainguard Image is sha256:6ba5d792d463b69f93e8d99541384d11b0f9b274e93efdeb91497f8f0aae03d1
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.
Note: If you're building on top of an image other than the wolfi-base image, the image will run as a non-root user. Because of this, if you need to install packages with
apk install
you need to use theUSER root
directive.
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.
If the packages you need are not available, you can build your own apks using melange. Please refer to this guide for more information.
Last updated: 2024-12-06 11:07