GoReleaser build multi arch Docker Images

0hlov3
Dev Genius
Published in
4 min readMar 3, 2022

--

Photo by william William on Unsplash

GoReleaser is a release automation tool for Go projects. The goal is to simplify the build, release and publish steps while providing variant customization options for all steps.
GoReleaser is built with CI tools in mind, you only need to download and execute it in your build script. Of course, you can still install it locally if you want.
Your release process can be customized through a .goreleaser.yaml file.
Once you set it up, every time you want to create a new release, all you need to do is tag and run goreleaser release

I recently learned about goreleaser and immediately became fond of the tool. It’s easy to use and simplifies the deployment process immensely.

Pre requirements

  1. GoReleaser (tested this with version 1.5.0)
  2. Docker Buildx installed

On some operations systems Docker’s Buildx is not included and we have to install it subsequently, you can test it with the commanddocker buildx .

Create a Git Repository

First of all we are going to create a Git Repository. So that we can use Git Tags, goreleaser uses the tags to create the container image tag.

mkdir goreleaser-test
cd goreleaser-test
git init

Create a Dockerfile

Now that we have a working git environment, we are going to create a minimal Dockerfile in our working environment for our Builds. We (goreleaser) will copy the Build Binary into the Container, the ENTRYPOINT will run our Binary when the Container starts.

FROM alpine:3.15.0# copy over the binary from the first stage
COPY helloworld /helloworld/helloworld
WORKDIR “/helloworld”
ENTRYPOINT [ “/helloworld/helloworld” ]

Create some Go

We will create a minimal Go binary that outputs Hello World, the operating system, and the processor architecture. So create the file in ./helloworld/helloworld.go

package mainimport (
"fmt"
"runtime"
)
func main() {
fmt.Println("Hello World")
fmt.Println(runtime.GOOS, runtime.GOARCH)
}

Create .goreleaser.yaml

The next step is to prepare our .goreleaser.yaml for the release. We put it in the main path.

# https://goreleaser.com
project_name: helloworld
before:
# https://goreleaser.com/customization/hooks/
hooks:
# tidy up
- go mod tidy
builds:
# https://goreleaser.com/customization/build/
- main: ./helloworld
binary: helloworld
env:
- CGO_ENABLED=0
goos:
- linux
goarch:
- amd64
- arm
- arm64
goarm:
- 6
- 7
mod_timestamp: "{{ .CommitTimestamp }}"
dockers:
# https://goreleaser.com/customization/docker/
- use: buildx
goos: linux
goarch: amd64
image_templates:
- "0hlov3s/{{ .ProjectName }}:{{ .Version }}-amd64"
- "0hlov3s/{{ .ProjectName }}:latest-amd64"
build_flag_templates:
- "--platform=linux/amd64"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- use: buildx
goos: linux
goarch: arm64
image_templates:
- "0hlov3s/{{ .ProjectName }}:{{ .Version }}-arm64v8"
- "0hlov3s/{{ .ProjectName }}:latest-arm64v8"
build_flag_templates:
- "--platform=linux/arm64/v8"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- use: buildx
goos: linux
goarch: arm
goarm: 6
image_templates:
- "0hlov3s/{{ .ProjectName }}:{{ .Version }}-armv6"
- "0hlov3s/{{ .ProjectName }}:latest-armv6"
build_flag_templates:
- "--platform=linux/arm/v6"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
- use: buildx
goos: linux
goarch: arm
goarm: 7
image_templates:
- "0hlov3s/{{ .ProjectName }}:{{ .Version }}-armv7"
- "0hlov3s/{{ .ProjectName }}:latest-armv7"
build_flag_templates:
- "--platform=linux/arm/v7"
- "--label=org.opencontainers.image.created={{.Date}}"
- "--label=org.opencontainers.image.title={{.ProjectName}}"
- "--label=org.opencontainers.image.revision={{.FullCommit}}"
- "--label=org.opencontainers.image.version={{.Version}}"
docker_manifests:
# https://goreleaser.com/customization/docker_manifest/
- name_template: 0hlov3s/{{ .ProjectName }}:{{ .Version }}
image_templates:
- 0hlov3s/{{ .ProjectName }}:{{ .Version }}-amd64
- 0hlov3s/{{ .ProjectName }}:{{ .Version }}-arm64v8
- 0hlov3s/{{ .ProjectName }}:{{ .Version }}-armv6
- 0hlov3s/{{ .ProjectName }}:{{ .Version }}-armv7
- name_template: 0hlov3s/{{ .ProjectName }}:latest
image_templates:
- 0hlov3s/{{ .ProjectName }}:latest-amd64
- 0hlov3s/{{ .ProjectName }}:latest-arm64v8
- 0hlov3s/{{ .ProjectName }}:latest-armv6
- 0hlov3s/{{ .ProjectName }}:latest-armv7
checksum:
# https://goreleaser.com/customization/checksum/
name_template: 'checksums.txt'
snapshot:
# https://goreleaser.com/customization/snapshots/
name_template: "{{ incpatch .Version }}-SNAPSHOT"
source:
# https://goreleaser.com/customization/source/
enabled: true

git commit & tag

git add .
git commit -m ‘Initial Commit’
git tag v0.0.1

Run a Test release

Since we have everything set up, we can do a test release. So when we run goreleaser wit--snapshot, we will build the Container Images locally and goreleaser won’t push them to a registry.

goreleaser release — rm-dist — snapshot

Checkout your Container image

No that we successfully created the Container images, we can test them on our local Maschine. So we are going to checkout which images were build.

❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
0hlov3s/helloworld 0.0.2-SNAPSHOT-armv6 a613a22f467a 35 hours ago 6.04MB
0hlov3s/helloworld latest-armv6 a613a22f467a 35 hours ago 6.04MB
0hlov3s/helloworld 0.0.2-SNAPSHOT-amd64 7058d357c075 35 hours ago 6.79MB
0hlov3s/helloworld latest-amd64 7058d357c075 35 hours ago 6.79MB
0hlov3s/helloworld 0.0.2-SNAPSHOT-armv7 d8e9a147bdd4 35 hours ago 5.06MB
0hlov3s/helloworld latest-armv7 d8e9a147bdd4 35 hours ago 5.06MB
0hlov3s/helloworld 0.0.2-SNAPSHOT-arm64v8 1bf6fe199d86 35 hours ago 6.64MB
0hlov3s/helloworld latest-arm64v8 1bf6fe199d86 35 hours ago 6.64MB

Since we figured out, what Images we have, we can run them with the docker run command.

❯ docker run 0hlov3s/helloworld:0.0.2-SNAPSHOT-amd64
Hello World

Helpful Links

Don‘t trust me

The author does not assume liability for errors contained in or for damages arising from the use of the Information.

And do not hesitate to ask me questions or send me suggestions for improvement.

#go #go/goreleaser

--

--

Passionate DevOps engineer with a preference for Infrastructure as Code, Automation, Kubernetes, Go, Azure- and HetznerCloud.