自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Docker鏡像如何做到“一次構(gòu)建,到處運(yùn)行”?

開發(fā) 架構(gòu)
在每個黑客的職業(yè)生涯中總有這么一個時刻需要為另一種 CPU 架構(gòu)編譯應(yīng)用程序。這種場景可能出現(xiàn)在為樹莓派項目編譯應(yīng)用程序,為嵌入式設(shè)備創(chuàng)建自定義鏡像,或者讓自己的軟件支持不同平臺。

 在每個黑客的職業(yè)生涯中總有這么一個時刻需要為另一種 CPU 架構(gòu)編譯應(yīng)用程序。這種場景可能出現(xiàn)在為樹莓派項目編譯應(yīng)用程序,為嵌入式設(shè)備創(chuàng)建自定義鏡像,或者讓自己的軟件支持不同平臺。亦或是,我們只是想知道這個過程是怎么樣的,或者好奇最終匯編代碼和桌面電腦上無處不在的 x86-64/amd64 架構(gòu)匯編有何區(qū)別。

[[283951]]

不論是哪種原因,通常我們都需要整理好行裝進(jìn)行一段朝圣之旅。但是這個旅程不是登上孤獨(dú)的山頂,而是通向地獄深淵,是一段從開發(fā)應(yīng)用程序的陽光平原走向計算機(jī)體系結(jié)構(gòu)的黑暗洞穴之旅:底層系統(tǒng)和嵌入式變化帶來的難以捉摸的世界。介于這次跋涉的前景堪憂,大部分黑客最終通過 Ctrl+Z 結(jié)束了旅程,回到了地面,一邊喘氣一邊警告同伴交叉編譯、QEMU 和 chroot 的恐怖之處。

好了,我可能有點(diǎn)夸張了。但是真相是為其他 CPU 架構(gòu)構(gòu)建應(yīng)用程序沒有那么直截了當(dāng)。多虧了 Docker 19.03 帶來實驗性的插件,讓多架構(gòu)構(gòu)建比以往要方便很多。

為了理解 Docker 對多架構(gòu)構(gòu)建支持的重要性,首先我們需要了解如何為陌生架構(gòu)構(gòu)建應(yīng)用程序。

背景:為陌生架構(gòu)編譯應(yīng)用的方法

注:讀者如果對本節(jié)概念已經(jīng)了解,或者只是想知道如何構(gòu)建鏡像,可以跳過本節(jié)。

讓我們快速了解下當(dāng)前對于為陌生架構(gòu)編譯應(yīng)用程序的方法。

方法 1:直接在目標(biāo)硬件上構(gòu)建

如果我們可以訪問目標(biāo)架構(gòu)硬件,同時操作系統(tǒng)上有我們所需的所有構(gòu)建數(shù)據(jù),那么就可以直接在硬件上編譯應(yīng)用程序。

例如,對我們特定場景下構(gòu)建多架構(gòu) Docker 鏡像,可以在樹莓派上安裝 Docker 運(yùn)行時環(huán)境,然后和在開發(fā)機(jī)上一樣,直接在上面通過應(yīng)用程序的 Dockerfile 構(gòu)建鏡像。該方法是可行的,因為樹莓派的官方操作系統(tǒng) Raspbian 支持本地安裝 Docker。

但是,如果我們沒法辦法方便的訪問目標(biāo)硬件呢?我們可以在開發(fā)機(jī)器上直接構(gòu)建非本地架構(gòu)的應(yīng)用程序嗎?

方法 2:模擬目標(biāo)硬件

還記得和 16 位任天堂游戲機(jī)一起的快樂時光嗎?當(dāng)時我只是一個小孩子,但是當(dāng)我長大一點(diǎn)之后,我發(fā)現(xiàn)對諸如《超級瑪麗》和《時空之輪》等經(jīng)典游戲非常懷念。不過我沒有機(jī)會擁有一臺超級任天堂游戲機(jī),但是多虧了像 ZSNES 這樣的模擬器,讓我能回到過去,在 32 位個人電腦上體驗這些經(jīng)典游戲帶來的樂趣。

