使用 docker buildx 構建跨平臺鏡像

buildx是Docker官方提供的一個構建工具,它可以幫助用戶快速、高效地構建Docker鏡像,并支持多種平臺的構建。使用buildx,用戶可以在單個命令中構建多種架構的鏡像,例如x86和arm架構,而無需手工操作多個構建命令。此外buildx還支持Dockerfile的多階段構建和緩存,這可以大大提供鏡像構建的效率和速度。

buildx是一個管理Docker構建的CLI插件,底層使用了BuildKit擴展了Docker構建功能。

BuildKit是Docker官方提供一個高性能構建引擎,可以用來替代Docker原有的構建引擎。相比于原有引擎,BuildKit具有更快的構建速度、更高的并行性、更少的資源占用和更好的安全性。

要安裝并使用buildx,需要Docker Engine版本號大于等于19.03。

跨平臺鏡像構建策略

builder支持是那種不通策略構建跨平臺鏡像。

在內核中使用QEMU仿真支持

如果你正在使用Docker Desktop,則已經支持了QEMU,QEMU是最簡單的構建跨平臺鏡像策略。它不需要對原有的Dockerfile進行任何更改,BuildKit會通過binfmt_misc這一Linux內核功能實現跨平臺程序的執行。

工作原理:

QEMU是一個處理器模擬器,可以模擬不通的CPU架構,我們可以把它理解為是另一種形式的虛擬機。在buildx中,QEMU用于在構建過程中執行非本地架構的二進制文件。例如,在x86主機上構建一個ARM鏡像時,QEMU可以模擬ARM環境并運行ARM二進制文件。

binfmt_misc是Linux內核的一個模塊,它允許用戶注冊可執行文件格式和響應的解釋器。當內核遇到未知格式的可執行文件時,會使用binfmt_misc查找與該文件格式關聯的解釋器(在這種情況下是QEMU)并運行文件。rk3568的平臺上此功能是關閉的。

QEMU和binfmt_misc的結合使得通過buildx跨平臺構建成為可能。這樣我們就可以在一個架構的主機上構建針對其他架構的Docker鏡像,而無需擁有實際的目標硬件。

雖然Docker Desktop預配置了binfmt_misc對其他平臺的支持,但對于其他版本Docker,你可能需要使用tonistiigi/binfmt鏡像啟動一個特權容器來進行支持。

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

運行此命令會安裝不同架構的解釋器程序,即/usr/bin目錄下的qemu模擬器:

?在我們編譯服務器上加載了binfmt_misc模塊:

docker buildx使用qemu的作用

Docker Buildx 是 Docker 的一個實驗性功能,它擴展了 Docker 的構建功能,包括使用多節點、qemu 等。QEMU 是一個開源的虛擬機軟件,它可以模擬不同的 CPU 和其他硬件,使得我們可以在一個操作系統上構建另一種操作系統的鏡像。

使用 Docker Buildx 的 qemu 功能,可以幫助我們構建面向多種不同架構(如 ARM、MIPS 等)的 Docker 鏡像。

以下是一個簡單的例子,展示如何使用 Docker Buildx 和 QEMU 來構建一個面向 ARM 架構的 Docker 鏡像:

# 創建一個新的 buildkit 實例
docker buildx create --name mybuilder --use# 啟動 buildkit 實例
docker buildx start mybuilder# 啟用 QEMU 驅動支持
docker buildx inspect --bootstrap# 構建一個面向 ARM 架構的 Docker 鏡像
docker buildx build --platform linux/arm/v7 -t myimage:latest .

在這個例子中,--platform?參數指定了我們想要構建的目標平臺是 ARM v7。這樣,Docker 會使用 QEMU 來模擬一個 ARM 環境,并在 x86 架構的機器上構建出面向 ARM 架構的 Docker 鏡像。

binfmt_misc文件系統

binfmt-misc是Linux內核提供的一種類似windows上文件關聯的功能,但比文件關聯更強大的是,它不僅可以根據文件后綴名判斷,還可以根據文件內容(Magic Bytes)使用不同的程序打開。一個典型的使用場景就是:使用qemu運行其他架構平臺上的二進制文件。

開啟binfmt-misc

臨時開啟可以使用以下命令:

$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

這種方式重啟后會失效,如果想長期生效,可以在/etc/fstab文件中增加一行:

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

