參考官方文檔:
- Multi-stage
- Multi-platform
- Multi-platform images
方法
??如果在 x86_64/amd64
的平臺上,想構建適用于多個平臺的鏡像,例如 linux/amd64
、linux/arm64
,根據官方文檔,有三種方法可以使用:
-
QEMU
??使用 QEMU 模擬構建多平臺映像是最簡單的入門方法,但可能比本機構建慢得多,特別是對于編譯、壓縮或解壓縮等計算量大的任務。因此如果條件允許的話,更推薦使用 Cross-compilation(交叉編譯)。但因為使用起來最簡單,所以我在x86_64平臺上構建arm64鏡像并運行容器時用的是這個方法。 -
Multiple native nodes
??使用多個本機節(jié)點可以為 QEMU 無法處理的更復雜的情況提供更好的支持,并且通常具有更好的性能。 -
Cross-compilation
??交叉編譯使多平臺構建速度更快、用途更廣泛,但必須要有相對應的編譯器。
Buildx 設置
??在構建鏡像時,是通過設置 --platform
參數來指定目標平臺的。例如, linux/amd64
、 linux/arm64
或 darwin/amd64
。
??默認的構建驅動程序不支持并發(fā)多平臺構建,一次只能針對一個平臺進行構建(例如 docker build --platform=linux/amd64
)。
??如果想同時針對多個平臺進行構建(例如 --platform=linux/amd64,linux/arm64
),則需要創(chuàng)建構建器(builder)。
??要使用不同的驅動程序,需要使用 Docker Buildx。 Buildx 是下一代構建客戶端,它提供與 docker build
命令類似的用戶體驗,同時支持其他功能。
??例如創(chuàng)建一個使用docker-container作為驅動程序,名為container
的新構建器:
docker buildx create --driver=docker-container --name=container
可以使用 docker buildx ls
命令列出可用的構建器。*
標明了當前正在使用的構建器(在下面的示例中為default
):
? docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
container docker-container
container0 unix:///var/run/docker.sock inactive
default * docker
default default running v0.11.7+d3e6c1360f6e linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
從上面的輸出中可以看到,container
后的BUILDKIT
和PLATFORMS
為空,那么在第一次使用container
構建鏡像時,就會先下載相關文件,然后才會開始構建。
??也可以提前安裝并在創(chuàng)建完成后馬上啟用構建器。需要用到tonistiigi/binfmt,之后還會自動下載moby/buildkit鏡像。
如果電腦重啟后在/proc/sys/fs/binfmt_misc
中找不到qemu相關內容,那么還需要重新執(zhí)行這條命令:
docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx create --name mybuilder --bootstrap --use
結果如下:
? docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
container docker-container
container0 unix:///var/run/docker.sock inactive
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock running v0.12.3 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default docker
default default running v0.11.7+d3e6c1360f6e linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
使用QEMU仿真
??仿真構建時,需要指定構建器參數 --builder
,以及平臺參數 --platform
。
編譯文件
??例如下面這條命令用于編譯多平臺二進制文件:
docker buildx build \
--target=binaries \
--output=bin \
--builder=container \
--platform=linux/amd64,linux/arm64,linux/arm/v7 .
示例Dockerfile詳細內容見Github,需要下載整個倉庫然后在倉庫根目錄執(zhí)行該命令。
構建鏡像
以下示例使用單個 Dockerfile 為多個平臺構建了安裝有 curl 的 Alpine 映像。
Dockerfile:
# syntax=docker/dockerfile:1
FROM alpine:3.16
RUN apk add curl
構建命令:
docker buildx build \
--builder=mybuilder \
--platform=linux/amd64,linux/arm64,linux/arm/v7 \
--tag=<username>/<image>:latest \
--push .
??其中 --push
表示構建完畢后推送到倉庫。
??必須添加 --push
或 --load
參數,否則會得到警告WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
。意思是構建結果只保存在緩存中,使用 --push
可以將鏡像推送到遠程倉庫,使用 --load
可以將鏡像保存在本地。
??需要注意的是,如果參數添加的是 --load
而不是 --push
,并且--platform
后面跟了多個平臺,例如--platform=linux/amd64,linux/arm64,linux/arm/v7
,那么還是會得到報錯ERROR: docker exporter does not currently support exporting manifest lists
,這是因為本地無法保存多個同名的鏡像。所以如果要保存構建出的多個平臺的鏡像到本地,就得分多次執(zhí)行命令,每次只在 --platform
后添加一個平臺,并且每次的 --tag
后面的鏡像名稱都不同。
??例如為三個平臺構建了鏡像,就得分三次執(zhí)行命令:
docker buildx build \
--builder=mybuilder \
--platform=linux/amd64 \
--tag=<username>/<image>_amd64:latest \
--load .
docker buildx build \
--builder=mybuilder \
--platform=linux/arm64 \
--tag=<username>/<image>_arm64:latest \
--load .
docker buildx build \
--builder=mybuilder \
--platform=linux/arm/v7 \
--tag=<username>/<image>_arm_v7:latest \
--load .
??可以使用 docker buildx imagetools
命令檢查鏡像,前提是鏡像已推送到遠程倉庫。例如:
? docker buildx imagetools inspect <username>/<image>:latest
Name: docker.io/<username>/<image>:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48
Manifests:
Name: docker.io/<username>/<image>:latest@sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
Name: docker.io/<username>/<image>:latest@sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm64
Name: docker.io/<username>/<image>:latest@sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm/v7
??如果是使用 --load
保存到了本地,使用 docker image inspect
命令查看鏡像。例如:
docker image inspect <username>/<image>_arm_v7
使用交叉編譯(cross-compilation)
https://docs.docker.com/build/guide/images/cross-compilation.png
編譯文件
由于Go語言的編譯器支持在編譯時通過使用 GOOS
和 GOARCH
環(huán)境變量來進行交叉編譯,因此可以通過Docker自動將 --platform
的參數解析為構建參數TARGETPLATFORM
、TARGETOS
、TARGETARCH
,并在Dockerfile中賦值給環(huán)境變量,來實現交叉編譯。
示例Dockerfile詳細內容見Github或官網文檔,需要下載整個倉庫然后在倉庫根目錄執(zhí)行該命令。
構建鏡像
Dockerfile示例:
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
FROM alpine
COPY --from=build /log /log
在x86_64上運行arm64容器
??先執(zhí)行這條命令,確保/proc/sys/fs/binfmt_misc
有qemu相關內容:
docker run --privileged --rm tonistiigi/binfmt --install all
??接下來以運行arm64版本的ubuntu 18.04為例:
- 下載鏡像
docker pull --platform=linux/arm64 ubuntu:18.04
- 運行
docker run --rm -it ubuntu:18.04
忽略警告WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
文章來源:http://www.zghlxwxcb.cn/news/detail-806713.html
- 查看版本等相關信息
uname -a
??hello-world鏡像同理:文章來源地址http://www.zghlxwxcb.cn/news/detail-806713.html
docker run --rm --platform=linux/arm64 hello-world
? docker run --rm --platform=linux/arm64 hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(arm64v8)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
到了這里,關于Docker編譯多平臺文件、構建多平臺鏡像并運行的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!