通過模擬器,我們不僅能夠玩電子游戲,還能夠構(gòu)建非本地二進(jìn)制文件。當(dāng)然這里不是使用 ZSNES,而是使用更加強(qiáng)大更靈活的模擬器:QEMU。QEMU 是一個自由且開源的模擬器,支持許多通用架構(gòu),包括:ARM、Power-PC 和 RISC-V。通過運(yùn)行一個全功能模擬器,我們可以啟動一個可以運(yùn)行 Linux 操作系統(tǒng)的通用 ARM 虛擬機(jī),然后在虛擬機(jī)中設(shè)置開發(fā)環(huán)境,編譯應(yīng)用程序。

但是,如果仔細(xì)思考下,一個全功能虛擬機(jī)有一些浪費(fèi)資源。在該模式下,QEMU 會模擬整個系統(tǒng),包括諸如定時器、內(nèi)存控制器、SPI 和 I2C 總線控制器等硬件。但是大部分情況下,我們編譯應(yīng)用程序不會關(guān)心以上所提到的硬件特性。還能更好么?

方法 3:通過 binfmt_misc 模擬目標(biāo)架構(gòu)的用戶空間

在 Linux 系統(tǒng)上,QEMU 有另外一種操作模式,可以通過用戶模式模擬器來運(yùn)行非本地架構(gòu)的二進(jìn)制程序。該模式下,QEMU 會跳過方法 2 中描述的對整個目標(biāo)系統(tǒng)硬件的模擬,取而代之的是通過 binfmt_misc 在 Linux 內(nèi)核注冊一個二進(jìn)制格式處理程序,將陌生二進(jìn)制代碼攔截并轉(zhuǎn)換后再執(zhí)行,同時將系統(tǒng)調(diào)用按需從目標(biāo)系統(tǒng)轉(zhuǎn)換成當(dāng)前系統(tǒng)。最終對于用戶來說,他們會發(fā)現(xiàn)可以在本機(jī)運(yùn)行這些異構(gòu)二進(jìn)制程序。

通過用戶態(tài)模擬器和 QEMU,我們可以通過輕量級虛擬化(chroot 或者容器)來安裝其他 Linux 發(fā)行版,并像在本地一樣編譯我們需要的異構(gòu)二進(jìn)制程序。

下面我們會看到這將會是構(gòu)建多架構(gòu) Docker 鏡像的可選方式。

方法 4:使用交叉編譯器

最后,我們還有一種在嵌入式系統(tǒng)社區(qū)標(biāo)準(zhǔn)的做法:交叉編譯。

交叉編譯器是一個特殊的編譯器,它運(yùn)行在主機(jī)架構(gòu)上,但是可以為不同的目標(biāo)架構(gòu)生成的二進(jìn)制程序。例如,我們可以有一個 amd64 架構(gòu)的 C++ 交叉編譯器,目標(biāo)架構(gòu)是一個 aarch64(64 位 ARM)的嵌入式設(shè)備(例如一個智能手機(jī)或者其他東西)?;谶@種方式的一個現(xiàn)實中的例子是,世界上數(shù)十億安卓設(shè)備都使用這種方式來構(gòu)建軟件。

從性能上考慮,這種方式有和直接在目標(biāo)硬件上構(gòu)建(方法 1)相同的效率,因為它沒有運(yùn)行在模擬器上。但是交叉編譯的變數(shù)取決于使用的編程語言,如果是 Go 語言就非常方便。

搞糊涂了嗎?對于 Docker 鏡像來說會更復(fù)雜……

注意前面提到的所有編譯方式都只是生成單一的應(yīng)用程序二進(jìn)制文件。對于現(xiàn)代容器來說,當(dāng)我們引入 Docker 鏡像的時候,不僅僅是關(guān)于構(gòu)建單獨(dú)的二進(jìn)制文件,而是構(gòu)建一整個異構(gòu)容器鏡像!這比之前說的要更加麻煩。

如果所有這些聽上去很痛苦,不要難過,因為構(gòu)建非本地平臺二進(jìn)制程序本來就很痛苦。在此之上增加 Docker 帶來的復(fù)雜度,看起來應(yīng)該留給專家來處理。

