Loading...

省流:自 buildx 0.10 版本开始,就可能会出现这个问题,解决版本是 docker buildx 时增加参数 --provenance=false

问题复现

先来看示例,如有 Dockerfile:

FROM alpine RUN uname -a > /os.txt CMD cat /os.txt

通过以下命令构建 Multi-platform 镜像:

docker buildx create --driver docker-container --use docker buildx build --platform linux/amd64,linux/arm64 --push --tag zhaojun1998/buildx-demo:latest .

推送后,通过 docker manifest inspect zhaojun1998/buildx-demo:latest 查看:

{ "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 668, "digest": "sha256:5a0b3d0151d5505f6ab6bf2f6824b2d8fdcfcd0ae7cf9f2403606c6fccaf27f2", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 668, "digest": "sha256:38da41f844e3bfae577f8b768b53a4980838bba97c6952aaae4debf3ea66cee7", "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 566, "digest": "sha256:6749a2e66b9e0e9cfc751e215e1036385c9cfd17e68bc8feca771381ce8ce806", "platform": { "architecture": "unknown", "os": "unknown" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 566, "digest": "sha256:f0b8829a483c98b1bc7fd0a8b16765fe5b29cca632a13db971c0c3749df09c3f", "platform": { "architecture": "unknown", "os": "unknown" } } ] }

这里面有几个问题:

  1. mediaType 版本为 application/vnd.oci.image.index.v1+json,最新版本为 v2。
  2. 下面有两个 platform.architectureplatform.osunknown 的数据项。

有些工具无法正常处理这种情况的镜像,如阿里的 image-syncer

解决办法

构建命令中增加 --provenance=false

docker buildx build --provenance=false --platform linux/amd64,linux/arm64 --tag zhaojun1998/buildx-demo:no-provenance --push .

然后再通过 docker manifest inspect zhaojun1998/buildx-demo:no-provenance 查看:

{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 696, "digest": "sha256:c2f325142a90e152e0ea9eca07f5de281e183028da40991d5354b08da913da62", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 696, "digest": "sha256:8211d0f98a9a8a6f4b87826a2cb78ae375e76c2e5d6fbaaee46709f9f422022d", "platform": { "architecture": "arm64", "os": "linux" } } ] }

现在可以发现,上面的两个问题已经解决了。

已有镜像修复

上面的可以在新推送镜像时避免产生问题,但是对于已有镜像有时候不方便重新制作,可以通过以下办法修复已有镜像:

去除 unknown 部分

可以用以下脚本 fix-image.sh 来解决:

#!/bin/bash set -v set -e # 检查是否提供了镜像地址 if [ -z "$1" ]; then echo "请提供镜像地址" exit 1 fi IMAGE=$1 # 获取镜像的 manifest MANIFEST=$(docker manifest inspect $IMAGE) # 检查是否成功获取 manifest if [ $? -ne 0 ]; then echo "获取 manifest 失败" exit 1 fi echo "获取到 manifest 为: $MANIFEST" # 解析 manifest,移除 architecture 或 os 为 unknown 的条目 FILTERED_MANIFEST=$(echo $MANIFEST | jq 'del(.manifests[] | select(.platform.architecture == "unknown" or .platform.os == "unknown"))') echo "过滤后 manifest 为: $FILTERED_MANIFEST" # 检查是否有剩余的条目 if [ $(echo $FILTERED_MANIFEST | jq '.manifests | length') -eq 0 ]; then echo "过滤后没有剩余的条目,退出" exit 1 fi # 提取剩余条目的 digest DIGESTS=$(echo $FILTERED_MANIFEST | jq -r '.manifests[].digest') # 准备 docker manifest create 命令 NEW_IMAGE="${IMAGE}" # 这里可以自行决定修复后的镜像是否和原来的 tag 一样,如增加 -fix CREATE_CMD="docker manifest create $NEW_IMAGE" for DIGEST in $DIGESTS; do CREATE_CMD="$CREATE_CMD --amend ${IMAGE%%:*}@$DIGEST" done # 执行 docker manifest create 命令 eval $CREATE_CMD # 推送新的 manifest docker manifest push $NEW_IMAGE echo "新的 manifest 已创建并推送: $NEW_IMAGE"

使用办法为 ./fix-image.sh zhaojun1998/buildx-demo:latest,可以看到修复后的 manifest 变为了:

{ "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 668, "digest": "sha256:d756e0a11dd550bb5ea6affd46352119aee6f16981fa588667c54929efa95589", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 668, "digest": "sha256:ef6cd7110abcd9eb9c1c402e46c6de4de6138e5e0ef6f7b84b81a56d64b84212", "platform": { "architecture": "arm64", "os": "linux" } } ] }

升级镜像规范版本

根据自己的系统架构安装 regctl,然后执行命令:

regctl image mod zhaojun1998/buildx-demo:latest --to-docker --replace

再查看 manifest 为:

{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 587, "digest": "sha256:89d1d24005f61c825f1e07d819ce52c71c0c4ba96d7457d9b9f40dde59c31c78", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 587, "digest": "sha256:c1cd468c5476d0c33ca877a0dce7871d55550fdfbc00466f450f3bf63e5ea8ac", "platform": { "architecture": "arm64", "os": "linux" } } ] }

参考

最后修改:2024 年 10 月 08 日
如果觉得我的文章对你有用,请我喝杯咖啡吧。