您好,登錄后才能下訂單哦!
這篇文章主要介紹“Docker鏡像怎么做到一次構建,到處運行”,在日常操作中,相信很多人在Docker鏡像怎么做到一次構建,到處運行問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Docker鏡像怎么做到一次構建,到處運行”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
方法 1:直接在目標硬件上構建
如果我們可以訪問目標架構硬件,同時操作系統上有我們所需的所有構建數據,那么就可以直接在硬件上編譯應用程序。
例如,對我們特定場景下構建多架構 Docker 鏡像,可以在樹莓派上安裝 Docker 運行時環境,然后和在開發機上一樣,直接在上面通過應用程序的 Dockerfile 構建鏡像。該方法是可行的,因為樹莓派的官方操作系統 Raspbian 支持本地安裝 Docker。
但是,如果我們沒法辦法方便的訪問目標硬件呢?我們可以在開發機器上直接構建非本地架構的應用程序嗎?
方法 2:模擬目標硬件
還記得和 16 位任天堂游戲機一起的快樂時光嗎?當時我只是一個小孩子,但是當我長大一點之后,我發現對諸如《超級瑪麗》和《時空之輪》等經典游戲非常懷念。不過我沒有機會擁有一臺超級任天堂游戲機,但是多虧了像 ZSNES 這樣的模擬器,讓我能回到過去,在 32 位個人電腦上體驗這些經典游戲帶來的樂趣。
通過模擬器,我們不僅能夠玩電子游戲,還能夠構建非本地二進制文件。當然這里不是使用 ZSNES,而是使用更加強大更靈活的模擬器:QEMU。QEMU 是一個自由且開源的模擬器,支持許多通用架構,包括:ARM、Power-PC 和 RISC-V。通過運行一個全功能模擬器,我們可以啟動一個可以運行 Linux 操作系統的通用 ARM 虛擬機,然后在虛擬機中設置開發環境,編譯應用程序。
但是,如果仔細思考下,一個全功能虛擬機有一些浪費資源。在該模式下,QEMU 會模擬整個系統,包括諸如定時器、內存控制器、SPI 和 I2C 總線控制器等硬件。但是大部分情況下,我們編譯應用程序不會關心以上所提到的硬件特性。還能更好么?
方法 3:通過 binfmt_misc 模擬目標架構的用戶空間
在 Linux 系統上,QEMU 有另外一種操作模式,可以通過用戶模式模擬器來運行非本地架構的二進制程序。該模式下,QEMU 會跳過方法 2 中描述的對整個目標系統硬件的模擬,取而代之的是通過 binfmt_misc 在 Linux 內核注冊一個二進制格式處理程序,將陌生二進制代碼攔截并轉換后再執行,同時將系統調用按需從目標系統轉換成當前系統。最終對于用戶來說,他們會發現可以在本機運行這些異構二進制程序。
通過用戶態模擬器和 QEMU,我們可以通過輕量級虛擬化(chroot 或者容器)來安裝其他 Linux 發行版,并像在本地一樣編譯我們需要的異構二進制程序。
下面我們會看到這將會是構建多架構 Docker 鏡像的可選方式。
方法 4:使用交叉編譯器
最后,我們還有一種在嵌入式系統社區標準的做法:交叉編譯。
交叉編譯器是一個特殊的編譯器,它運行在主機架構上,但是可以為不同的目標架構生成的二進制程序。例如,我們可以有一個 amd64 架構的 C++ 交叉編譯器,目標架構是一個 aarch74(64 位 ARM)的嵌入式設備(例如一個智能手機或者其他東西)。基于這種方式的一個現實中的例子是,世界上數十億安卓設備都使用這種方式來構建軟件。
從性能上考慮,這種方式有和直接在目標硬件上構建(方法 1)相同的效率,因為它沒有運行在模擬器上。但是交叉編譯的變數取決于使用的編程語言,如果是 Go 語言就非常方便。
搞糊涂了嗎?對于 Docker 鏡像來說會更復雜……
注意前面提到的所有編譯方式都只是生成單一的應用程序二進制文件。對于現代容器來說,當我們引入 Docker 鏡像的時候,不僅僅是關于構建單獨的二進制文件,而是構建一整個異構容器鏡像!這比之前說的要更加麻煩。
如果所有這些聽上去很痛苦,不要難過,因為構建非本地平臺二進制程序本來就很痛苦。在此之上增加 Docker 帶來的復雜度,看起來應該留給專家來處理。
感謝最新版本 Docker 運行時環境帶來的實驗性擴展,構建多架構鏡像現在比以前方便多了。
為了能夠更方便的構建多架構 Docker 鏡像,我們可以使用最近發布的 Docker 擴展:buildx。buildx 是下一代標準 docker build 命令的前端,既我們熟悉的用于構建 Docker 鏡像的命令。通過借助 BuildKit 的所有功能,buildx 擴展了表中 docker build 命令的功能,成為 Docker 構建系統的新后端。
讓我們花幾分鐘看下如何使用 buildx 來構建多架構鏡像。
步驟 1:開啟 buildx
要使用 buildx,首先要確認我們的 Docker 運行時環境已經是最新版本 19.03。新版本中,buildx 事實上已經默認和 Docker 捆綁在一起,但是需要通過設置環境變量 DOCKER_CLI_EXPERIMENTAL 來開啟。讓我們在當前命令行會話中開啟:
$ export DOCKER_CLI_EXPERIMENTAL=enabled
通過檢查版本來驗證目前我們已經可以使用 buildx:
$ docker buildx version github.com/docker/buildx v0.3.1-tp-docker 6db68d029599c6710a32aa7adcba8e5a344795a7
可選步驟:從源碼構建
如果要使用最新版本的 buildx,或者在當前環境下設置 DOCKER_CLI_EXPERIMENTAL 環境變量不生效(例如我發現在 Arch Linux 系統中設置無效),我們可以從源碼構建 buildx:
$ export DOCKER_BUILDKIT=1 $ docker build --platform=local -o . git://github.com/docker/buildx $ mkdir -p ~/.docker/cli-plugins && mv buildx ~/.docker/cli-plugins/docker-buildx
步驟 2:開啟 binfmt_misc 來運行非本地架構 Docker 鏡像
如果讀者使用的是 Mac 或者 Windows 版本 Docker 桌面版,可以跳過這個步驟,因為 binfmt_misc 默認開啟。
如果使用是 Linux 系統,需要設置 binfmt_misc。在大部分發行版中,這個操作非常簡單,但是現在可以通過運行一個特權 Docker 容器來更方便的設置:
$ docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
通過檢查 QEMU 處理程序來驗證 binfmt_misc 設置是否正確:
$ ls -al /proc/sys/fs/binfmt_misc/ total 0 drwxr-xr-x 2 root root 0 Nov 12 09:19 . dr-xr-xr-x 1 root root 0 Nov 12 09:16 .. -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-aarch74 -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-arm -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-ppc64le -rw-r--r-- 1 root root 0 Nov 12 09:25 qemu-s390x --w------- 1 root root 0 Nov 12 09:19 register -rw-r--r-- 1 root root 0 Nov 12 09:19 status
然后,驗證下指定架構處理程序已經啟用,例如:
$ cat /proc/sys/fs/binfmt_misc/qemu-aarch74 enabled interpreter /usr/bin/qemu-aarch74 flags: OCF offset 0 magic 7f454c460201010000000000000000000200b7 mask ffffffffffffff00fffffffffffffffffeffff
步驟 3:將默認 Docker 鏡像構建器切換成多架構構建器
默認情況下,Docker 會使用舊的構建器,不支持多架構構建。
為了創建一個新的支持多架構的構建器,運行:
$ docker buildx create --use --name mybuilder
驗證新的構建器已經生效:
$ docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS mybuilder * docker-container mybuilder0 unix:///var/run/docker.sock inactive default docker default default running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
搞定。現在 Docker 會使用新的構建器,支持構建多架構鏡像。
步驟 4:構建多架構鏡像
好了,現在我們終于可以開始構建一個多架構鏡像了。為了演示這個功能,我們需要一個示例應用。
讓我們創建一個簡單的 Go 應用程序,輸出當前運行環境的架構信息:
$ cat hello.go package main import ( "fmt" "runtime" ) func main() { fmt.Printf("Hello, %s!\n", runtime.GOARCH) }
讓我們創建一個 Dockerfile 來容器化這個應用
$ cat Dockerfile FROM golang:alpine AS builder RUN mkdir /app ADD . /app/ WORKDIR /app RUN go build -o hello . FROM alpine RUN mkdir /app WORKDIR /app COPY --from=builder /app/hello . CMD ["./hello"]
這是一個多階段 Dockerfile,通過 Go 編譯器構建我們的應用程序,然后將構建出來的二進制程序使用 Alpine Linux 鏡像創建成最小鏡像。
現在,讓我們使用 buildx 來構建一個支持 arm、arm64 和 amd64 架構的多架構鏡像,并一次性推送到 Docker Hub:
$ docker buildx build -t mirailabs/hello-arch --platform=linux/arm,linux/arm64,linux/amd64 . --push
是的,就是這樣。現在 Docker Hub 上我們有了 支持 arm、arm64 和 amd64 架構的多架構 Docker 鏡像。當我們運行 docker pull mirailabs/hello-arch 時,Docker 會根據機器的架構來獲取匹配的鏡像。
如果讀者要問 buildx 是如何實現這個魔法的?好吧,在命令的背后,buildx 使用 QEMU 和 binfmt_misc 創建了三個 Docker 鏡像(arm、arm64 和 amd64 架構每個創建一個)。當構建完成后,Docker 會創建一個清單,其中包含這三個鏡像以及他們對應的架構。換句話說,“多架構鏡像”實際上是一個清單,列舉了每個架構對應的鏡像。
步驟 5:測試多架構鏡像
讓我們來快速測試下多架構鏡像,以確保它們都能夠正常工作。由于我們已經設置了 binfmt_misc,因此在開發機器上已經能夠執行任何架構的鏡像了。
首先,列出每個鏡像的散列值:
$ docker buildx imagetools inspect mirailabs/hello-arch Name: docker.io/mirailabs/hello-arch:latest MediaType: application/vnd.docker.distribution.manifest.list.v2+json Digest: sha256:bbb246e520a23e41b0c6d38b933eece68a8407eede054994cff43c9575edce96 Manifests: Name: docker.io/mirailabs/hello-arch:latest@sha256:5fb57946152d26e64c8303aa4626fe503cd5742dc13a3fabc1a890adfc2683df MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/arm/v7 Name: docker.io/mirailabs/hello-arch:latest@sha256:cc6e91101828fa4e464f7eddec3fa7cdc73089560cfcfe4af16ccc61743ac02b MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/arm64 Name: docker.io/mirailabs/hello-arch:latest@sha256:cd0b32276cdd5af510fb1df5c410f766e273fe63afe3cec5ff7da3f80f27985d MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/amd64
有了這些散列值的幫助,我們可以逐一運行鏡像,并觀察其輸出:
$ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:5fb57946152d26e64c8303aa4626fe503cd5742dc13a3fabc1a890adfc2683df Hello, arm! $ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:cc6e91101828fa4e464f7eddec3fa7cdc73089560cfcfe4af16ccc61743ac02b Hello, arm64! $ docker run --rm docker.io/mirailabs/hello-arch:latest@sha256:cd0b32276cdd5af510fb1df5c410f766e273fe63afe3cec5ff7da3f80f27985d Hello, amd64!
到此,關于“Docker鏡像怎么做到一次構建,到處運行”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。