Pushing images to Docker Hub for multiple architectures (e.g. amd64, arm64) and pulling the correct one automatically

梦想与她 提交于 2020-01-15 08:52:10

问题


I'm trying to create one image for different architectures, namely for amd64 and arm64.

The Dockerfile I've created is identical in its contents.

When I build from this Dockerfile on my main machine, which is on amd64, the resultant image will run on all other amd64 machines. However, when I attempt to run this image on arm64, I will see exec errors.

The main culprit seems to stem from my use of Ubuntu as the base image (FROM: ubuntu:latest), which somehow "knows" which architecture on which I'm building. As a result, I end up with a different image depending on the architecture I'm building on.

This isn't an issue in itself. After all, I can build once on amd64 and again on arm64.

What I'd like to do is be able to push one image for each architecture and have them pull to other machines automatically, without having to configure two sets of Dockerfiles. Another way to put it is I'd really like to know how the team at Ubuntu configures their images so that :latest pulls the latest version and the correct architecture.

Any advice would be appreciated!

Edit: For reference, I'm using Docker 19.03.5. The Dockerfile looks like this:

FROM ubuntu:latest

COPY /requirements.txt /tmp/

RUN apt-get update && \
    apt-get install -y python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev && \
    apt-get install -y libtiff5-dev libjpeg8-dev zlib1g-dev
RUN cd /usr/local/bin && \
    ln -s /usr/bin/python3 python && \
    pip3 install --upgrade pip
RUN pip install lxml && \
    pip install -r /tmp/requirements.txt && \
    pip install gunicorn

回答1:


I'd recommend using BuildKit with buildx which is available in 19.03. First you probably want some setup on a Linux host using qemu and binfmt_misc for cross compiling. Without it, you would need a build node for each platform you want to build. With binfmt_misc, you need two important details to work inside of a container, first is you need the static user binaries, and second is the --fix-binary flag needs to be used when injecting them into the kernel. For the first, that comes down to the package name you install, e.g. on Debian the package name is qemu-user-static. And for the second, this may require a version of the package from from an unstable release. E.g. here are a few bug reports to get the change included:

  • https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=868030
  • https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1815100

Once you've done this, you can verify the --fix-binary result by looking for the F flag in /proc/sys/fs/binfmt_misc/*.

Next, you need to setup a buildx worker. That can be done with:

docker buildx create --driver docker-container --name local --use \
  unix:///var/run/docker.sock
docker buildx inspect --bootstrap local

You should see something like the following from the inspect, note the multiple platforms:

$ docker buildx inspect --bootstrap local
[+] Building 54.1s (1/1) FINISHED
 => [internal] booting buildkit                                                                                                  54.1s
 => => pulling image moby/buildkit:buildx-stable-1                                                                               45.4s
 => => creating container buildx_buildkit_local0                                                                                  8.7s
Name:   local
Driver: docker-container

Nodes:
Name:      local0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Now you can perform a build for multiple architectures. The $image_and_tag must be an external registry where buildx can push the image. You cannot have a multi-arch image locally because docker images locally must be a single platform, but the registry like Docker Hub does support multi-arch manifests:

docker buildx build --platform linux/amd64,linux/arm64 \
  --output type=registry -t $image_and_tag .

And you can even test those other images using the qemu cross platform support:

docker container run --platform linux/arm64 $image_and_tag

Note that you may need to enable experimental CLI options in docker, I forget which features have not made it to GA yet. In ~/.docker/config.json, add:

{
  "auths": {
    ...
  },
  "experimental": "enabled"
}

Or you can export a variable (adding to your .bashrc to make it persistent):

export DOCKER_CLI_EXPERIMENTAL=enabled

Note: docker desktop has included settings for qemu/binfmt_misc for a while, so you can skip straight to the buildx steps in that environment. Buildx can also be run as a standalone tool. See the repo for more details: https://github.com/docker/buildx



来源:https://stackoverflow.com/questions/59365141/pushing-images-to-docker-hub-for-multiple-architectures-e-g-amd64-arm64-and

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!