Reputation: 3527
I have a Dockerfile that I run on amd64 but want to run on arm64. Since go build tool takes GOARCH=arm64 as argument I don't need any other cross compilation tool to make the binary.
# Run the build
FROM mojlighetsministeriet/go-polymer-faster-build
ENV WORKDIR /go/src/github.com/mojlighetsministeriet/email
COPY . $WORKDIR
WORKDIR $WORKDIR
RUN go get -t -v ./...
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build
# Create the final docker image
FROM scratch
COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=0 /go/src/github.com/mojlighetsministeriet/email/email /
ENTRYPOINT ["/email"]
The problem is that the resulting image gets marked with the wrong Architecture amd64 instead of arm64. How can I pass an argument to docker build so that it sets Architecture to arm64?
$ docker image inspect mojlighetsministeriet/email-arm64
[
{
"Id": "sha256:33bcd7da8631c7a0829d61cc53479a26ab7f31fab1cb039105de415ddc6178f3",
"RepoTags": [
"mojlighetsministeriet/email-arm64:latest"
],
"RepoDigests": [
"mojlighetsministeriet/email-arm64@sha256:ab3f05d5597c3a304953b5c14f795179aa75bdfd458af3dc3cfb8b8d8eb87bc3"
],
"Parent": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Comment": "",
"Created": "2017-12-05T18:36:36.273648787Z",
"Container": "7a226edb3b52aaeeefec9e0fb4dd1da50d84992fb6cc374aeda9d82eec1bb2c8",
"ContainerConfig": {
"Hostname": "7a226edb3b52",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"ENTRYPOINT [\"/email\"]"
],
"Image": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/email"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "17.10.0-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": null,
"Image": "sha256:e5888262d93ea0946b5fd8146cf1c19ec3a7bac4d36eb51848ef0aefa75cf8e7",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/email"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 7861466,
"VirtualSize": 7861466,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/03cb0162bf922636e4e0ec90123b81565a447c6cd511741103551d2f0e7f09f9/diff",
"MergedDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/merged",
"UpperDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/diff",
"WorkDir": "/var/lib/docker/overlay2/091f74815a0caf457df7e57ade43b41c4dd8551388beca44815a7038501742ee/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:66f615d03920919b0fa8bc9fed45515bb95636be1837fdd10a82b2c183e2ad5b",
"sha256:bd6a01b885eb6e3eec38a3fe3a2899646509633730b210cf6987456fd40b8a1c"
]
},
"Metadata": {
"LastTagTime": "2017-12-14T10:24:10.796813522+01:00"
}
}
]
Upvotes: 51
Views: 117254
Reputation: 264831
Buildkit has the tooling included to make this process very easy for Go images. Your Dockerfile can be modified to look like:
# The --platform uses the built in variable to pick the image matching your build host
# You only want to specify this on non-final stages of a multi-stage build, otherwise you would end up with a filesystem for one platform being marked with the wrong platform
FROM --platform=$BUILDPLATFORM mojlighetsministeriet/go-polymer-faster-build as build
ENV WORKDIR /go/src/github.com/mojlighetsministeriet/email
COPY . $WORKDIR
WORKDIR $WORKDIR
RUN go get -t -v ./...
# to leverage buildkit with Go's cross compiler use the TARGETOS and TARGETARCH args
# they are built in from buildkit and match GOOS and GOARCH
ARG TARGETOS
ARG TARGETARCH
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build
# without specifying a platform here, the scratch image will have the target platform architecture
FROM scratch
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=build /go/src/github.com/mojlighetsministeriet/email/email /
ENTRYPOINT ["/email"]
Then your build command would look like:
docker buildx build --platform linux/arm64 -t mojlighetsministeriet/email-arm64 .
Or create a multi-platform image with:
docker buildx build --platform linux/amd64,linux/arm64 -t mojlighetsministeriet/email .
The --platform
flag in those commands set the target for both the embedded build args and more importantly the image config.
Upvotes: 0
Reputation: 2617
I have deployed docker image on azure container apps which only allows amd64
. Following solution worked for me.
docker build -t user/image . --platform="linux/amd64"
In the same way you can change platform for you.
Upvotes: 7
Reputation: 1303
None of the previous answers worked for me. I was building a static Go binary per architecture and copying it into a completely empty container built FROM scratch
. I needed to take the following approach, using the docker manifest annotate
command to explicitly set the architecture of the built container:
docker build -f myproject.Dockerfile --pull -t registry.gitlab.com/myuser/myproject/myproject:manifest-arm64 --build-arg ARCH=arm64 .
docker build -f myproject.Dockerfile --pull -t registry.gitlab.com/myuser/myproject/myproject:manifest-amd64 --build-arg ARCH=amd64 .
docker push registry.gitlab.com/myuser/myproject/myproject:manifest-arm64
docker push registry.gitlab.com/myuser/myproject/myproject:manifest-amd64
docker manifest create registry.gitlab.com/myuser/myproject/myproject:manifest-latest \
--amend registry.gitlab.com/myuser/myproject/myproject:manifest-arm64 \
--amend registry.gitlab.com/myuser/myproject/myproject:manifest-amd64
docker manifest annotate --arch arm64 registry.gitlab.com/myuser/myproject/myproject:manifest-latest registry.gitlab.com/myuser/myproject/myproject:manifest-arm64
docker manifest push registry.gitlab.com/myuser/myproject/myproject:manifest-latest
Upvotes: 0
Reputation: 35
I build and run arm64 images on amd64 host with the help of qemu-user. But docker inspect
these arm64 images always show "Architecture": "amd64"
. I hope it
can show "Architecture": "arm64"
I tried DOCKER_DEFAULT_PLATFORM
and --platform=linux/arm64
, both not work. I'm using docker 19.03.13.
Finally, i found the solution —— save image first, change its metadata, then load it back:
set -e
IMAGE_ID=$(docker image inspect --format '{{.ID}}' $1)
IMAGE_ID=${IMAGE_ID#sha256:}
if [ ${#IMAGE_ID} -ne 64 ]; then
echo "Invalid image sha256 id"
exit 1
fi
rm -rf ${IMAGE_ID}
mkdir -p ${IMAGE_ID}
echo "IMAGE ${IMAGE_ID}"
echo "> save..."
docker save ${IMAGE_ID} | tar -xC ${IMAGE_ID}
echo "> change arch..."
sed -i 's/"architecture":"amd64"/"architecture":"arm64"/' ${IMAGE_ID}/${IMAGE_ID}.json
echo "> reload..."
tar -cC ${IMAGE_ID} . | docker load
echo "> clean..."
rm -rf ${IMAGE_ID}
echo "Note: you need to tag it manually"
Save it to changeArch.sh, then run sh changeArch.sh <sha_id>
or sh changeArch.sh <image:tag>
.
Upvotes: 0
Reputation: 840
For building single docker images: Set your environment variable using the command line or modifying your .bashrc or .zshenv file. (introduced in v19.03.0 in 03/2019)
export DOCKER_DEFAULT_PLATFORM=linux/arm64
Alternatively, in the Dockerfile, include the following flag in the FROM command (for a multi-stage Dockerfile build, the flag is only needed for the first stage):
FROM --platform=linux/arm64 python:3.7-alpine
For building images as part of a docker-compose build, include the platform: linux/arm64 for each service. For example:
services:
frontend:
platform: linux/arm64
build: frontend
ports:
- 80:80
depends_on:
- backend
backend:
platform: linux/arm64
build: backend
This also works the other way around, for instance if you have an Apple M1 Chip and want to deploy images to a Linux or Windows based AMD64 environment. Simply swap 'linux/arm64' for 'linux/amd64'
Upvotes: 71
Reputation: 38253
https://docs.docker.com/desktop/multi-arch/
# Shows builders installed
docker buildx ls
# Use builder that supports platform
docker buildx use default
docker buildx build --platform linux/arm64 -t <image_name>:<image_tag> --push .
Upvotes: 39
Reputation: 4157
I was able to solve the problem, not exactly as I wanted, but close enough.
Have an amd64 Linux machine with docker
Setup qemu user static for arm support https://hub.docker.com/r/multiarch/qemu-user-static/
In your docker file use base image with support for arm. E.g. ubuntu
Build your image with command similar to the following:
docker build --platform arm --pull -t your_tag .
This command will force docker to pull arm version of the base image and will also set arm architecture to your result image. But be careful, if you use tags with multiple architectures, the command above will set the tag to arm version. So to run the native amd64 version you will need to pull the tag again without --platform arg.
Upvotes: 3