Docker buildx使用笔记

最近一直在弄docker相关的东西, 因为我自己在用m1的mac, 架构是arm64的, 与一般服务器常用的x86_64架构不同, 因此构建的镜像在服务器上无法使用, 需要二次构建, 这怎么可能?! 必须一次性搞定, 因此本文记录一下

笨办法

参考资料

多架构下的 Docker 镜像 – 陈少文的网站

docker多架构镜像_oneslide的博客-CSDN博客_docker 多架构镜像

解决方法

因为部分应用着急用, 先用笨办法解决一下👇🏻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 定义私服仓库和制品名称
REGISTRY="nexus.goldwind.com.cn"
IMG_PATH="aws/prod/pricing-api"
# 登录私服
docker login ${REGISTRY}

# 在本地(arm)和远端(amd64)分别运行
docker build -t ${REGISTRY}/${IMG_PATH}:$(uname -m) .
docker push ${REGISTRY}/${IMG_PATH}:$(uname -m)

# 在任意环境之一执行拉取镜像操作
docker pull ${REGISTRY}/${IMG_PATH}:x86_64
docker pull ${REGISTRY}/${IMG_PATH}:arm64

# 如果有manifest先执行删除操作
docker manifest rm ${REGISTRY}/${IMG_PATH}:latest
# 创建manifest
docker manifest create --insecure ${REGISTRY}/${IMG_PATH}:latest ${REGISTRY}/${IMG_PATH}:x86_64 ${REGISTRY}/${IMG_PATH}:arm64
# 声明架构信息
docker manifest annotate --os linux --arch arm64 ${REGISTRY}/${IMG_PATH}:latest ${REGISTRY}/${IMG_PATH}:arm64
docker manifest annotate --os linux --arch amd64 ${REGISTRY}/${IMG_PATH}:latest ${REGISTRY}/${IMG_PATH}:x86_64
# 推送manifest, 添加`--insecure`参数可以推到非HTTPS协议的私服
docker manifest push --insecure ${REGISTRY}/${IMG_PATH}:latest

问题&缺陷

很明显, 这个需要在两个环境分别执行, 效率极低不说, 主要是很麻烦, 而且缺少环境还不能搞, 这个肯定不行, 需要在一个环境可以直接构建是最好的

聪明方法

查询资料

经过一段时间的google, 查找到了官方提供了一个名为buildx1的方法支持多架构构建镜像, 其中的概览如下:

Docker Buildx is a CLI plugin that extends the docker command with the full support of the features provided by Moby BuildKit builder toolkit. It provides the same user experience as docker build with many new features like creating scoped builder instances and building against multiple nodes concurrently.

翻译一下

Docker Buildx是一个CLI插件,它扩展了docker命令,完全支持Moby BuildKit builder工具包提供的功能。它提供了与docker build相同的用户体验和许多新的功能,如创建范围内的构建器实例和针对多个节点并发构建。

另外, 比较有用的信息还有2:

Feature docker docker-container kubernetes remote
Automatic --load
Cache export ❔ (inline only)
Docker/OCI tarball output
Multi-arch images
BuildKit configuration ❔ (managed externally)

因为我需要解决的是多架构构建的问题, 因此官方有写如何并发构建3的内容, 后续用上的时候在看

通读了官方文档4, 其中提示到👇🏻的信息

While Docker Desktop comes preconfigured with binfmt_misc support for additional platforms, for other installations it likely needs to be installed using tonistiigi/binfmt image.

说明有些镜像可能需要安装额外的binfmt_misc支持, 执行👇🏻命令

1
docker run --privileged --rm tonistiigi/binfmt --install all

过程记录

如何构建多架构 Docker 镜像?_云计算_Preetam DSouza_InfoQ精选文章

docker buildx 开启及使用(模拟器构建和远程构建) - 简书

1
2
# 查看当前的驱动器
docker buildx ls
默认驱动器
1
2
# 创建一个docker-container类型的驱动
docker buildx create --name mybuilder --use
添加新驱动
1
2
3
4
5
6
# 定义私服仓库和制品名称
REGISTRY="nexus.goldwind.com.cn"
IMG_PATH="aws/prod/pricing-api"

# 构建多架构镜像
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t ${REGISTRY}/${IMG_PATH}:latest --push .
返回HTTP类型的请求导致错误

如👆🏻图, 报错, 因为私服不是HTTPS协议的, 因此无法推送镜像, 查询手册, 发现可以添加--allow security.insecure解决

添加参数忽略证书问题

添加后, 依旧报错, 不过错误不同了granting entitlement security.insecure is not allowed by build daemon configuratio

不允许的参数

通过阅读👇🏻的官方文档

  1. Change Docker Desktop preferences on Mac | Docker Documentation
  2. dockerd | Docker Documentation

说实话没啥用, 一个是说修改Docker Desktop配置的介绍, 一个是说如何对Engine添加相关命令行--insecure-registry参数的, 无法解决我这个使用buildx的问题

