如何在Docker for macOS中导入和运行多平台OCI映像?

uz75evzq  于 2023-03-01  发布在  Docker
关注(0)|答案(3)|浏览(167)

我有一个go web服务,我一直在用docker build构建,并在我的M1 Mac和各种Linux机器上用docker run运行了一段时间。它是一个安装在distroless基础上的简单二进制文件,运行得很好。现在我想导出一个多平台映像,发送给同事在他们的计算机(M1和Intel Mac)上运行。我已经这样导出了一个OC:

docker buildx build --platform linux/amd64,linux/arm64 -t toy -o type=oci,dest=toy.oci .

导入工作正常:

docker image import toy.oci toy
sha256:02f7342d9d6ec2a1b66440aedb8d9a6ae0e968373fc8f2b698f7c8e73e6747e0

运行它是另一回事:

docker run -d --name toy -p 4242:4242 toy:latest
docker: Error response from daemon: No command specified.
See 'docker run --help'.

这很奇怪,因为我的Dockerfile有一个ENTRYPOINT。不管怎样,我试着告诉它要运行的命令:

docker run -d --name toy -p 4242:4242 toy:latest /bin/toy
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "/bin/toy": stat /bin/toy: no such file or directory: unknown.

几乎就像容器里没有文件一样!docker image ls显示了我的32 MB图像,所以我知道那里有东西,但是它在哪里?是不是缺少了一个图层?
FWIW我也试过type=tar,得到了同样的结果。
我想我错过了一个步骤,但我的DuckDuckGo-foo失败了。如何构建实际工作的可导出多平台Docker映像?

uplii1fm

uplii1fm1#

这里同时发生了几件事:

  • 只能导入单个平台映像。
  • 要导入映像,您应该使用docker loaddocker import命令从容器加载文件系统导出,并且不包含任何映像元数据。
  • docker load命令需要与OCI布局不同的自己的元数据。

我在regctl中有一个功能,可以提取特定的平台,并执行刚刚签入到main中的转换(因此它将在v0.4.5中发布,或者如果您不想自己构建它,可以直接从GHA提取二进制文件)。

# regclient works with directories rather than tars, so import the OCI tar to a directory
regctl image import ocidir://toy toy.oci
# get the digest from your local platform, you can also change "local" to "linux/amd64"
dig="$(regctl image digest --platform local ocidir://toy)"
# export the single platform image using the digest
regctl image export "ocidir://toy@${dig}" toy-docker.tar
# load into docker
docker load <toy-docker.tar

从Docker转换到containerd进行映像管理时,此行为将发生变化。发生这种情况时,多平台映像可以直接加载到Docker中,并且其导入命令应直接支持OCI布局。截至本次更新,这在Docker Desktop中处于试验阶段,尚未随Linux上的Docker引擎发布。

wgeznvg7

wgeznvg72#

我在M1上使用多拱支架构建图像的方法是:

  • 运行docker buildx create --bootstrap
  • 确保节点已启动并运行在适当的平台docker buildx ls上,并且已选中该平台,节点名称旁边有一个星号,否则运行:docker buildx use [node].
  • 开始构建您的映像:docker buildx build --platform linux/amd64,linux/arm64 -t sample:v1 . --push。这会将映像推送到注册表。

一旦图像在注册表中,你的同事就可以开始拉它了。这是最简单的方法,因为我在过去尝试其他目标输出时遇到过问题。

sczxawaw

sczxawaw3#

@BMitch的回答很好地解决了这里的各种问题,足以让我了解到我可以完全使用Docker。问题是缺乏对加载多平台图像的支持,因此每个平台必须有单独的图像。这方面的咒语是:

docker buildx build --platform linux/amd64 -t toy -o type=docker,dest=toy-amd64.tar .
docker buildx build --platform linux/arm64 -t toy -o type=docker,dest=toy-arm64.tar .

然后,可以与任何人共享各个tar文件,并加载:

docker load <toy-arm64.tar
docker run -d --name toy -p 4242:4242 toy:latest /bin/toy

在AMD 64平台上切换到toy-amd64.tar
为了好玩,我创建了make目标来执行构建和加载,如下所示:

docker-export: $(patsubst %,toy-%.tar, arm64 amd64)

toy-%.tar: vendor cmd/toy/toy.go schema/*.schema.json corpus/user/valid/*.json
    docker buildx build --platform linux/$* -t nytimes/toy -o type=docker,dest=$@ .

# Import an exported docker image for the current architecture.
docker-import: toy-$(patsubst aarch64,$(shell docker --debug info | grep Architecture | awk '{print $2}'),arm64).tar
    docker load <toy-$(patsubst aarch64,$(shell docker --debug info | grep Architecture | awk '{print $2}'),arm64).tar

相关问题