在 VPS 主机上构建 Docker 容器 arm 、arm64 、amd64 等多平台容器镜像跨平台构建

闲置的 VPS 小鸡终于有了用武之地,本文通过 Centos 8 系统实现了跨平台构建 Docker 容器镜像。

前言

利用 Docker 19.03 引入的插件 buildx ,可以很轻松地构建多平台 Docker 镜像。buildx 是 docker build ... 命令的下一代替代品,它利用 BuildKit 的全部功能扩展了 docker build 的功能。

下面就来演示一下如何在短短几分钟内使用 buildx 构建出不同平台的 Docker 镜像。步骤如下:

步骤

1、检查 Docker 版本并启用 Docker 实验性功能

检查Docker的版本

docker --version

修改 vi /etc/docker/daemon.json 文件添加 "experimental": true 并重启 Docker 。

// 添加以后查看daemon.json中的内容
cat /etc/docker/daemon.json

// 查看内容类似下面这样
{
  "experimental": true
}

重启 Docker 程序

systemctl restart docker
//更多常用 Docker 命令大家可以收藏一下

启动Docker        systemctl start docker
守护进程重启   sudo systemctl daemon-reload
重启Docker服务   systemctl restart  docker
重启Docker服务  sudo service docker restart
关闭Docker   service docker stop   
停止Docker  systemctl stop docker

检查docker是否使能处于实验阶段的新特性

docker info | grep -i exp

2、启用 buildx 插件

要想使用 buildx,首先要确保 Docker 版本不低于 19.03,同时还要通过设置环境变量 DOCKER_CLI_EXPERIMENTAL 来启用。可以通过下面的命令来为当前终端启用 buildx 插件:

export DOCKER_CLI_EXPERIMENTAL=enabled

验证是否开启:

docker buildx version

#github.com/docker/buildx v0.3.1-tp-docker 6db68d029599c6710a32aa7adcba8e5a344795a7

如果在某些系统上设置环境变量 DOCKER_CLI_EXPERIMENTAL 不生效(比如 Arch Linux),你可以选择从源代码编译:

export DOCKER_BUILDKIT=1
docker build --platform=local -o . git://github.com/docker/buildx
mkdir -p ~/.docker/cli-plugins && mv buildx ~/.docker/cli-plugins/docker-buildx

3、启用 binfmt_misc

如果你使用的是 Docker 桌面版(MacOS 和 Windows),默认已经启用了 binfmt_misc,可以跳过这一步。

如果你使用的是 Linux,需要手动启用 binfmt_misc。大多数 Linux 发行版都很容易启用,不过还有一个更容易的办法,直接运行一个特权容器,容器里面写好了设置脚本:

docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d

建议将 Linux 内核版本升级到 4.x 以上,特别是 CentOS 用户,你可能会遇到错误。

验证是 binfmt_misc 否开启:

ls -al /proc/sys/fs/binfmt_misc/

#总用量 0
#总用量 0
#-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-aarch64
#-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-arm
#-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-ppc64le
#-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-s390x
#--w------- 1 root root 0 11月 18 00:09 register
#-rw-r--r-- 1 root root 0 11月 18 00:12 status

验证是否启用了相应的处理器:

cat /proc/sys/fs/binfmt_misc/qemu-aarch64

#enabled
#interpreter /usr/bin/qemu-aarch64
#flags: OCF
#offset 0
#magic 7f454c460201010000000000000000000200b7
#mask ffffffffffffff00fffffffffffffffffeffff

4、从默认的构建器切换到多平台构建器

Docker 默认会使用不支持多 CPU 架构的构建器,我们需要手动切换。

先创建一个新的构建器:

docker buildx create --use --name mybuilder

启动构建器:

docker buildx inspect mybuilder --bootstrap

#[+] Building 5.0s (1/1) FINISHED
# => [internal] booting buildkit                                                                                                                          5.0s
# => => pulling image moby/buildkit:buildx-stable-1                                                                                                       4.4s
# => => creating container buildx_buildkit_mybuilder0                                                                                                     0.6s
#Name:   mybuilder
#Driver: docker-container

#Nodes:
#Name:      mybuilder0
#Endpoint:  unix:///var/run/docker.sock
#Status:    running
#Platforms: linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

查看当前使用的构建器及构建器支持的 CPU 架构,可以看到支持很多 CPU 架构:

docker buildx ls

#NAME/NODE    DRIVER/ENDPOINT             STATUS  PLATFORMS
#mybuilder *  docker-container
#  mybuilder0 unix:///var/run/docker.sock running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
#default      docker
#  default    default                     running linux/amd64, linux/386

5、构建多平台镜像

在我们就可以构建支持多 CPU 架构的镜像了!假设有一个简单的 golang 程序源码:

cat hello.go

#package main

#import (
#        "fmt"
#        "runtime"
#)

#func main() {
#        fmt.Printf("Hello, %s!\n", runtime.GOARCH)
#}

创建一个 Dockerfile 将该应用容器化:

cat Dockerfile

#FROM golang:alpine AS builder
#RUN mkdir /app
#ADD . /app/
#WORKDIR /app
#RUN go build -o hello .