docker - push cache to insecure registry by buildx - Stack Overflow

上面的帖子貌似揭示了一些问题, 我原来的Docker Desktop配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": true,
"features": {
"buildkit": true
},
"insecure-registries": [
"10.32.26.254:8082",
"10.32.26.254:8088",
"10.32.90.208:8080",
"nexus.goldwind.com.cn:8080",
"nexus.goldwind.com.cn:9000"
],
"registry-mirrors": [
"http://nexus.goldwind.com.cn:9000"
]
}

修改后的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": true,
"features": {
"buildkit": true
},
"insecure-registries": [
"10.32.26.254:8082",
"10.32.26.254:8088",
"10.32.90.208:8080",
"http://nexus.goldwind.com.cn:8080",
"http://nexus.goldwind.com.cn:9000"
],
"registry-mirrors": [
"http://nexus.goldwind.com.cn:9000"
]
}

添加了schema(http://), 不过依旧无效, 继续查文档

docker buildx build | Docker Documentation

上面是官方给出的buildx添加参数方法

1
2
docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'
docker buildx build --allow security.insecure .

依照官方的, 修改我的命令

1
2
docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t ${REGISTRY}/${IMG_PATH}:latest --push --allow security.insecure .
运行报错

提示返回了http协议的内容, 报错

Buildx is not honouring the insecure registry config in toml config provided by the default builder. · Issue #777 · docker/buildx

搜到上面的一个帖子, 里面指出需要指定一个toml的配置文件, 通过这个配置文件说明registry的情况, 因此修改命令

1
2
3
4
5
6
7
8
9
10
docker buildx rm insecure-builder
cat << EOF > buildkit-config.toml
[registry."${REGISTRY}"]
# 这行不需要加, 无需设置镜像代理
# mirrors = ["${REGISTRY}"]
http = true
insecure = true
EOF
docker buildx create --use --config buildkit-config.toml --name insecure-builder
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t ${REGISTRY}/${IMG_PATH}:latest --push --allow security.insecure .

执行后报错

回到了之前的问题?

这个报错居然回到了之前的问题??? 那么如果将之前的解决方法与这个方法合并一下呢?

1
2
3
docker buildx rm insecure-builder
docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure' --config buildkit-config.toml
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t ${REGISTRY}/${IMG_PATH}:latest --push --allow security.insecure .
终于成功了!太不容易了

总结

核心参考文档如下:

docker buildx build | Docker Documentation

Buildx is not honouring the insecure registry config in toml config provided by the default builder. · Issue #777 · docker/buildxhttps://github.com/docker/buildx/issues/777#issuecomment-928000274

完整命令汇总如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 定义私服仓库和制品名称
REGISTRY="nexus.goldwind.com.cn:8080"
IMAGE_PROJECT="jsonhero"
IMAGE_ENV="prod"
IMAGE_NAME="jsonhero"
IMG_PATH="${IMAGE_PROJECT}/${IMAGE_ENV}/${IMAGE_NAME}"

# 登录私服
docker login ${REGISTRY}

# 创建配置文件
cat << EOF > buildkit-config.toml
[registry."${REGISTRY}"]
# 这行不需要加, 无需设置镜像代理
# mirrors = ["${REGISTRY}"]
http = true
insecure = true
EOF

# 创建新的驱动器
docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure' --config buildkit-config.toml

# 构建多容器镜像并推送
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t ${REGISTRY}/${IMG_PATH}:latest --push --allow security.insecure .

反思

以后遇到这类问题首先应该先去看看官方手册是否有对某个功能的详细文档描述, 比如buildx build这块的配置内容我就绕了弯路, 没理解buildx其实是通过container的方式实现构建工作的, 跟你本地的docker服务配置没关系的, 并且自己已经配置了insecure-registry的相关内容, 按理说不会有返回http请求的报错了, 还报错就证明方向出了问题. 搜索到部分帖子说到了buildx create, 应当去查查官方文档, 比如我在写下这段话的时候去搜了一下, 正好找到了更详细的信息👇🏻

  1. docker buildx create | Docker Documentation
  2. buildkit/buildkitd.toml.md at master · moby/buildkit

其中1号链接为官方介绍buildx create --config相关信息的详细说明, 2号链接为官方链接中包含的样例配置信息, 其中就包含了本次的全部信息.

搜索其他博客或者StackOverflow的提问多数时候可以快速解决问题, 但是, 如果要知其然且知其所以然, 还是需要多看看官方手册的说明, 其中不光内容翔实, 也可以更快速的解决问题, 有时候==慢就是快, 快反而慢==


  1. Working with Buildx | Docker Documentation↩︎

  2. Buildx drivers overview | Docker Documentation↩︎

  3. Using multiple builders | Docker Documentation↩︎

  4. Building multi-platform images | Docker Documentation↩︎