4

Docker镜像多架构构建

 2 years ago
source link: https://www.hi-roy.com/posts/docker%E9%95%9C%E5%83%8F%E5%A4%9A%E6%9E%B6%E6%9E%84%E6%9E%84%E5%BB%BA/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Docker镜像多架构构建

2022-09-14

目前arm系统越来越常见,对镜像的多架构需求也越来越大。对于同一个镜像,最简单的办法就是在amd64或arm机器上build后通过不同的tag进行区分,比如nginx:v1-amd64nginx:v1-arm64,但这种方式比较丑陋,而且没有对应架构的机器用来构建怎么办?

目前最新的办法就是使用buildx来进行构建,不过这个特性目前默认是没启用的,需要在docker的配置文件中添加"experimental": true后重启docker服务生效。

首先执行下面的命令让amd64的机器也可以构建arm的镜像:

docker run --rm --privileged tonistiigi/binfmt:latest --install all

然后创建一个新的build实例:

docker buildx create --use --name=mybuilder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master

这样准备工作就全都做好了。

接下来以一个kubebuilder命令创建的operator项目默认的Dockerfile为例:

# Build the manager binary
FROM --platform=$TARGETPLATFORM golang:1.16 as builder

ARG TARGETOS TARGETARCH

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/

# Build
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM  --platform=$TARGETPLATFORM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532

ENTRYPOINT ["/manager"]

修改点有2个:

  1. FROM后面使用--platform=$TARGETPLATFORM 参数来指定构建架构版本。
  2. GOOS=${TARGETOS} GOARCH=${TARGETARCH} 参数来指定go程序的编译架构。

这些TARGET开头的变量可以在参考链接2里看到全部含义。

接下来使用这个文件进行构建:

docker buildx build -t hello/namespace/name:v1 -f Dockerfile .  --platform linux/amd64,linux/arm64 --push

注意这里的buildx--platform参数后面跟随需要构建的版本、以及--push,buildx构建的多架构镜像要么使用这个参数push到镜像仓库,要么使用--load加载到本地,不可省略。

构建完成后就会生成相应的多架构镜像了,可以使用docker manifest inspect来进行验证,比如:

docker manifest inspect hello/namespace/name:v1
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 1367,
         "digest": "sha256:a7b99854e13939e3beaf21c1da8b4654022018eda9f438155b18ae16eeff49a5",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2169,
         "digest": "sha256:844885928813685ffa8c5ea4c6e9e7a09d95ac79e417afae0be7b73086762cfd",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

可以看出确实是生成了多个架构的镜像,使用时直接在不同架构的机器上pull就会自动下载对应的架构镜像了。或者也可以使用docker pull --platform arm64|amd64 xxxxx来指定拉取镜像的架构。

对于某些没有办法使用buildx的场景,我们可以手动build不同架构的镜像,然后再手动创建manifest,比如:

# 指定拉取amd64架构
docker pull --platform amd64 gcr.io/distroless/static:nonroot
# 重新打tag
docker tag 9ef34  hello/ns/static:nonroot-amd64
# 推送
docker push hello/ns/static:nonroot-amd64

# 指定拉取arm64架构
docker pull --platform arm64 gcr.io/distroless/static:nonroot
# 重新打tag
docker tag 91714  hello/ns/static:nonroot-arm64
# 推送
docker push hello/ns/static:nonroot-arm64

## 制作manifest
docker manifest create hello/ns/static:nonroot  hello/ns/static:nonroot-amd64 hello/ns/static:nonroot-arm64
docker manifest push hello/ns/static:nonroot
docker manifest rm hello/ns/static:nonroot

重点是最后3行,push manifest后使用就和第一种方法一样了。

另外如果想进行多架构构建有几个注意点:

  1. 确定使用的FROM镜像是不是支持多架构。
  2. 如果Dockerfile文件里使用了COPY、ADD等复制到镜像的文件,确保这些文件也是跨平台的。(比如Java源码跨平台,但javac不是…)
  3. 如果Dockerfile文件里使用了yum|apt install一类的命令,注意软件包不要指定架构。

查看镜像仓库里都有哪些镜像:

curl -u "用户名":"密码"  -X GET http://镜像地址:5000/v2/_catalog?n=2000  | python -m json.tool

查看镜像有哪些tag:

curl -u "用户名":"密码" -X GET http://镜像地址:5000/v2/命名空间/镜像名称/tags/list | python -m json.tool

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK