Docker多架构镜像编译

随着arm64架构的普及,越来越多的开发者使用arm64架构的服务器,但是x86_64架构的服务器仍然流行,那么在构建镜像过程中就需要支持多种架构的镜像。本文将介绍2种方式在 Docker 中构建多架构镜像。

manifest

手动创建manifest文件,然后使用docker manifest push命令推送到镜像仓库。比如社区中同时支持 arm64amd64 架构的kube-rbac-proxy 镜像,现在希望推送到自建 harbor 镜像仓库。

Pull 社区镜像到本地

1
2
docker pull quay.io/brancz/kube-rbac-proxy:v0.8.0-arm64
docker pull quay.io/brancz/kube-rbac-proxy:v0.8.0-amd64

创建 manifest 列表

1
docker manifest create harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0 harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0-arm64 harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0-amd64

此时创建了一个 harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0manifest 列表,其中包含了 arm64amd64 两个架构的镜像。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
docker manifest inspect  harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 739,
         "digest": "sha256:34e8724e0f47e31eb2ec3279ac398b657db5f60f167426ee73138e2e84af6486",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 739,
         "digest": "sha256:5a9f8e2f60fc4d02e364fa0192c01c79e8fac7e0c6a01cbc5b17152d6f21deae",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

设置 manifest 列表

1
2
docker manifest annotate harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0 harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0-arm64 --os linux --arch arm64
docker manifest annotate harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0 harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0-amd64 --os linux --arch amd64

查看 manifest 列表

1
docker manifest inspect harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0

推送 manifest 列表

1
docker manifest push harbor.alongparty.cn/operator/kube-rbac-proxy:v0.8.0

202401031402571

buildx

Docker 19.03+ 版本中可以使用 docker buildx build 命令使用 BuildKit 构建镜像。该命令支持 --platform 参数可以同时构建支持多种系统架构的 Docker 镜像,大大简化了构建步骤。

新建 builder 实例

1
2
3
4
5
6
# 适用于国内环境
docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master

docker buildx create --name mybuilder --driver docker-container

docker buildx use mybuilder

构建镜像

  • Dockerfile
1
2
FROM --platform=$TARGETPLATFORM busybox
COPY plugins /usr/share/elasticsearch/plugins
  • 构建镜像
1
docker buildx build --platform linux/arm64,linux/amd64 -t harbor.alongparty.cn/operator/es-plugins:7.13.4 --push .

注意: 在构建多架构镜像时底层镜像需要支持多架构,例如 busybox 镜像需要支持 linux/arm64linux/amd64 两个架构。自身应用程序也需要支持多架构,比如 golang 编译的二进制文件需要支持 linux/arm64linux/amd64 两个架构,不然在运行过程中可能会出现问题。

架构相关变量

Dockerfile 支持如下架构相关的变量

  • TARGETPLATFORM

    构建镜像的目标平台,例如 linux/amd64, linux/arm/v7, windows/amd64。

  • TARGETOS

    TARGETPLATFORM 的 OS 类型,例如 linux, windows

  • TARGETARCH

    TARGETPLATFORM 的架构类型,例如 amd64, arm

  • TARGETVARIANT

    TARGETPLATFORM 的变种,该变量可能为空,例如 v7

  • BUILDPLATFORM

    构建镜像主机平台,例如 linux/amd64

  • BUILDOS

    BUILDPLATFORM 的 OS 类型,例如 linux

  • BUILDARCH

    BUILDPLATFORM 的架构类型,例如 amd64

  • BUILDVARIANT

    BUILDPLATFORM 的变种,该变量可能为空,例如 v7

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

registry="harbor.alongparty.cn/default"

for image in $(cat images.txt)
do
    docker pull $image
    docker manifest inspect  $image | jq -r '.manifests[]'| jq -r '[.digest,.platform.architecture,.platform.os] | @tsv' > manifests.txt
    self_image=$(echo $image | awk -F/ -v OFS="-" '{print $(NF-1),$NF}')
    while read line
    do
        manifest=$(echo "$line" | awk '{print $1}')
        arch=$(echo $line | awk '{print $2}')
        os=$(echo $line | awk '{print $3}')
        if [[ $os == "linux" ]]; then
            docker pull ${image}@${manifest}
            docker tag ${image}@${manifest} ${registry}/${self_image}-${arch}
            docker push ${registry}/${self_image}-${arch}
        fi
    done < manifests.txt
    docker manifest create ${registry}/${self_image} ${registry}/${self_image}-amd64 ${registry}/${self_image}-arm64
    docker manifest push ${registry}/${self_image}
done
0%