構建支持多平臺的docker鏡像

wuxqing 4年前發布 | 4K 次閱讀

構建支持多平臺的docker鏡像

一、思路

近期團隊在進行服務/軟件的多平臺(多CPU架構,例如:arm、mips等)改造,由于服務已經docker化,所以只需制作對應平臺的鏡像即可。

最先想到的就是在tag名這里做文章,例如:

docker.open-open.com/test:1.0-x86_64  
docker.open-open.com/test:1.0-arm64  
docker.open-open.com/test:1.0-mips64

或者

docker.open-open.com/x86_64/test:1.0  
docker.open-open.com/arm64/test:1.0  
docker.open-open.com/mips64/test:1.0

在每臺目標機上構建鏡像,并通過架構名來區分。這種方式,在運維層面需要額外的工作,例如運行腳本、編排文件等都需要維護多套。

我們在查看docker hub的tags時,可以看到 docker 鏡像倉庫是支持多個平臺的

docker tag

使用時,也只需簡單的 docker pull 鏡像名、docker run 鏡像名,docker cli會根據本機CPU架構選擇合適的鏡像文件。

要制作支持多平臺的docker鏡像,有2種方式

  • docker manifest
    需要 docker 版本不低于 18

  • buildlx
    需要 docker 版本不低于 19.03

二、開啟實驗性功能

docker manifest和buildlx 都需要開啟實驗性功能,默認是關閉的。

2.1 添加docker client的使用參數

$ mkdir ~/.docker/ -p
$ vim ~/.docker/config.json

添加如下內容

{
    "experimental": "enabled"
}

如果 ~/.docker/config.json 文件已經存在,只需添加"experimental": "enabled"

2.2 驗證是否開啟

執行 docker version

$ docker version | grep -Pzo 'Client(.|\n)*\n\n'

Client: Docker Engine - Community
 Version: 19.03.5
 API version: 1.40
 Go version: go1.12.12
 Git commit: 633a0ea
 Built: Wed Nov 13 07:25:41 2019
 OS/Arch: linux/amd64
Experimental: true

Experimental: true 表示已開啟

執行 docker --help

$ docker --help | grep -iE 'manifest|buildx'

buildx*   Build with BuildKit (Docker Inc., v0.3.1-tp-docker)
manifest  Manage Docker image manifests and manifest lists

出現 buildx 和 manifest 2行說明,就表示可以使用buildx、manifest

三、使用 docker manifest

3.1 創建 manifest 列表

  • 使用格式
$ docker manifest create --help  

Usage:  docker manifest create MANIFEST_LIST MANIFEST [MANIFEST...]
  • 示例
    $ docker manifest create docker.open-open.com/service_dev:1.0.0 \
    docker.open-open.com/service_dev:1.0.0-x86_64 \
    docker.open-open.com/service_dev:1.0.0-arm64 \
    docker.open-open.com/service_dev:1.0.0-mips64
    

注意:
manifest 對應的鏡像,需要在目標機上構建,并上傳到鏡像倉庫中

3.2 上傳 manifest 列表

  • 使用格式
$ docker manifest push --help  

Usage:  docker manifest push [OPTIONS] MANIFEST_LIST
  • 示例
$ docker manifest push docker.open-open.com/service_dev:1.0.0  
sha256:c62005140cd5368a8a18bdb0e0dcbcb9e24a04ceb1e22518dd9501cd979c9c50

3.3 查看 manifest 清單

  • 使用格式
$ docker manifest inspect --help  

Usage:  docker manifest inspect [OPTIONS] [MANIFEST_LIST] MANIFEST
  • 示例
$ docker manifest inspect docker.open-open.com/service_dev:1.0.0
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 4724,
         "digest": "sha256:f36faf79ac9f430f6e212d21bed24a4edc20e46b22ae422e83a14329b2300fbc",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 4724,
         "digest": "sha256:74b99f5527450769579f93613c06cf67acf33f932d2a566d206e855b55ed484e",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 4724,
         "digest": "sha256:3578489111d40b42d422b415c3584c831e56ca9e8fbf6c416ff49814e2bd088c",
         "platform": {
            "architecture": "mips64le",
            "os": "linux"
         }
      }
   ]
}

四、使用 buildlx

4.1 安裝buildx