感謝最新版本 Docker 運(yùn)行時環(huán)境帶來的實驗性擴(kuò)展,構(gòu)建多架構(gòu)鏡像現(xiàn)在比以前方便多了。

構(gòu)建多架構(gòu) Docker 鏡像

為了能夠更方便的構(gòu)建多架構(gòu) Docker 鏡像,我們可以使用最近發(fā)布的 Docker 擴(kuò)展:buildx。buildx 是下一代標(biāo)準(zhǔn) docker build 命令的前端,既我們熟悉的用于構(gòu)建 Docker 鏡像的命令。通過借助 BuildKit 的所有功能,buildx 擴(kuò)展了表中 docker build 命令的功能,成為 Docker 構(gòu)建系統(tǒng)的新后端。

讓我們花幾分鐘看下如何使用 buildx 來構(gòu)建多架構(gòu)鏡像。

步驟 1:開啟 buildx

要使用 buildx,首先要確認(rèn)我們的 Docker 運(yùn)行時環(huán)境已經(jīng)是最新版本 19.03。新版本中,buildx 事實上已經(jīng)默認(rèn)和 Docker 捆綁在一起,但是需要通過設(shè)置環(huán)境變量 DOCKER_CLI_EXPERIMENTAL 來開啟。讓我們在當(dāng)前命令行會話中開啟: 

  1. $ export DOCKER_CLI_EXPERIMENTAL=enabled 

通過檢查版本來驗證目前我們已經(jīng)可以使用 buildx: 

  1. $ docker buildx version 
  2. github.com/docker/buildx v0.3.1-tp-docker 6db68d029599c6710a32aa7adcba8e5a344795a7 

可選步驟:從源碼構(gòu)建

如果要使用最新版本的 buildx,或者在當(dāng)前環(huán)境下設(shè)置 DOCKER_CLI_EXPERIMENTAL 環(huán)境變量不生效(例如我發(fā)現(xiàn)在 Arch Linux 系統(tǒng)中設(shè)置無效),我們可以從源碼構(gòu)建 buildx: 

  1. $ export DOCKER_BUILDKIT=1 
  2. $ docker build --platform=local -o . git://github.com/docker/buildx 
  3. $ mkdir -p ~/.docker/cli-plugins && mv buildx ~/.docker/cli-plugins/docker-buildx 

步驟 2:開啟 binfmt_misc 來運(yùn)行非本地架構(gòu) Docker 鏡像

如果讀者使用的是 Mac 或者 Windows 版本 Docker 桌面版,可以跳過這個步驟,因為 binfmt_misc 默認(rèn)開啟。

如果使用是 Linux 系統(tǒng),需要設(shè)置 binfmt_misc。在大部分發(fā)行版中,這個操作非常簡單,但是現(xiàn)在可以通過運(yùn)行一個特權(quán) Docker 容器來更方便的設(shè)置: 

  1. $ docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d 

通過檢查 QEMU 處理程序來驗證 binfmt_misc 設(shè)置是否正確: 

  1. $ ls -al /proc/sys/fs/binfmt_misc/ 
  2. total 0 
  3. drwxr-xr-x 2 root root 0 Nov 12 09:19 . 
  4. dr-xr-xr-x 1 root root 0 Nov 12 09:16 .. 
  5. -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-aarch64 
  6. -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-arm 
  7. -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-ppc64le 
  8. -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-s390x 
  9. --w------- 1 root root 0 Nov 12 09:19 register 
  10. -rw-r--r-- 1 root root 0 Nov 12 09:19 status 

然后,驗證下指定架構(gòu)處理程序已經(jīng)啟用,例如: 

  1. $ cat /proc/sys/fs/binfmt_misc/qemu-aarch64 
  2. enabled 
  3. interpreter /usr/bin/qemu-aarch64 
  4. flags: OCF 
  5. offset 0 
  6. magic 7f454c460201010000000000000000000200b7 
  7. mask ffffffffffffff00fffffffffffffffffeffff 