#FROM alpine
#RUN mkdir /app
#WORKDIR /app
#COPY --from=builder /app/hello .
#CMD ["./hello"]

这是一个多阶段构建 Dockerfile,使用 Go 编译器来构建应用,并将构建好的二进制文件拷贝到 alpine 镜像中。

现在就可以使用 buildx 构建一个支持 arm、arm64 和 amd64 多架构的 Docker 镜像了,同时将其推送到 Docker Hub

docker buildx build -t otakusay/hello-arch --platform=linux/arm,linux/arm64,linux/amd64 . --push

注意:自动上传镜像到 Docker Hub 需要提前通过 docker login 命令登录认证 Docker Hub

现在就可以通过 docker pull otakusay/hello-arch 拉取刚刚创建的镜像了,Docker 将会根据你的 CPU 架构拉取匹配的镜像。

背后的原理也很简单,之前已经提到过了,buildx 会通过 QEMU 和 binfmt_misc 分别为 3 个不同的 CPU 架构(arm,arm64 和 amd64)构建 3 个不同的镜像。构建完成后,就会创建一个 manifest list ,其中包含了指向这 3 个镜像的指针。

如果想将构建好的镜像保存在本地,可以将 type 指定为 docker,但必须分别为不同的 CPU 架构构建不同的镜像,不能合并成一个镜像,即:

docker buildx build -t otakusay/hello-arch --platform=linux/arm -o type=docker .
docker buildx build -t otakusay/hello-arch --platform=linux/arm64 -o type=docker .
docker buildx build -t otakusay/hello-arch --platform=linux/amd64 -o type=docker .

如果每个架构都有一个单独的 Dockerfile 可以通过下面的命令参数执行 Dockerfile 文件路径

docker buildx build -f  Dockerfile.arm -t otakusay/hello-arch --platform=linux/arm -o type=docker .
docker buildx build -f  Dockerfile.arm64 -t otakusay/hello-arch --platform=linux/arm64 -o type=docker .
docker buildx build -f  Dockerfile.amd64 -t otakusay/hello-arch --platform=linux/amd64 -o type=docker .

6、测试多平台镜像

由于之前已经启用了 binfmt_misc,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 3 个镜像是否有问题。

首先列出每个镜像的 digests

docker buildx imagetools inspect yangchuansheng/hello-arch

#Name:      docker.io/otakusay/hello-arch:latest
#MediaType: application/vnd.docker.distribution.manifest.list.v2+json
#Digest:    sha256:ec55f5ece9a12db0c6c367acda8fd1214f50ee502902f97b72f7bff268ebc35a

#Manifests:
  #Name:      docker.io/otakusay/hello-arch:latest@sha256:38e083870044cfde7f23a2eec91e307ec645282e76fd0356a29b32122b11c639
  #MediaType: application/vnd.docker.distribution.manifest.v2+json
  #Platform:  linux/arm/v7

  #Name:      docker.io/otakusay/hello-arch:latest@sha256:de273a2a3ce92a5dc1e6f2d796bb85a81fe1a61f82c4caaf08efed9cf05af66d
  #MediaType: application/vnd.docker.distribution.manifest.v2+json
  #Platform:  linux/arm64

  #Name:      docker.io/otakusay/hello-arch:latest@sha256:8b735708d7d30e9cd6eb993449b1047b7229e53fbcebe940217cb36194e9e3a2
  #MediaType: application/vnd.docker.distribution.manifest.v2+json
  #Platform:  linux/amd64

运行每一个镜像并观察输出结果:

docker run --rm docker.io/otakusay/hello-arch:latest@sha256:38e083870044cfde7f23a2eec91e307ec645282e76fd0356a29b32122b11c639

#Hello, arm!

docker run --rm docker.io/otakusay/hello-arch:latest@sha256:de273a2a3ce92a5dc1e6f2d796bb85a81fe1a61f82c4caaf08efed9cf05af66d

#Hello, arm64!

docker run --rm docker.io/otakusay/hello-arch:latest@sha256:8b735708d7d30e9cd6eb993449b1047b7229e53fbcebe940217cb36194e9e3a2

#Hello, amd64!

后语

回顾一下,本文带大家了解了在不同的 CPU 架构上运行软件的挑战性,以及 buildx 如何帮助我们解决了其中的一些挑战。使用 buildx,我们无需对 Dockerfile 进行任何修改,就可以创建支持多种 CPU 架构的 Docker 镜像,然后将其推送到 Docker Hub。任何安装了 Docker 的系统都可以拉取到与它的 CPU 架构相对应的镜像。

未来 buildx 可能会成为 docker build 命令的一部分,最终所有上面提到的功能都会变成默认的功能,下沉到基础设施中交叉编译程序的做法将会变成远古时代的愚蠢行为。

给TA打赏
共{{data.count}}人
人已打赏
Docker教程

Docker 容器设置固定 IP

2020-9-24 16:27:48

Docker教程

通过 Manifest 实现用户根据当前 CPU 架构自动从 Docker Hub 获取相应的 Docker 容器镜像

2020-10-9 1:43:06

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索