省流:自 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"
}
}
]
}
这里面有几个问题:
- mediaType 版本为
application/vnd.oci.image.index.v1+json
,最新版本为 v2。 - 下面有两个
platform.architecture
与platform.os
为unknown
的数据项。
有些工具无法正常处理这种情况的镜像,如阿里的 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"
}
}
]
}
3 条评论
这篇文章如同一幅色彩斑斓的画卷,每一笔都充满了独特的创意。
跳出常规思维,角度独特,令人耳目一新。
这篇文章如同一首动人的乐章,触动了读者内心深处的柔软。