你的 compose 檔裡有這麼一行:
image: mcr.microsoft.com/mssql/server:2022-latest
這串東西不是隨便取的名字,而是一組精確的座標——它告訴 Docker 去哪個倉庫、找哪個櫃子、拿哪個版本。這一章把它拆到最後一個字元,順便回答幾個天天遇到卻很少人講清楚的問題:為什麼 nginx 可以只寫三個字母、latest 為什麼不是「最新版」、為什麼同事的 Mac 建出來的映像丟到公司伺服器會噴 exec format error。最後教你把自己的 Spring Boot 映像推上去。
映像名稱是一組四段式座標,完整格式長這樣:
[registry 主機]/[命名空間]/[映像名]:[標籤]
mcr.microsoft.com / mssql / server : 2022-latest
① ② ③ ④mcr.microsoft.com 是微軟自家的容器倉庫(Microsoft Container Registry)。省略時預設是 docker.io(Docker Hub)。mssql、bitnami、你的 Docker Hub 帳號。latest。因為 Docker 會自動補完:
你寫的: nginx
實際上是: docker.io/library/nginx:latest
↑ ↑ ↑ ↑
預設 registry 官方 映像名 預設 tag
命名空間library 是 Docker Hub 保留給官方映像(Official Images)的特殊命名空間——由 Docker 官方或軟體原廠維護的那批(nginx、redis、postgres、eclipse-temurin…)。這也是一個安全訊號:
redis(=library/redis)→ 官方維護,可信度高。someguy/redis → 某個路人自己建的,內容你完全不知道。名字只差一個斜線,信任等級天差地遠。ngnix(故意拼錯)或 mysqI(大寫 i 假裝小寫 L)的映像,等你手殘打錯就中招。複製貼上官方文件的映像名,不要憑印象手打。mcr.microsoft.com/mssql/server:2022-latest 的白話翻譯是:「去微軟的官方倉庫,找 mssql 這個櫃子裡的 server 抽屜,拿標著 2022-latest 的那一份。」latest 只是一個「預設標籤名」,沒有任何「最新」的含義。它不會自動指向最新版本,Docker 也不會幫你更新它。它就是一個字串,跟 v1、stable、banana 沒有本質差別。latest,那 latest 就永遠停在 v1.0。「latest 指向最新」純粹是靠維護者自律,不是機制保證。你今天: docker pull myapp:latest → 拿到 v1.0
(維護者推了新版,latest 被重新指向 v2.0)
同事明天: docker pull myapp:latest → 拿到 v2.0同一行指令、同一個名字、不同的東西。這正是「在我電腦上可以跑」的容器版翻版——你以為容器解決了環境不一致,結果被 latest 又打回原形。eclipse-temurin:17.0.9_9-jre-jammy,至少 17-jre。myapp:1.4.2、myapp:a3f91c2。這樣「正式環境跑的是哪一版程式碼」永遠有答案。mssql/server:2022-latest 也是同樣狀況:它代表「SQL Server 2022 這條線的最新累積更新」,會隨時間變動。開發環境無妨(甚至是好事,自動拿到修補),但如果你要精確重現某次的環境,就得釘死更明確的版本。既然標籤會變,那有沒有「絕對指向同一個東西」的方式?有,就是 digest。
docker pull nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31a3f91c2 這個 commit 永遠是同一份程式碼。要精確描述「是哪一份東西」,只能用後者。# 查出目前 tag 對應的 digest
docker inspect --format='{{index .RepoDigests 0}}' nginx:1.25
# compose 檔釘死(正式環境建議)
services:
app:
image: myregistry.io/myapp@sha256:abc123...你打 docker pull nginx 之後,實際上跟 registry 進行了三輪對話:
Already exists),只下載缺的。ch03 講的分層下載,就發生在這一步。問題來了:nginx:latest 要給 Intel/AMD 的 x86 伺服器用,也要給 M 系列 Mac 和樹莓派的 ARM 用。同一個名字,怎麼可能同時是兩種東西?
答案是 manifest list(又稱 image index)——一份「清單的清單」:
nginx:latest (manifest list)
├── linux/amd64 → 指向 A 這份 manifest
├── linux/arm64 → 指向 B 這份 manifest
└── linux/arm/v7 → 指向 C 這份 manifest你 pull 的時候,Docker 會自動報上自己的作業系統與 CPU 架構,registry 就給對應的那份。所以你的 M1 Mac 拿到 arm64 版、公司的 x86 伺服器拿到 amd64 版——同一行指令,各取所需。
docker build 出自己的 Spring Boot 映像 → 它是 arm64 的 → 推上 registry → 部署到公司 x86 Linux 伺服器 → 容器起不來,錯誤訊息是:exec format error或 no matching manifest for linux/amd64。# 指定單一目標架構
docker build --platform linux/amd64 -t myapp:1.0 .
# 一次建出多架構並推送(需要 buildx)
docker buildx build --platform linux/amd64,linux/arm64 \
-t myregistry.io/myapp:1.0 --push .推送的關鍵觀念只有一個:映像的名字就是它的位址。要推到哪裡,就得先把名字改成那個位址。
# ① 建置(本機名稱,還沒有 registry 位址)
docker build -t myapp:1.0 .
# ② 重新命名成「目的地座標」——這步是關鍵
docker tag myapp:1.0 yourname/myapp:1.0
# ↑本機名 ↑帳號/映像名:版本
# ③ 登入
docker login
# ④ 推送
docker push yourname/myapp:1.0docker tag myapp:1.0 myharbor.company.com/team/myapp:1.0
docker push myharbor.company.com/team/myapp:1.0docker tag 不會複製任何資料,只是替同一個映像多取一個名字(多一個指標)——所以它是瞬間完成的。docker login 之後,憑證預設存在 ~/.docker/config.json,而且可能只是 base64 編碼,不是加密。任何能讀到這個檔案的人就拿到了你的推送權限。docker-credential-ecr-login),或在 CI 用短期權杖(AWS ECR 的登入權杖 12 小時就過期)。toomanyrequests: You have reached your pull rate limit。registry:2。docker pull 這個動作的本質是:從網路上下載一整套別人準備的檔案系統,然後在你的機器上執行它。用這個角度想,就知道該謹慎了。
library/ 命名空間)與 Verified Publisher 標記;沒有這兩者的映像,等於來路不明的執行檔。latest 隨機決定。docker scout cves myapp:1.0 # Docker 內建
trivy image myapp:1.0 # 業界常用的開源工具接到 CI 裡,有高風險漏洞就擋下建置。ubuntu 基底裝了幾百個套件,每個都是潛在漏洞;alpine 或 distroless 只有必要的東西,攻擊面小一個數量級(ch10 詳談,含 Java 的選擇建議)。| 段落 | 作用 | 省略時的預設 | 範例 |
|---|---|---|---|
| ① Registry 主機 | 去哪個倉庫拿 | docker.io(Docker Hub) | mcr.microsoft.com |
| ② 命名空間 | 哪個組織/帳號的櫃子 | library(官方映像專用) | mssql、bitnami、你的帳號 |
| ③ 映像名 | 哪個軟體(抽屜) | 必填 | server、nginx、redis |
| ④ 標籤 | 哪個版本 | latest | 2022-latest、17-jre、1.4.2 |
| 面向 | Tag(標籤) | Digest(摘要) |
|---|---|---|
| 長相 | nginx:1.25 | nginx@sha256:0d17b565c37b… |
| 本質 | 可變的指標(像 Git 分支名) | 內容算出的雜湊(像 commit SHA) |
| 會不會變 | 會!維護者隨時可重新指向 | 永遠不會(變了就是另一個 digest) |
| 可讀性 | 好記好讀 | 又長又難記 |
| 可重現性 | 無保證 | 100% 保證同一份東西 |
| 適用場景 | 開發、日常操作 | 正式環境部署、K8s、稽核 |
| 地雷 | 症狀 | 原因 | 正解 |
|---|---|---|---|
| 用 latest 上正式環境 | 不同機器跑到不同版本,無法回滾 | latest 只是預設標籤名,會被覆寫 | 釘明確版本或 digest;自家映像用 commit SHA 當 tag |
| M1 Mac 建的映像上 x86 伺服器 | exec format error | 建出來的是 arm64 映像 | docker build --platform linux/amd64,或 buildx 建多架構 |
| 拉到 typosquatting 映像 | 映像內含惡意程式 | 手打名字打錯一個字母(ngnix、mysqI) | 複製官方文件的名稱;確認是 library/ 官方映像 |
| CI 突然拉不動映像 | toomanyrequests: pull rate limit | 整棟樓共用對外 IP,匿名拉取額度用光 | 登入後拉、架 pull-through cache、或複製到自家 registry |
點擊卡片翻面查看答案,共 10 張。