可以使用以下命令檢查開啟是否成功:

$ mount | grep binfmt_misc
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
$ ls -l /proc/sys/fs/binfmt_misc
總用量 0
--w------- 1 root root 0 2月   5 22:55 register
-rw-r--r-- 1 root root 0 2月   5 22:55 status

先準備一個arm64架構的程序,執行后發現有報錯:

bash: ./go-test:無法執行二進制文件: 可執行文件格式錯誤

現在,我們執行一下apt install qemu-user-binfmt命令,然后再運行上面的arm64程序,發現能正常運行了。安裝qemu-user-binfmt后,會在/proc/sys/fs/binfmt_misc目錄下創建若干個文件,其中就有一個qemu-aarch64,來看一下這個文件的內容:

root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64 
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: OC
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff
root@ubuntu:/proc/sys/fs/binfmt_misc#

這個文件描述的是規則文件:

第一行enabled表示該規則啟用?;

第二行 interpreter /usr/bin/qemu-aarch64-static表示使用/usr/bin/qemu-aarch64-static來執行二進制文件;

第三行:OC表示運行的標志位,具體含義如下:

?P: 表示perserve-argv,這意味著在調用模擬器時,原始的參數(argv)將被保留。這對于默寫程序在運行時需要知道它們自己的名稱(即argv[0])的情況很有用

O: 表示offset,這意味著在啟動模擬器之前,需要從二進制文件中讀取一個偏移量,這個偏移量將作為模擬器的一個參數

C:表示credentials,這意味著模擬器將使用于原始程序相同的用戶ID和組ID運行,這有助于確保模擬器在運行時與原始程序相同的權限。

第四行:offset 0表示從0便宜值開始讀取文件;

第五行:?magic 7f454c460201010000000000000000000200b700表示要匹配的模數字節;

arm64架構的ELF文件頭部的magic字段如下,也就是說binfmt_misc文件系統可以根據ELF文件中的magic字段來決定此文件使用哪個架構的模擬器運行:

下面是兩個不同架構的?

mips架構的:? 7f454c4601020100000000000000000000020008
arm64架構的:7f454c460201010000000000000000000200b700

第六行:mask ffffffffffffff00fffffffffffffffffeffffff 表示字節掩碼,用哦過來忽略掉文件中的一些不重要的字節。

在x86_64系統中運行arm64架構的Docker鏡像

現在我們用docker命令運行一個arm64的鏡像:

$ docker run -it arm64v8/ubuntu bash
Unable to find image 'arm64v8/ubuntu:latest' locally
latest: Pulling from arm64v8/ubuntu
005e2837585d: Pull complete 
Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
Status: Downloaded newer image for arm64v8/ubuntu:latest
standard_init_linux.go:207: exec user process caused "no such file or directory"

通過一番探索之后,發現只要執行下命令:apt install qemu-user-static,再啟動docker容器就正常了。

使用 Dockerfile 中的多階段交叉構建

交叉編譯的復雜度不在于Docker,而是取決于程序本身。比如Go程序就很容易實現交叉編譯,只需要在使用go build構建程序時執行GOOS、GOARCH兩個環境變量即可實現。

創建builder

要使用buildx構建跨 平臺鏡像,我們需要先創建一個builder,可以翻譯為構建器。

使用docker buildx ls命令可以查看builder列表:

root@ubuntu:/proc# docker buildx ls
NAME/NODE         DRIVER/ENDPOINT             STATUS  PLATFORMS
mybuild *         docker-container                    mybuild0        unix:///var/run/docker.sock running linux/arm64*, linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
vigilant_hugle    docker-container                    vigilant_hugle0 unix:///var/run/docker.sock stopped 
default           docker                              default         default                     running linux/amd64, linux/386

*號表示當前正在使用的builder,當我們運行docker build命令時就是在使用此builder構建鏡像。第二列的DRIVER/ENDPOINT表示使用的驅動程序。buildx支持以下幾種驅動程序:

  • docker:使用捆綁到Docker守護進程中的BuildKit庫,就是安裝Docker后默認的BuildKit。
  • docker-container:使用Docker新創建一個專用的BuildKit容器。
  • kubernetes: 在kubernetes集群中創建一個BuildKit Pod。
  • remote:直接連接到手工管理的BuildKit守護進程。