$ wget https://github.com/docker/buildx/releases/download/v0.4.1/buildx-v0.4.1.linux-amd64
  • 安裝

    $ mkdir ~/.docker/cli-plugins/
    $ cp buildx-v0.4.1.linux-amd64 ~/.docker/cli-plugins/docker-buildx
    $ chmod +x ~/.docker/cli-plugins/docker-buildx
    
  • 查看

    $ docker buildx version
    github.com/docker/buildx v0.4.1 bda4882a65349ca359216b135896bddc1d92461c
    

4.2 添加多架構支持

  • 默認支持的架構

    $ docker buildx ls
    NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
    default * docker                  
    default default         running linux/amd64, linux/386
    

    注:
    每個架構下面執行的結果不一樣

  • 新增

    $ docker run --privileged --rm tonistiigi/binfmt --install all
    $ docker buildx create --use --name mybuilder
    $ docker buildx inspect --bootstrap
    
  • 查看

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

注意
如果重啟了機器,需要重新執行

$ docker run --privileged --rm tonistiigi/binfmt --install all

tonistiigi/binfmt 不支持misp,要自行修改代碼
cmd/binfmt/config.go 中添加mips的支持

"mips64el": {
        binary: "qemu-mips64el",
        magic:  `\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00`,
        mask:   `\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff`,
    },

4.3 構建鏡像

Dockerfile文件不需要改的
構建命令用 docker buildx build 代替 docker build

示例

$ docker buildx build --platform linux/arm64,linux/amd64,linux/mips64le . \
    -t docker.open-open.com/service_dev:1.0.0 --push

參數--push 表示構建成功后,上傳鏡像

成功后可以用docker manifest inspect 鏡像名 或者 docker buildx imagetools inspect 鏡像名查看

示例

$ docker buildx imagetools inspect docker.open-open.com/service_test:1.0.34r
Name:      docker.open-open.com/service_test:1.0.34r
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:a615d286c00fee23654a135f53c3d5dbd3f2d3621d3cd99d22ba98c6f81b05f9

Manifests: 
  Name:      docker.open-open.com/service_test:1.0.34r@sha256:de698defff054380a4ea792c678007cfb2ccf209457c729402979e4a6b753f67
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.open-open.com/service_test:1.0.34r@sha256:bb56ac0b075634b29d20bdbc6b630a6ca9579920605f0dfdd62d67422dd16c19
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.open-open.com/service_test:1.0.34r@sha256:54a989e94e9b1a23475a202ead2aeab00c9d8b5963f371edc71ffbe87176cee7
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/mips64le

五、manifest 與 buildlx 選擇

buildlx 的優點:

  • 可以不要目標平臺的設備,在本機就可以構建出多個平臺(例如:arm、mips等)的鏡像
  • 構建方式簡潔,只需修改構建命令

buildlx 的缺點:

  • 由于 buildlx 使用 QEMU,構建時,如果需要編譯(例如:c/c++),速度非常慢,往往10多分鐘就可以編譯好的,卻要花費好幾個小時
  • 有時候會卡死(中斷重新構建,可以解決問題)
  • 有時候會編譯失敗(無法解決)
  • 有時候編譯出來的鏡像,在目標機器上無法運行(無法解決)

manifest 的優點:

  • 兼容性好
  • 構建速度快

manifest 的缺點:

  • 需要有目標平臺的設備
  • 比 buildlx 略繁瑣
  • manifest 列表 create 后,無法刪除內部的manifest。鏡像變動了,tag必須也變動

我們在實際使用中優先采用的是 buildlx,只有 buildlx 無法編譯或構建的鏡像無法使用時才會采用manifest。

六、基礎鏡像(base)的選擇

要構建多平臺的鏡像,那么基礎鏡像也要支持相應的平臺。這個可以到docker hub去看,我們最終選擇的是debian:buster-slim

debian:buster-slim 支持的平臺很全面,國內的龍芯、飛騰、鯤鵬都可以使用。體積也非常的小。

沒有采用Alpine,因為有些項目在非x86_64上編譯通不過。

參考文章

https://docs.docker.com/engine/reference/commandline/manifest/
https://www.docker.com/blog/multi-arch-images/
https://github.com/docker/buildx/

 本文由用戶 wuxqing 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!