創(chuàng)建Manifest List
我們使用docker manifest子命令管理manifest list。其中,docker manifest create子命令用于在本地創(chuàng)建一個manifest list。該命令需要指定待manifest list地址和一系列的manifests。例如需要創(chuàng)建包含amd64和arm64兩個平臺鏡像的manifest list,則命令如:
docker manifest create kofj/multi-demo kofj/multi-demo:amd64 kofj/multi-demo:arm64
docker manifest create命令的詳細幫助信息如下所示:
# docker manifest create --help
Usage: docker manifest create MANIFEST_LIST MANIFEST [MANIFEST...]
Create a local manifest list for annotating and pushing to a registry
Options:
-a, --amend Amend an existing manifest list
--insecure Allow communication with an insecure registry
我們按照上述方法創(chuàng)建出來的manifest list中并沒有說明其中的manifest是什么操作系統(tǒng)和平臺的,docker manifest annotate命令用于注釋創(chuàng)建出來的manifest list。例如注釋某個manifest是linxu系統(tǒng)arm64平臺的,則命令:
docker manifest annotate kofj/multi-demo kofj/multi-demo:arm64--os linux--arch arm64
docker manifest annotate命令的詳細幫助信息如下所示:
# docker manifest annotate --help
Usage: docker manifest annotate [OPTIONS] MANIFEST_LIST MANIFEST
Add additional information to a local image manifest
Options:
--arch string Set architecture
--os string Set operating system
--os-features strings Set operating system feature
--variant string Set architecture variant
注意:
1.創(chuàng)建manifest list清單的過程中會檢查遠端倉庫中manifests是否存在,所以我們必修提前推送鏡像到遠端。如果遠端倉庫是不安全的,在創(chuàng)建的過程中需要添加參數--inseure。
2.使用docker manifest annotate注釋manifest list的時候不需要使用--insecure。
為了方便使用,我們可以使用下述代碼段-06的腳本創(chuàng)建manifest list。
//代碼段-06
#!/bin/bash
IMAGE?=kofj/multi-demo
NOCOLOR:='33[0m'
RED:='33[0;31m'
GREEN:='33[0;32m'
LINUX_ARCH?=amd64 arm64 riscv64
IMAGES=$(foreach arch,$(LINUX_ARCH),$(IMAGE):$(arch))
echo${GREEN}Create manifest for${RED}(${LINUX_ARCH})${NOCOLOR};
docker manifest create${IMAGE}${IMAGES}
for arch in${LINUX_ARCH};do
echo${GREEN}Annotate manifest${RED}linux/$$arch${NOCOLOR};
echo===================;
docker manifest annotate${IMAGE}${IMAGE}:$$arch--os linux--arch$$arch;
done
推送manifest list
當我們完成manifest list的創(chuàng)建工作后,它還是存儲在本地的。這時候,還需要推送到遠端的鏡像倉庫。與推送普通鏡像不同,推送manifest list需要使用docker manifest push命令進行。如果我們要推送kofj/multi-demo這個manifest list,則命令如:
docker manifest push kofj/multi-demo
使用docker manifest push命令可以通過附加--purge選項在推送完成后刪除存儲在本地的manifest list;當我們的目標倉庫沒有使用或者使用了非可信TLS證書的時候,則需要使用--insecure選項。
buildx自動構建
軟件依賴
·Docker≥19.03:自該Docker版本包含buildx。
·Linux kernel≥4.8:自該Linux內核版本binfmt_misc支持fix-binary(F)flag。fix_binary標志允許內核在容器或chroot內使用binfmt_misc注冊的二進制格式處理程序,即使該處理程序二進制文件不是該容器或chroot內可見的文件系統(tǒng)的一部分。
·binfmt_misc file system mounted:需要掛載binfmt_misc文件系統(tǒng),以便用戶空間工具可以控制此內核功能,即注冊和啟用處理程序。
·Docker Desktop≥2.1.0 如果是使用的Docker Desktop。
配置Buildx
buildx從19.03開始與Docker CE捆綁發(fā)布,但是需要我們在Docker CLI上啟用實驗性功能開開啟??梢酝ㄟ^兩種方式啟用它:
1.將"experimental":"enabled”添加到Docker CLI的配置文件~/.docker/config.json。
2.另外一種方法時設置環(huán)境變量DOCKER_CLI_EXPERIMENTAL=enabled。
使用Docker Desktop的同學可以通過UI菜單Preferences→Command Line進入Docker CLI配置界面,通過Switch開關Enable experimental features啟用實驗性功能。
如果需要使用最新版本的buildx,可以從https://github.com/docker/buildx/releases/latest下載最新的二進制發(fā)行版,并將其復制到~/.docker/cli-plugins文件夾中,重命名為docker-buildx,然后更改執(zhí)行權限:
chmod+x~/.docker/cli-plugins/docker-buildx
最后讓我們驗證buildx是否已經可用了:
$docker buildx version
github.com/docker/buildx v0.3.1-tp-docker 6db68d029599c6710a32aa7adcba8e5a344795a7
配置binfmt_misc
QEMU是一個很棒的開源項目,它可以模擬很多平臺。將QEMU和Docker結合起來使用能使得我們更容易的構建跨平臺的容器鏡像。集成QEMU依賴于Linux內核功能。Linux內核中的binfmt_misc功能可以使得內核識別任意類型的可以執(zhí)行文件格式,并傳遞到特定的用戶空間應用程序和虛擬機(https://zh.wikipedia.org/wiki/Binfmt_misc)。當Linux遇到一種無法識別的可執(zhí)行文件格式(比如說其它平臺的可執(zhí)行文件格式)時,它會檢查有沒有配置任何“用戶空間應用程序”用于處理它。如果檢測到了,就將可執(zhí)行文件傳遞給該應用程序。
為此,我們需要在內核當中注冊其它平臺的可執(zhí)行文件格式。
對于使用Docker Desktop(MacOS和Windows上都是)的同學,因為默認配置了binfmt_misc,可以跳過這一步。而使用Linux發(fā)行版操作系統(tǒng)的同學則需要自行安裝配置binfmt_misc,以便能夠非原生的其它平臺的鏡像。
要在宿主機上執(zhí)行其它CPU平臺的指令,需要安裝QEMU模擬器。因為程序執(zhí)行時會在當前程序可見的文件系統(tǒng)中查找動態(tài)庫,而在容器或chroot環(huán)境中注冊的處理程序在其它的cgroup namespace中可能無法找到,所以需要靜態(tài)編譯連接的QEMU。同時,我們需要安裝一個包含足夠新的update-binfmts二進制文件的包,以便能夠支持fix-binary(F)標志,并在注冊QEMU模擬器時實際使用,這樣才能結合buildx一起鏡像跨平臺構建。
QEMU和binfmt_misc支持工具可以通過宿主機或者Docker容器鏡像安裝。但是,使用Docker鏡像安裝配置能讓事情變得更加簡單。鏡像docker/binfmt中包含QEMU二進制文件和在binfmt_misc中注冊QEMU的安裝腳本。
docker run--privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
執(zhí)行完后,我們驗證下是否注冊成功了。成功注冊后,/proc/sys/fs/binfmt_misc目錄中會有多個qemu-前綴的文件。查看/proc/sys/fs/binfmt_misc/qemu-aarch64文件內容,可以看到falgs標志為OCF,說明這個處理程序是通過(F)標志注冊的,能夠正常的結合buildx完成跨平臺構建。
root kofj-hk~ls-al/proc/sys/fs/binfmt_misc
total 0
drwxr-xr-x 2 root root 0 Oct 12 20:19.
dr-xr-xr-x 1 root root 0 Oct 12 20:19..
-rw-r--r--1 root root 0 Oct 12 20:19 python2.7
-rw-r--r--1 root root 0 Oct 12 20:19 python3.6
-rw-r--r--1 root root 0 Oct 12 20:21 qemu-aarch64
-rw-r--r--1 root root 0 Oct 12 20:21 qemu-arm
-rw-r--r--1 root root 0 Oct 12 20:21 qemu-ppc64le
-rw-r--r--1 root root 0 Oct 12 20:21 qemu-s390x
--w-------1 root root 0 Oct 12 20:19 register
-rw-r--r--1 root root 0 Oct 12 20:19 status
root kofj-hk~cat/proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter/usr/bin/qemu-aarch64
flags:OCF
offset 0
magic 7f454c460201010000000000000000000200b7
mask ffffffffffffff00fffffffffffffffffeffff
使用buildx構建
前置依賴注備好后,我們終于可以使用buildx構建多平臺鏡像了。與其它方案不同的是,使用buildx可以讓我們不必改動dockerfile。
Buildx始終使用BuildKit引擎構建鏡像,不需要配置環(huán)境變量DOCKER_BUILDKIT=1。BuildKit可以很好的用于多個平臺的構建,而不僅適用于我們當前構建鏡像時所使用的平臺和操作系統(tǒng)。進行構建時,使用--platform標志可以用于指定構建輸出的目標平臺(例如linux/amd64,linux/arm64,linux/riscv64)。
首先,我們先準備好Dockerfile文件:
FROM golang:1.14 as builder
COPY./src
WORKDIR/src
RUN ls-al&&go build-a-tags netgo-ldflags'-w'-mod=vendor-v-o/src/bin/webapp/src/cmd/main.go
#Final image
FROM ubuntu:18.04
LABEL authors="Fanjian Kong"
COPY--from=builder/src/bin/webapp/app/
WORKDIR/app
CMD["/app/webapp"]
然后,讓我們嘗試下運行buildx。
root kofj-hk~docker buildx build--platform linux/amd64,linux/arm64,linux/arm-t harbor-community.tencentcloudcr.com/multi-arch/demo:2020-10-12.--push
error:auto-push is currently not implemented for docker driver,please create a new builder instance
居然報錯error:auto-push is currently not implemented for docker driver,please create a new builder instance了!別擔心,這是因為Docker默認的builder是不支持多平臺構建的。我們可以通過docker buildx ls查看當前節(jié)點上的builder有哪些。
root kofj-hk~docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
default*docker
default default running linux/amd64,linux/386
為了使用多平臺構建功能,我們需要新建一個builder,并設置當前builder為新建的。
#新建同時切換builder
docker buildx create--use--name mybuilder
#只新建,然后再切換builder
docker buildx create--name mybuilder
docker buildx use mybuilder
現在,讓我們再次執(zhí)行buildx,看著一切向著期待的方向發(fā)展了。
注意事項
注意1:到目前位置,buildx支持linux/amd64,linux/386,linux/arm/v7,linux/arm/v6,linux/arm64,linux/ppc64le,linux/s390x。所以docker/binfmt鏡像僅注冊了arm、ppc64le和s390x的處理程序。如果你需要構建、運行RISC-V平臺的容器鏡像,建議使用multiarch/qemu-user-static鏡像鏡像配置。
docker run--rm--privileged multiarch/qemu-user-static--reset-p yes
注意2:在軟件依賴中我們提到需要Linux內核版本>=4.8.0;如果在內核版本為3.10.0的系統(tǒng)(比如CentOS)上運行docker/binfmt,會出現報錯Cannot write to/proc/sys/fs/binfmt_misc/register:write/proc/sys/fs/binfmt_misc/register:invalid argument,這是由于內核不支持(F)標志造成的。出現這種情況,建議您升級系統(tǒng)內核或者換使用較高版本內核的Linux發(fā)行版。
小結
多年前,大規(guī)模部署應用程序是一項非常耗費人力、財力、時間,還需要大量技能和技巧的事務,工程師們還需要應對應用程序所運行的每一臺服務器的環(huán)境差異。這對大公司而言是個極其沉重的負擔,小公司更是無力應對。
正如多年前人們無法想象大規(guī)模部署復雜的應用程序只需要一個kubectl create命令,不久前我們也不會想到構建多平臺的容器鏡像只需要一個docker buildx build。但是,我們還有更加廣闊的想象空間,自動化流程、更多平臺的支持、更智能簡單的工具,你能想到的都有可能在不久的將來變成現實。
技術的發(fā)展進步,不斷降低了生產活動中社會平均勞動時間,提升了生產力,能夠釋放勞動者去做更多有益的探索。讓我們不斷學習、擁抱、應用新技術,在時代的浪潮中勇往直前。
可執(zhí)行方案回顧
1.確保使用的Linux發(fā)行版內核>=4.8.0(推薦使用Ubuntu 18.04以上的TLS發(fā)行版),且Docker>=19.03;
2.啟用Docker CLI實驗性功能:export DOCKER_CLI_EXPERIMENTAL=enabled;
3.配置其它平臺的模擬器:docker run--privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d;
4.新建Docker builder實例支持多平臺構建:docker buildx create--use--name mybuilder;
5.在項目目錄中執(zhí)行構建:docker buildx build--platform linux/amd64,linux/arm64,linux/arm-t harbor-community.tencentcloudcr.com/${YOUR_NAMESPACE}/multi-arch:2020-10-12.--push。
6.相關演示代碼、腳本可以在https://github.com/kofj/multi-arch-demo.git獲取。
推廣時間
目前,騰訊云容器鏡像服務TCR已完成公測進入商業(yè)化階段。我們也已經對部分用戶開放了Multi Arch鏡像和OCI云原生制品支持。如果您對該功能感興趣,歡迎聯系客服開通。