因為使用docker驅動程序的默認builder不支持使用單條命令(默認builder的--platform參數只接收單個值)構建跨平臺鏡像,所以我們需要使用docker-container驅動創建一個新的builder。

命令語法如下:

$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>

參數含義如下;

--name: 構建起名稱,必填。

--driver:構建器驅動程序,默認為docker-container。

--driver-opt:驅動程序選項,如選項--driver-opt=image=moby/buildkit:v0.11.3可以安裝指定版本的BuildKit,默認值為moby/buildkit。

我們可以使用如下命令創建一個新的builder:

$ docker buildx create --name mybuilder
mybuilder

再次查看 builder 列表:

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT             STATUS   BUILDKIT PLATFORMS
mybuilder *     docker-containermybuilder0    unix:///var/run/docker.sock inactive
default         dockerdefault       default                     running  20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux   dockerdesktop-linux desktop-linux               running  20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

?可以發現選中的構建起已經切換到了Mybuilder,如果沒有選中,你需要手動使用docker buildx use mybuilder命令切換構建器。

啟動 builder

?我們新創建的mybuilder當前狀態為inactive,需要啟動才能使用。

$ docker buildx inspect --bootstrap mybuilder
[+] Building 16.8s (1/1) FINISHED=> [internal] booting buildkit                                                                                                                                  16.8s=> => pulling image moby/buildkit:buildx-stable-1                                                                                                               16.1s=> => creating container buildx_buildkit_mybuilder0                                                                                                              0.7s
Name:   mybuilder
Driver: docker-containerNodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Buildkit:  v0.9.3
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

inspect子命令用來檢查構建起狀態,使用--bootstrap參數可以啟動mybuilder構建器,再次查看builder列表,mybuilder狀態已經變成了running。

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT             STATUS  BUILDKIT PLATFORMS
mybuilder *     docker-containermybuilder0    unix:///var/run/docker.sock running v0.9.3   linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default         dockerdefault       default                     running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux   dockerdesktop-linux desktop-linux               running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

其中PLATFORMS一列所展示的值

?linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 就是當前構建器所支持的所有平臺了。

現在使用docker ps命令可以看到mybuilder構建器所對應的BuildKit容器已經啟動。

$ docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED         STATUS         PORTS                                NAMES
b8887f253d41   moby/buildkit:buildx-stable-1   "buildkitd"              4 minutes ago   Up 4 minutes                                        buildx_buildkit_mybuilder0

這個容器就是輔助我們構建跨平臺鏡像用的,不要手動刪除它。

使用 builder 構建跨平臺鏡像?

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

docker buildx build 語法跟 docker build 一樣, --platform 參數表示構建鏡像的目標平臺, -t 表示鏡像的 Tag, . 表示上下文為當前目錄。?

唯一不通的是對--platform參數的支持,docker build的--platform參數只支持傳遞一個平臺信息,如--platform linux/arm64,也就是一次能構建單個平臺的鏡像。

而使用docker buildx build構建鏡像則支持同時傳遞多個平臺信息,中間使用英文逗號分隔,這樣就實現了只用一條命令便可以構建多個跨平臺鏡像的功能。

執行以上命令后,我們將會得到一條警告:

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

這條警告提示我們沒有為docker-container驅動程序指定輸出,生成結果將只會保留在構建緩存中,使用--push可以將鏡像推送到Docker Hub遠程倉庫,使用--load可以將鏡像保存在本地。

這是因為我們新創建的mybuilder是啟動了一個容器來運行BuildKit,它并不能直接將構建好的跨平臺鏡像輸出到本機或推送到遠程,必須要用戶來手動指定輸出位置。

我們可以嘗試指定--load將鏡像保存在本地主機。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
[+] Building 0.0s (0/0)
ERROR: docker exporter does not currently support exporting manifest lists

結果會得到一條錯誤日志。看來它并不支持將跨平臺鏡像輸出到本地,這其實是因為傳遞了多個--platform的關系,如果--platform只傳遞了一個平臺,則可以使用--load將構建好的鏡像輸出到本機。

那么我們就只能通過--push參數將跨平臺鏡像推送到遠程倉庫了。不過在此之前需要確保使用docker login完成登錄。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

