I'm building a Docker image for multiple architectures (amd64 and arm64 - both on Linux). I'm using a multistage build - this means using go-alpine image as a builder (to compile my Go source code into an executable), and then copying the executable to a smaller secondary image.
Initially, I was copying the compiled program into an Alpine image, but I decided to switch to a scratch image (because of the security benefit) - this involved changing my build command so that the resultant executable is statically linked. My Dockerfile is now:
FROM golang:1.16 AS builder
WORKDIR /go/src/
RUN go get -d -v ./...
COPY . .
RUN env ${opts} go build -a -installsuffix cgo -o app .
FROM scratch
WORKDIR /root/
COPY --from=builder /go/src/app .
CMD ["./app"]
When I build for amd64, I run
docker build --build-arg opts="CGO_ENABLED=0 GOOS=linux GOARCH=amd64" -t myuser/example:amd64 .
- if I inspect this image, it shows "Architecture": "amd64"
as expected.
When I build for arm64, I run
docker build --build-arg opts="CGO_ENABLED=0 GOOS=linux GOARCH=arm64" -t myuser/example:arm64 .
- if I inspect this image, it shows "Architecture": "amd64"
- which isn't what I want.
If I compile the Go code locally by running CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build
, and then I run file
on the compiler output, it shows that the compiled output is arm64. I assume that the issue is therefore a result of Docker pulling an amd64 base image (since my PC is x86), but I can't figure out how to fix the issue.
The snippets you shared are cross-compiling your Go binary, but like you pointed out, are still using an amd64
base image. To do this, you will need to build a docker container for multiple platforms:
https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/
The example is something like:
docker buildx build \
--platform linux/arm64/v8,linux/amd64 \
--tag your-username/multiarch-example:buildx-latest .
Using the docker platform route, you shouldn't need to use go-multiarch building since the go
tool should infer the platform its building for.
As an alternative, you could cross-compile your binary on your host, and then have a docker image for each platform that is based off of the scratch image for that architecture and just copies your executable in.