• Docker镜像多架构构建


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

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

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

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

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

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

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

    接下来以一个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"]
    
    • 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
    • 26
    • 27
    • 28
    • 29

    修改点有2个:

    --platform=$TARGETPLATFORM
    GOOS=${TARGETOS} GOARCH=${TARGETARCH}
    
    • 1
    • 2

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

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

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

    注意这里的 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"
             }
          }
       ]
    }
    
    • 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

    可以看出确实是生成了多个架构的镜像,使用时直接在不同架构的机器上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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

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

    yum|apt install
    
    • 1

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

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

    查看镜像有哪些tag:

    curl -u "用户名":"密码" -X GET http://镜像地址:5000/v2/命名空间/镜像名称/tags/list | python -m json.tool
    
    • 1
  • 相关阅读:
    VS Code For Web 深入浅出 -- 进程间通信篇
    e为底数的指数运算e^x,math.exp(x)
    全网最全Django面试题整理(一)
    LeetCode-46-全排列
    ROW_NUMBER 开窗函数优化方案(Oracle && KingBase 性能比对)
    力扣每日一题69:x的平方根
    FG6223EUUD系列模块选型参考
    使用python快速搭建接口自动化测试脚本实战总结
    14.微信小程序之地理定位功能
    Leetcode 剑指 Offer II 044. 在每个树行中找最大值
  • 原文地址:https://blog.csdn.net/m0_70748381/article/details/126865574