現在登錄Docker Hub就可以看見推送上來的跨平臺鏡像了。

我們也可以使用imagestools來檢查跨平臺鏡像的manifest信息,這條命令只能用來獲取倉庫中的image信息,本地的images無法查看。

$ docker buildx imagetools inspect jianghushinian/hello-go
Name:      docker.io/jianghushinian/hello-go:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104dbManifests:Name:      docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6MediaType: application/vnd.docker.distribution.manifest.v2+jsonPlatform:  linux/arm64Name:      docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441baMediaType: application/vnd.docker.distribution.manifest.v2+jsonPlatform:  linux/amd64

?

可以看到,這個跨平臺鏡像包含了兩個目標平臺的鏡像,分別是linux/arm64和linux/amd64。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42090.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42090.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42090.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【React Hooks原理 - useCallback、useMemo】

介紹 在實際項目中&#xff0c;useCallback、useMemo這兩個Hooks想必會很常見&#xff0c;可能我們會處于性能考慮避免組件重復刷新而使用類似useCallback、useMemo來進行緩存。接下來我們會從源碼和使用的角度來聊聊這兩個hooks。【源碼地址】 為什么要有這兩個Hooks 在開始…

使用selenium定位input標簽下的下拉框

先來看一下頁面效果&#xff1a;是一個可輸入的下拉列表 再來看一下下拉框的實現方式&#xff1a; 是用<ul>和<li>方式來實現的下拉框&#xff0c;不是select類型的&#xff0c;所以不能用傳統的select定位方法。 在著手定位元素前一定一定要先弄清楚下拉列表…

前后端的學習框架

前后端的學習框架 視頻鏈接&#xff1a;零基礎AI全棧開發系列教程&#xff08;一&#xff09;_嗶哩嗶哩_bilibili

什么是后端?

1、什么是后端&#xff1f; 后端開發人員從事于構建Web應用程序背后的實際邏輯&#xff0c;負責通過API向前端或者其他系統提供其他需要的信息&#xff0c;如&#xff1a;數據。 實際上&#xff0c;開發web應用中對用戶不可見的部分&#xff0c;稱為web后端&#xff0c;也就是…

初學vue3與ts:獲取組件ref實例

/*** 獲取組件ref* param {VueComponentIns} 組件實例* returns 組件ref*/ // eslint-disable-next-line export function useCompRef<T extends abstract new (...args: any) > any>(_: T) {return ref<InstanceType<T>>(); }使用 <a-com ref"a…

匯凱金業:數字貨幣對經濟的影響有哪些

隨著信息技術的飛速發展&#xff0c;數字貨幣作為一種新興的貨幣形態&#xff0c;正逐步走進人們的視野&#xff0c;并對傳統經濟體系產生著深遠影響。它不僅革新了交易方式&#xff0c;更在重塑金融格局、賦能經濟發展等方面展現出巨大潛力。 一、交易效率的“加速器” 數字…

單例模式之懶漢式

文章目錄 單例模式&#xff08;懶漢式&#xff09;代碼懶漢式&#xff08;線程不安全&#xff09;懶漢式&#xff08;線程安全&#xff0c;加鎖&#xff09;雙重檢查鎖&#xff08;線程安全&#xff0c;推薦&#xff09; 單例模式&#xff08;懶漢式&#xff09; 懶漢式是符合…

xxl-job集成SpringBoot

安裝xxl-job客戶端一般有很多方式&#xff0c;我這里給大家提供兩種安裝方式&#xff0c;包含里面的各項配置等等。 前期需要準備好MySQL數據庫。復制SQL到數據庫里面。 # # XXL-JOB v2.4.2-SNAPSHOT # Copyright (c) 2015-present, xuxueli.CREATE database if NOT EXISTS x…

項目機會:4萬平:智能倉,AGV,穿梭車,AMR,WMS,提升機,機器人……

導語 大家好&#xff0c;我是社長&#xff0c;老K。專注分享智能制造和智能倉儲物流等內容。 如下為近期國內智能倉儲物流相關項目的公開信息線索&#xff0c;這些項目具體信息會發布到知識星球&#xff0c;請感興趣的球友先人一步到知識星球【智能倉儲物流技術研習社】自行下載…

《SoC設計方法與實現》:全面掌握系統芯片設計精髓(可下載)

