Docker多架構(gòu)鏡像構(gòu)建全過程
- 項(xiàng)目:cust-cont (自定義容器服務(wù))
- 目標(biāo):實(shí)現(xiàn)一次構(gòu)建同時(shí)支持 ARM64 和 AMD64 平臺(tái)的 Docker 鏡像
一、背景與需求
1.1 原有方案
項(xiàng)目原有兩個(gè)獨(dú)立的構(gòu)建腳本:
| 腳本 | 用途 | 構(gòu)建命令 |
|---|---|---|
| docker_build_arm.sh | 構(gòu)建 ARM 鏡像 | docker build |
| docker_build_x86.sh | 構(gòu)建 x86 鏡像 | docker build --platform linux/amd64 |
痛點(diǎn):
- 每次發(fā)版需要分別執(zhí)行兩個(gè)腳本
- 生成兩個(gè)獨(dú)立的 tar 包,管理成本高
- 無法生成統(tǒng)一的多架構(gòu)鏡像
1.2 目標(biāo)方案
實(shí)現(xiàn)一個(gè)統(tǒng)一的構(gòu)建腳本 docker_build.sh,支持:
- 一次構(gòu)建生成多架構(gòu)鏡像(ARM64 + AMD64)
- 支持推送到私有倉庫或?qū)С鲭x線 tar 包
- 通過參數(shù)靈活控制構(gòu)建行為
二、技術(shù)方案
2.1 核心技術(shù):Docker Buildx
Docker Buildx 是 Docker 官方的多架構(gòu)構(gòu)建工具,基于 BuildKit 實(shí)現(xiàn)。
架構(gòu)原理:
┌─ linux/amd64 鏡像層
registration_info:v1.0 ──┤
└─ linux/arm64 鏡像層
一個(gè)鏡像 tag 包含多架構(gòu) manifest,部署時(shí) Docker 自動(dòng)選擇對(duì)應(yīng)架構(gòu)。
2.2 構(gòu)建策略
| 場景 | Driver | 說明 |
|---|---|---|
| 單架構(gòu)構(gòu)建 | docker (默認(rèn)) | 使用本地 Docker daemon,可利用本地鏡像緩存 |
| 多架構(gòu)構(gòu)建 | docker-container | 在獨(dú)立 BuildKit 容器中構(gòu)建,支持跨架構(gòu) |
2.3 輸出格式
| 模式 | 格式 | 導(dǎo)入方式 |
|---|---|---|
| 單架構(gòu)導(dǎo)出 | Docker tar | docker load < image.tar |
| 多架構(gòu)導(dǎo)出 | OCI tar | docker load < image.tar |
| 推送倉庫 | Registry | docker pull registry/image:tag |
三、實(shí)施過程
3.1 環(huán)境要求
# 檢查 Docker 版本(需要 19.03+) docker version # 實(shí)際版本: 29.1.4 # 檢查 Buildx 是否可用 docker buildx version # 實(shí)際版本: v0.30.1
3.2 創(chuàng)建構(gòu)建腳本
創(chuàng)建 docker_build.sh,主要功能:
# 參數(shù)解析 --push # 推送到私有倉庫 --save # 導(dǎo)出為離線 tar 包 --registry <addr> # 私有倉庫地址(默認(rèn): 192.168.50.32) --platform <p> # 目標(biāo)平臺(tái): amd64, arm64, all(默認(rèn): all) --version <ver> # 鏡像版本(默認(rèn): 時(shí)間戳) --skip-build # 跳過 Maven 構(gòu)建
3.3 安裝 QEMU 模擬器
在 x86 機(jī)器上構(gòu)建 ARM 鏡像需要 QEMU:
# 安裝 ARM64 QEMU 模擬器 docker run --rm --privileged tonistiigi/binfmt --install arm64 # 驗(yàn)證支持的架構(gòu) # 輸出: linux/amd64, linux/arm64, ...
四、問題排查與解決
4.1 問題一:單架構(gòu)構(gòu)建時(shí) docker driver 不支持導(dǎo)出
現(xiàn)象:
ERROR: Docker exporter is not supported for the docker driver.
?
原因:
docker buildx build --output type=docker,dest=file.tar
在使用默認(rèn) docker driver 時(shí)不支持直接導(dǎo)出到文件。
解決方案:
單架構(gòu)導(dǎo)出時(shí)改用傳統(tǒng)的 docker build + docker save 方式:
# 單架構(gòu)構(gòu)建 docker build --platform linux/amd64 -t image:tag . docker save -o image.tar image:tag
4.2 問題二:跨架構(gòu)構(gòu)建報(bào) exec format error
現(xiàn)象:
exec /bin/sh: exec format error
原因:
在 x86 機(jī)器上構(gòu)建 ARM 鏡像時(shí),需要 QEMU 模擬器來執(zhí)行 ARM 二進(jìn)制文件。
解決方案:
# 安裝 QEMU docker run --rm --privileged tonistiigi/binfmt --install arm64
4.3 問題三:Buildx 無法訪問 Docker Hub(核心問題)
現(xiàn)象:
ERROR: failed to do request: Head "https://registry-1.docker.io/v2/...": dial tcp xxx:443: i/o timeout
原因分析:
| 構(gòu)建方式 | Driver | 網(wǎng)絡(luò)環(huán)境 | 鏡像緩存 |
|---|---|---|---|
| docker build | docker | 宿主機(jī)網(wǎng)絡(luò) | 使用宿主機(jī)緩存 |
| docker buildx (多架構(gòu)) | docker-container | 獨(dú)立容器網(wǎng)絡(luò) | 獨(dú)立緩存,需重新拉取 |
關(guān)鍵區(qū)別:
- 普通
docker build使用宿主機(jī)的 Docker daemon,可以使用/etc/docker/daemon.json中配置的鏡像加速器 - Buildx docker-container driver 運(yùn)行在獨(dú)立的 BuildKit 容器中,有自己獨(dú)立的網(wǎng)絡(luò)和配置,不會(huì)自動(dòng)使用宿主機(jī)的鏡像加速器配置
驗(yàn)證步驟:
# 檢查宿主機(jī)是否能訪問 Docker Hub curl -s --connect-timeout 5 https://registry-1.docker.io/v2/ # 返回 UNAUTHORIZED 說明可以連接 # 查看宿主機(jī)鏡像加速器配置 cat /etc/docker/daemon.json # 已配置: docker.1ms.run, docker.xuanyuan.me
解決方案:
步驟一:創(chuàng)建 BuildKit 配置文件
mkdir -p ~/.docker/buildx cat > ~/.docker/buildx/buildkitd.toml << 'EOF' [registry."docker.io"] mirrors = ["docker.1ms.run", "docker.xuanyuan.me"] EOF
步驟二:創(chuàng)建使用該配置的 Builder
# 刪除舊的 builder docker buildx rm multiarch 2>/dev/null || true # 創(chuàng)建新的 builder,關(guān)鍵參數(shù): # --driver-opt network=host 使用宿主機(jī)網(wǎng)絡(luò) # --config 指定 buildkit 配置文件 docker buildx create \ --name multiarch \ --driver docker-container \ --driver-opt network=host \ --config ~/.docker/buildx/buildkitd.toml \ --use # 啟動(dòng)并驗(yàn)證 docker buildx inspect --bootstrap
驗(yàn)證配置生效:
File#buildkitd.toml: > [registry] > [registry."docker.io"] > mirrors = ["docker.1ms.run", "docker.xuanyuan.me"]
五、最終測試結(jié)果
| 測試場景 | 命令 | 結(jié)果 | 輸出 |
|---|---|---|---|
| 單架構(gòu) AMD64 | --save --platform amd64 | ? 成功 | *_amd64.tar (300M) |
| 單架構(gòu) ARM64 | --save --platform arm64 | ? 成功 | *_arm64.tar (324M) |
| 多架構(gòu) | --save | ? 成功 | *_multiarch.tar (258M) |
六、腳本使用指南
6.1 基本用法
# 查看幫助 ./docker_build.sh --help
6.2 導(dǎo)出離線 tar 包
# 導(dǎo)出多架構(gòu)包(ARM64 + AMD64) ./docker_build.sh --save # 導(dǎo)出指定版本 ./docker_build.sh --save --version 1.2.0 # 只導(dǎo)出 x86 架構(gòu) ./docker_build.sh --save --platform amd64 # 只導(dǎo)出 ARM 架構(gòu) ./docker_build.sh --save --platform arm64 # 跳過 Maven 構(gòu)建(jar 包已存在時(shí)) ./docker_build.sh --save --skip-build
6.3 推送到私有倉庫
# 推送到默認(rèn)倉庫 (192.168.50.32) ./docker_build.sh --push # 推送到指定倉庫 ./docker_build.sh --push --registry 10.0.0.100 # 指定版本推送 ./docker_build.sh --push --version 1.2.0
6.4 輸出文件說明
| 命令 | 輸出文件 | 格式 |
|---|---|---|
| --save | images/registration_info_<版本>_multiarch.tar | OCI |
| --save --platform amd64 | images/registration_info_<版本>_amd64.tar | Docker |
| --save --platform arm64 | images/registration_info_<版本>_arm64.tar | Docker |
6.5 目標(biāo)機(jī)器導(dǎo)入
# 導(dǎo)入鏡像 docker load < registration_info_<版本>_multiarch.tar # 查看導(dǎo)入的鏡像 docker images | grep registration_info
七、常見問題 FAQ
Q1: 首次運(yùn)行多架構(gòu)構(gòu)建很慢?
首次運(yùn)行需要:
- 拉取 BuildKit 鏡像 (
moby/buildkit:buildx-stable-1) - 拉取基礎(chǔ)鏡像的多架構(gòu)層
后續(xù)構(gòu)建會(huì)使用緩存,速度會(huì)快很多。
Q2: 如何更新鏡像加速器地址?
編輯配置文件:
vim ~/.docker/buildx/buildkitd.toml
然后重建 builder:
docker buildx rm multiarch # 下次運(yùn)行腳本會(huì)自動(dòng)重建
Q3: 如何清理構(gòu)建緩存?
# 清理 buildx 緩存 docker buildx prune # 清理所有緩存(謹(jǐn)慎使用) docker buildx prune -a
Q4: 多架構(gòu)包比單架構(gòu)包?。?/h3>
是的,OCI 格式的多架構(gòu)包使用了更高效的壓縮和層去重,所以可能比兩個(gè)單架構(gòu)包加起來更小。
八、相關(guān)文件
| 文件 | 說明 |
|---|---|
| docker_build.sh | 多架構(gòu)構(gòu)建腳本 |
| docker_build_arm.sh | 原 ARM 構(gòu)建腳本(保留) |
| docker_build_x86.sh | 原 x86 構(gòu)建腳本(保留) |
| ~/.docker/buildx/buildkitd.toml | BuildKit 鏡像加速器配置 |
| Dockerfile | 鏡像構(gòu)建文件 |
參考資料:
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Mac下 docker 無法 ping 通宿主機(jī)的問題
這篇文章主要介紹了解決Mac下 docker 無法 ping 通宿主機(jī)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Docker部署mysql遠(yuǎn)程連接 解決2003的問題
這篇文章主要介紹了Docker部署mysql遠(yuǎn)程連接 解決2003錯(cuò)誤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
docker報(bào)錯(cuò)"no space left on device&qu
文章說明因Docker根目錄空間不足導(dǎo)致的問題,解決方案為遷移至更大空間目錄,步驟包括檢查磁盤使用、關(guān)閉Docker、創(chuàng)建新目錄、復(fù)制數(shù)據(jù)、修改配置文件路徑并重啟服務(wù),以確保數(shù)據(jù)安全和配置正確2025-09-09
Docker 部署Go的兩種基礎(chǔ)鏡像的實(shí)現(xiàn)
這篇文章主要介紹了Docker 部署Go的兩種基礎(chǔ)鏡像的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04

