最近看到公司开始发布支持 arm系统的镜像包,找到几篇文章(链接见最后),发现即使手上没有 arm 系统环境也能同时构建这种包了,正好前一阵升级过19.03 ,有这个基础,于是实践一下,使用 Buildx 构建多种系统架构的镜像。
Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 Moby BuildKit 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。
BuildKit 是下一代的镜像构建组件,主要特点有很多,本文主要使用其可以编译多种系统架构的特性。
网址:https://github.com/moby/buildkit
需要注意的是,该功能仅适用于 Docker v19.03+ 版本 ,以及系统内核版本需要大于 4.8,这个地方的坑也只有我这个老环境才能遇到。
查看版本信息,我的环境Docker 最新版本号是 19.03.11。
[root@dc1-m2 ~] # docker version Client: Docker Engine - Community Version: 19.03.11 API version: 1.40 Go version: go1.13.10 Git commit: 42e35e61f3 Built: Mon Jun 1 09:13:48 2020 OS /Arch : linux /amd64 Experimental: true Server: Docker Engine - Community Engine: Version: 19.03.8 API version: 1.40 (minimum version 1.12) Go version: go1.12.17 Git commit: 0ae5cfe45f Built: Tue Mar 24 08:25:36 2020 OS /Arch : linux /amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683 |
buildx 命令属于实验特性,因此首先需要开启该特性。
编辑 ~/.docker/config.json 文件,新增如下内容(以下的演示适用于事先不存在 .docker 目录的情况下),如果本身有config.json文件,直接加1行 "experimental": "enabled" 就好
$ mkdir ~/.docker $ cat > ~/.docker /config .json <<EOF { "experimental" : "enabled" } EOF |
Linux/macOS 下或者通过设置环境变量的方式(不推荐):
1 |
<span class="pln">$ export DOCKER_CLI_EXPERIMENTAL</span><span class="pun">=</span><span class="pln">enabled</span> |
在 Docker 19.03+ 版本中可以使用 docker buildx build
命令使用 BuildKit 构建镜像。该命令支持 --platform
参数可以同时构建支持多种系统架构的 Docker 镜像,大大简化了构建步骤。
Docker 在 Linux 系统架构下是不支持 arm 架构镜像,因此我们可以运行一个新的容器让其支持该特性,Docker 桌面版(windows、macos)无需进行此项设置。
$ docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64
注:docker/binfmt 可以参考网址:https://hub.docker.com/r/docker/binfmt/tags 获取最新镜像,最新的tag就是上面这个,5个月前的版本。
上面docker run ** docker/binfmt ** 命令遇到一个报错 2020/07/16 05:46:01 Cannot write to /proc/sys/fs/binfmt_misc/register: write /proc/sys/fs/binfmt_misc/register: invalid argument
搜了很久,当时没找到解决方法, 隔天才发现是系统内核必须要大于4.8。
庆幸的是,测试环境3台当中有1台可以正常运行,系统分别是 CentOS Linux release 7.8.2003 (Core)、CentOS Linux release 7.6.1810 (Core)、 Red Hat Enterprise Linux Server release 7.8 (Maipo) 正常运行,后来想想应该是内核版本差异,见另一篇 https://blog.wanjie.info/2020/07/how-to-upgrade-kernel-centos/。
由于 Docker 默认的 builder 实例不支持同时指定多个 --platform
,我们必须首先创建一个新的 builder 实例。
1 |
<span class="pln">$ docker buildx create </span><span class="pun">--</span><span class="pln">name mybuilder </span><span class="pun">--</span><span class="pln">driver docker</span><span class="pun">-</span><span class="pln">container</span> |
返回新的 builder 实例名,为「mybuilder」
1 |
<span class="pln">mybuilder</span> |
使用新创建好的 builder 实例
1 |
<span class="pln">$ docker buildx use mybuilder</span> |
查看已有的 builder 实例
[root@instance-20200607-0734 ~] # docker buildx ls NAME /NODE DRIVER /ENDPOINT STATUS PLATFORMS mybuilder * docker-container mybuilder0 unix: ///var/run/docker .sock inactive default docker default default running linux /amd64 , linux /arm64 , linux /riscv64 , linux /ppc64le , linux /s390x , linux /386 , linux /arm/v7 , linux /arm/v6 |
另外我们查看目录 /proc/sys/fs/binfmt_misc/ 会发现多了一些架构支持。
qemu-aarch64 qemu-arm qemu-ppc64le qemu-riscv64 qemu-s390x ...
要想构建多种系统架构的镜像,还需要一个支持的 Dockerfile 文件。
我们就用最近改造过多次的alpine来实践吧,Dockerfile如下。
FROM --platform=$TARGETPLATFORM alpine:3.12 #加1个平台参数,方便后面指定需要的平台 LABEL MAINTAINER= "[email protected]" ENV TIMEZONE= "Asia/Shanghai" \ BUILD_DEPS="tzdata \ curl \ sudo \ bash \ dnscache \ openssh-client \ sshpass \ acl" RUN apk update && \ apk upgrade && \ apk add --no-cache ${BUILD_DEPS} && \ cp -rfv /usr/share/zoneinfo/ ${TIMEZONE} /etc/localtime && \ echo ${TIMEZONE} > /etc/timezone && \ apk del tzdata && \ rm -rf /var/cache/apk/ * CMD [ "/bin/bash" ] |
$TARGETPLATFORM
是内置变量,由 --platform
参数来指定其值。
在本地构建支持 2 种 platform 的镜像 amd64 和 arm v7
docker buildx build --platform linux/amd64,linux/arm/v7 -t cnrock/alpine -o type=local,dest=~/.docker .
构建日志如下,可以看到当中有2个打包过程 linux/amd64 1/2 和 linux/arm/v7 1/2
[+] Building 25.9s (9 /9 ) FINISHED => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 869B 0.0s => [internal] load .dockerignore 0.1s => => transferring context: 2B 0.0s => [linux /arm/v7 internal] load metadata for docker.io /library/alpine :3.12 3.4s => [linux /amd64 internal] load metadata for docker.io /library/alpine :3.12 7.5s => [linux /amd64 1 /2 ] FROM docker.io /library/alpine :3.12@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 7.5s => => resolve docker.io /library/alpine :3.12@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 0.0s => => sha256:df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c 2.80MB / 2.80MB 3.5s => => sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e 1.51kB / 1.51kB 0.0s => => sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 1.64kB / 1.64kB 0.0s => => sha256:a15790640a6690aa1730c38cf0a440e2aa44aaca9b0e8931a9f2b0d7cc90fd65 528B / 528B 0.0s => => unpacking docker.io /library/alpine :3.12@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 0.7s => [linux /arm/v7 1 /2 ] FROM docker.io /library/alpine :3.12@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 0.0s => => resolve docker.io /library/alpine :3.12@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321 0.0s => CACHED [linux /arm/v7 2 /2 ] RUN apk update && apk upgrade 0.0s => [linux /amd64 2 /2 ] RUN apk update && apk upgrade && 5.8s => exporting to client 5.0s => => copying files linux /arm/v7 10.52MB 5.0s => => copying files linux /amd64 14.68MB 4.5s |
docker buildx build 的具体参数含义,参考下面的官方文档
https://docs.docker.com/engine/reference/commandline/buildx_build/
做完上面的那一步,实际上是把构建好的镜像放在了本地路径下。
上面这个命令还有一个很骚的操作,打包完成后直接上传到 hub.docker.com,只需登录后,去掉本地存储,在命令最后面加1个 --push 即可。
命令如下 :docker buildx build --platform linux/amd64,linux/arm/v7 -t cnrock/alpine . --push
打开hub.docker.com 网站检查一下,发现确实是我上传的2种架构的 alpine 自定义镜像
命令行方式检查一下 docker buildx imagetools inspect cnrock/alpine 发现确实有 2种架构的 alpine 自定义镜像
打包成功,找个arm环境试下效果吧。
https://www.docker.com/blog/multi-platform-docker-builds/
https://docs.docker.com/docker-for-mac/multi-arch/
1 |
<a class="external-link" href="https://teddysun.com/581.html" target="_blank" rel="nofollow noopener noreferrer" data-ext-link-init="true">使用 Docker Buildx 构建多种系统架构镜像</a> |
https://nexus.eddiesinentropy.net/2020/01/12/Building-Multi-architecture-Docker-Images-With-Buildx/
https://github.com/docker/buildx
https://phoenixnap.com/kb/how-to-upgrade-kernel-centos
文章评论