SoC&#xff08;System on Chip&#xff0c;系統級芯片&#xff09;設計是一項復雜而精細的工程活動&#xff0c;它涉及到將一個完整的電子系統的所有組件集成到一個單一的芯片上&#xff0c;包括處理器核心、內存、輸入/輸出端口以及可能的其他功能模塊。這種集成不僅要求設計…

oracle存儲結構-----邏輯存儲結構(表空間、段、區、塊)

文章目錄 oracle存儲結構圖&#xff08;邏輯存儲物理存儲&#xff09;oracle邏輯存儲結構圖邏輯存儲結構、表空間、段、區、數據塊的關系&#xff1a;1、數據 塊&#xff08;block&#xff09;---邏輯存儲最小單位2、 數據區&#xff08;extent&#xff09;--存儲空間分配和回收…

【AutoencoderKL】基于stable-diffusion-v1.4的vae對圖像重構

模型地址&#xff1a;https://huggingface.co/CompVis/stable-diffusion-v1-4/tree/main/vae 主要參考:Using-Stable-Diffusion-VAE-to-encode-satellite-images sd1.4 vae 下載到本地 from diffusers import AutoencoderKL from PIL import Image import torch import to…

電腦經常黑屏

情況簡述&#xff1a; 電腦經常突然黑屏&#xff0c;并且鼠標還能看到并且可操控 你是不是試過以下方法&#xff1a; 更換顯卡驅動版本?重置BIOS?重裝系統?全網找千篇一律沒啥用的教程? 這個標志熟悉吧&#xff0c;看看你的電腦里是否安裝了火絨&#xff0c;如果裝了繼續…

MySQL在Windows系統上的詳細安裝指南

一、準備工作 1. 確定MySQL版本 訪問MySQL官方網站&#xff1a;首先&#xff0c;你需要訪問MySQL的官方網站&#xff08;MySQL&#xff09;&#xff0c;或者更具體地&#xff0c;訪問MySQL的下載頁面&#xff08;MySQL :: Download MySQL Community Server&#xff09;。 選擇…

Linux運維:mysql主從復制原理及實驗

當一臺數據庫服務器出現負載的情況下&#xff0c;需要擴展服務器服務器性能擴展方式有向上擴展&#xff0c;垂直擴展。向外擴展&#xff0c;橫向擴展。通俗的講垂直擴展是將一臺服務器擴展為性能更強的服務器。橫向擴展是增加幾臺服務器。 主從復制好比存了1000塊錢在主上&…

Android14之獲取包名/類名/服務名(二百二十三)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

深度學習-梯度下降算法-NLP(五)

梯度下降算法 深度學習中梯度下降算法簡介找極小值問題數學上求最小值梯度梯度下降算法 找極小值問題在深度學習流程中深度學習整體流程圖求解損失函數的目標權重的更新 深度學習中梯度下降算法簡介 找極小值問題 引子&#xff1a; 我們訓練一個人工智能模型&#xff0c;簡單…

磁致伸縮液位計原理和特點

工作原理 磁致伸縮液位計的工作原理基于磁性材料在外部磁場作用下的尺寸變化來進行液位測量。該液位計主要由電子變送器、浮球&#xff08;浮子&#xff09;、探測桿&#xff08;測桿&#xff09;三部分組成。在磁致伸縮液位計的傳感器測桿外配有一浮子&#xff0c;此浮子可以…

【SpringCloud應用框架】Nacos服務配置中心

第四章 Spring Cloud Alibaba Nacos之服務配置中心 文章目錄 一、基礎配置二、新建子項目1.pom文件2.YML配置3.啟動類4.業務類5.Nacos配置規則 三、Nacos平臺創建配置操作四、自動配置更新五、測試 一、基礎配置 Nacos不僅僅可以作為注冊中心來使用&#xff0c;同時它支持作為…

【環境準備】 Vue環境搭建

文章目錄 前言vue-cli 安裝創建項目3.0、以下3.0 、以上 前言 書接上回《NodeJs(壓縮包版本)安裝與配置》&#xff0c;安裝完了NodeJs&#xff0c;接下來就要配置vue的環境了。 vue-cli 安裝 安裝vue-cli輸入如下命令 #&#xff08;安裝的是最新版&#xff09; npm install …