步驟 3:將默認(rèn) Docker 鏡像構(gòu)建器切換成多架構(gòu)構(gòu)建器

默認(rèn)情況下,Docker 會使用舊的構(gòu)建器,不支持多架構(gòu)構(gòu)建。

為了創(chuàng)建一個新的支持多架構(gòu)的構(gòu)建器,運(yùn)行:

  1. $ docker buildx create --use --name mybuilder 

驗證新的構(gòu)建器已經(jīng)生效: 

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

搞定?,F(xiàn)在 Docker 會使用新的構(gòu)建器,支持構(gòu)建多架構(gòu)鏡像。

步驟 4:構(gòu)建多架構(gòu)鏡像

好了,現(xiàn)在我們終于可以開始構(gòu)建一個多架構(gòu)鏡像了。為了演示這個功能,我們需要一個示例應(yīng)用。

讓我們創(chuàng)建一個簡單的 Go 應(yīng)用程序,輸出當(dāng)前運(yùn)行環(huán)境的架構(gòu)信息: 

  1. $ cat hello.go 
  2. package main 
  3.  
  4. import ( 
  5.         "fmt" 
  6.         "runtime" 
  7.  
  8. func main() { 
  9.         fmt.Printf("Hello, %s!\n", runtime.GOARCH) 

讓我們創(chuàng)建一個 Dockerfile 來容器化這個應(yīng)用

  1. $ cat Dockerfile 
  2. FROM golang:alpine AS builder 
  3. RUN mkdir /app 
  4. ADD . /app/ 
  5. WORKDIR /app 
  6. RUN go build -o hello . 
  7.  
  8. FROM alpine 
  9. RUN mkdir /app 
  10. WORKDIR /app 
  11. COPY --from=builder /app/hello . 
  12. CMD ["./hello"

這是一個多階段 Dockerfile,通過 Go 編譯器構(gòu)建我們的應(yīng)用程序,然后將構(gòu)建出來的二進(jìn)制程序使用 Alpine Linux 鏡像創(chuàng)建成最小鏡像。

現(xiàn)在,讓我們使用 buildx 來構(gòu)建一個支持 arm、arm64 和 amd64 架構(gòu)的多架構(gòu)鏡像,并一次性推送到 Docker Hub: 

  1. $ docker buildx build -t mirailabs/hello-arch --platform=linux/arm,linux/arm64,linux/amd64 . --push 

是的,就是這樣?,F(xiàn)在 Docker Hub 上我們有了 支持 arm、arm64 和 amd64 架構(gòu)的多架構(gòu) Docker 鏡像。當(dāng)我們運(yùn)行 docker pull mirailabs/hello-arch 時,Docker 會根據(jù)機(jī)器的架構(gòu)來獲取匹配的鏡像。

如果讀者要問 buildx 是如何實現(xiàn)這個魔法的?好吧,在命令的背后,buildx 使用 QEMU 和 binfmt_misc 創(chuàng)建了三個 Docker 鏡像(arm、arm64 和 amd64 架構(gòu)每個創(chuàng)建一個)。當(dāng)構(gòu)建完成后,Docker 會創(chuàng)建一個清單,其中包含這三個鏡像以及他們對應(yīng)的架構(gòu)。換句話說,“多架構(gòu)鏡像”實際上是一個清單,列舉了每個架構(gòu)對應(yīng)的鏡像。

步驟 5:測試多架構(gòu)鏡像

讓我們來快速測試下多架構(gòu)鏡像,以確保它們都能夠正常工作。由于我們已經(jīng)設(shè)置了 binfmt_misc,因此在開發(fā)機(jī)器上已經(jīng)能夠執(zhí)行任何架構(gòu)的鏡像了。

首先,列出每個鏡像的散列值: 

  1. $ docker buildx imagetools inspect mirailabs/hello-arch 
  2. Name:      docker.io/mirailabs/hello-arch:latest 
  3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json 
  4. Digest:    sha256:bbb246e520a23e41b0c6d38b933eece68a8407eede054994cff43c9575edce96 
  5.  
  6. Manifests: 
  7.   Name:      docker.io/mirailabs/hello-arch:latest@sha256:5fb57946152d26e64c8303aa4626fe503cd5742dc13a3fabc1a890adfc2683df 
  8.   MediaType: application/vnd.docker.distribution.manifest.v2+json 
  9.   Platform:  linux/arm/v7 
  10.  
  11.   Name:      docker.io/mirailabs/hello-arch:latest@sha256:cc6e91101828fa4e464f7eddec3fa7cdc73089560cfcfe4af16ccc61743ac02b 
  12.   MediaType: application/vnd.docker.distribution.manifest.v2+json 
  13.   Platform:  linux/arm64 
  14.  
  15.   Name:      docker.io/mirailabs/hello-arch:latest@sha256:cd0b32276cdd5af510fb1df5c410f766e273fe63afe3cec5ff7da3f80f27985d 
  16.   MediaType: application/vnd.docker.distribution.manifest.v2+json 
  17.   Platform:  linux/amd64 

有了這些散列值的幫助,我們可以逐一運(yùn)行鏡像,并觀察其輸出: 

  1. $ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:5fb57946152d26e64c8303aa4626fe503cd5742dc13a3fabc1a890adfc2683df 
  2. Hello, arm! 
  3.  
  4. $ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:cc6e91101828fa4e464f7eddec3fa7cdc73089560cfcfe4af16ccc61743ac02b 
  5. Hello, arm64! 
  6.  
  7. $ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:cd0b32276cdd5af510fb1df5c410f766e273fe63afe3cec5ff7da3f80f27985d 
  8. Hello, amd64! 

看上去很簡單,不是么?

總結(jié)

概括一下,本文我們了解了軟件支持多 CPU 架構(gòu)帶來的挑戰(zhàn),以及 Docker 的實驗性擴(kuò)展 buildx 如何幫助我們解決這些挑戰(zhàn)。通過使用 buildx,我們可以快速構(gòu)建一個多架構(gòu) Docker 鏡像,支持 arm、arm64 和 amd64 架構(gòu),而不需要修改 Dockerfile。同時這個鏡像可以推送到 Docker Hub,任何 Docker 支持的平臺都可以根據(jù)自己的架構(gòu)拉取對應(yīng)的鏡像。

未來,buildx 能力很有可能成為標(biāo)準(zhǔn) docker build 命令的一部分,我們可以不需要為使用這個功能做額外設(shè)置。把交叉編譯應(yīng)用程序比作跌入深淵的故事,不就將變成原始時代的鬼故事了。

前進(jìn),無懼多架構(gòu)!

 

責(zé)任編輯:華軒 來源: 高效開發(fā)運(yùn)維
相關(guān)推薦

2017-07-07 11:28:24

大數(shù)據(jù)大數(shù)據(jù)技術(shù)

2025-03-10 00:35:00

AndroidIPC管道

2019-04-18 10:55:00

故障演練流量

2021-04-02 06:18:27

Docker鏡像

2019-09-03 08:21:17

編碼云端程序員

2017-12-12 16:17:55

微服務(wù)系統(tǒng)運(yùn)維

2011-11-09 15:49:52

API

2009-11-20 11:37:11

Oracle完全卸載

2023-09-26 07:11:15

KubernetesJob節(jié)點(diǎn)

2016-01-08 10:03:07

硅谷通吃互聯(lián)網(wǎng)

2019-08-08 10:18:15

運(yùn)維架構(gòu)技術(shù)

2021-12-07 06:02:15

Redis Docker運(yùn)維

2024-02-20 08:08:43

2010-03-30 10:44:05

Nginx啟動

2024-12-04 13:52:30

2022-09-09 08:41:43

Netty服務(wù)端驅(qū)動

2021-05-24 10:55:05

Netty單機(jī)并發(fā)

2019-07-01 15:40:53

大數(shù)據(jù)架構(gòu)流處理

2017-11-14 08:25:36

數(shù)據(jù)庫MySQL安全登陸

2011-06-22 09:45:46

JavaScriptAPI
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號