[TOOLS] 11 分鐘閱讀OraCore 編輯部

Docker APT 讓 Ubuntu 更新不亂套

用 Docker 官方 APT repo 統一更新 Ubuntu 上的 Engine、Compose、Buildx,避免版本漂移與套件打架。

分享 LinkedIn
Docker APT 讓 Ubuntu 更新不亂套

Docker 官方 APT repo,Ubuntu 上的 Engine、Compose、Buildx 可以一起更新,不用再跟版本漂移打架。

我在 Ubuntu 機器上管 Docker 很多年了,老實講,最煩的從來不是裝不起來,是「裝得起來但每台都長得不一樣」。這台 Engine 版本新一點,那台 Compose 還卡在舊插件;Buildx 有時候在,有時候不在;然後你照著某篇教學做,下一次更新又冒出一個奇怪的差異。那種感覺很像你以為自己在維護一套工具,結果其實是在收拾一堆歷史包袱。

我後來才慢慢想通:Docker 不該被當成一次性安裝,而是要當成一個完整套件來管。Engine、Compose、Buildx,全部從同一個來源來,Ubuntu 自己的 Docker 套件就別再混進來。這件事很無聊,但無聊通常才是對的,尤其是你不想在半夜追 package drift 的時候。

這次拆的方法論,起點是 Matija 的這篇 Update Docker to Latest Version on Ubuntu。他把 Ubuntu 26.04、24.04、22.04 的更新路徑講得很直白,重點也很實際:Docker 官方 APT repo、docker-ceComposeBuildx,還有怎麼處理版本不一致的問題。

別再讓 Ubuntu 和 Docker 各管各的

訂閱 AI 趨勢週報

每週精選模型發布、工具應用與深度分析,直送信箱。不定期,不騷擾。

不會寄垃圾信,隨時可取消。

Update Docker to the latest version on Ubuntu 26.04, 24.04, or 22.04 using Docker’s official APT repo. Covers docker-ce, Compose, Buildx, and mismatch fixes.

翻譯一下就是:不要讓 Ubuntu 的套件庫跟 Docker 自己的套件庫同時想當老大。你如果今天從這邊裝 Engine、明天又從另一邊裝 Compose,短期看起來像是有裝好,長期就是等著出怪事。Engine 先升、插件沒升;Buildx 被換掉;某台機器的 CLI 路徑跟另一台不一樣。這些都不是大爆炸,但很會偷時間。

Docker APT 讓 Ubuntu 更新不亂套

我自己就踩過這種坑。兩台 Ubuntu 機器,一台是 distro repo 裝的 Docker,另一台是 Docker CE。表面上都能跑,真要 build image 的時候,行為差超多。不是那種一眼看得出來的錯,而是那種你會開始懷疑自己是不是記錯指令的怪問題。這種事最浪費的不是錯誤本身,是你對環境的信任感。

實操寫法很簡單:把 Docker 官方 repo 當唯一來源,Engine、Compose、Buildx 都從那裡來。已經混裝的機器,先清掉再升級,不要指望碰運氣。先看 apt 裡到底裝了什麼,移掉衝突套件,再重新裝回同一條供應鏈。重點不是帥,是一致。

  • Docker Engine、Compose、Buildx 用同一個套件來源。
  • 不要混 Ubuntu repo 和 Docker CE repo。
  • 每次更新後都檢查版本,別只看 apt 成功訊息。

先把 repo 建好,再讓 apt 幫你做髒活

Docker 官方 repo 的好處不是炫技,是它夠穩。你先加 GPG key,再加官方 APT source,更新套件索引,最後一次把需要的套件裝齊。這樣 apt 知道要去哪裡拿更新,不會把你帶去奇怪的依賴地獄。

我喜歡這種做法,因為它讓升級變得可預期。新版本出來,apt 看得到;你想鎖版,也能鎖;哪天機器重建,流程還是同一套,不會變成「從某篇部落格複製一段 shell,然後祈禱明年還能用」。我真的做過太多這種事,壽命都不長。

翻譯一下就是:repo 是底座,底座錯了,後面全都不用談。你要的是一條穩定的更新路徑,不是每次都重新發明安裝流程。官方文件在這裡最有用:Docker Ubuntu 安裝文件。我不是要重寫它,我只是把它的思路說白一點。

實操寫法:照官方文件把 repo 建起來,然後一次裝 Engine 和 plugins。裝完立刻查版本,不要等到出事才回頭看。這種步驟最好放進腳本或 provisioning,別靠手打記憶。

  • 先加 Docker repo,再裝任何 Docker 套件。
  • Engine、Compose、Buildx 一次裝齊。
  • 裝完用 docker version、docker compose version、docker buildx version 驗證。

Compose 和 Buildx 不該被當成附屬品

這一段很多人會跳過,然後之後才開始怪 Docker 不穩。Compose 和 Buildx 不是裝飾品,它們就是工作流的一部分。Engine 升了,插件沒跟上,行為差異就會開始冒出來,而且通常不是在最舒服的時候冒出來。

Docker APT 讓 Ubuntu 更新不亂套

Matija 的文章會把 Compose 和 Buildx 一起講,我覺得這點很對。很多更新教學只講 Docker Engine,好像大家都不用 compose、也不用 multi-platform build。現實剛好相反,大多數人碰得最多的是 compose,Buildx 也是第一次做跨平台 image 或碰到新版 build 功能時才會真的在意。你不把它們一起管,Docker 就會看起來像老半天沒整理過。

也就是說,你應該把 Docker 當 bundle,不是單一 package。Engine、Compose plugin、Buildx plugin 要一起檢查。只要其中一個落後,整組體驗就會慢半拍。

實操寫法:更新後固定跑三個指令,直接把它變成肌肉記憶。

docker version

docker compose version

docker buildx version

如果其中一個失敗,或版本跟你預期的不一樣,不要當沒看到。那就是警報。先修 package source 或重裝 plugin,再往下做。

版本檢查不是多餘,是便宜保險

我現在已經不太相信「apt 裝成功」這件事本身了。套件管理員很客氣,客氣到有點會騙人。它會跟你說安裝完成,但你之後才發現 CLI plugin 沒裝到、版本不是你要的、或某個 symlink 指到奇怪的地方。所以我每次升級完,都會立刻做版本檢查。

這聽起來很麻煩,但你被坑過一次之後就知道,這其實很省錢。快速查版本可以幫你確認 repo 對不對、plugin 有沒有真的落地、Docker 有沒有吃到你以為的那組 binaries。尤其 Ubuntu 上如果你以前手動裝過 Docker,舊檔案很愛陰魂不散。

翻譯一下就是:apt 說完工,不代表真的完工。真正完工是你常用的指令都回到正確版本,而且行為正常。這才算數。

實操寫法:每次更新 Docker 後,固定檢查 Engine、Compose、Buildx。你如果管多台 Ubuntu 主機,順手比對不同機器的輸出。版本一旦漂掉,你會比使用者先看到。

  • 安裝完立刻跑版本檢查。
  • 多台機器就比對輸出,別只看單台。
  • 如果指令指到舊 binary,先清掉舊安裝。

Ubuntu 升級時,Docker 不能跟著一起亂掉

我會喜歡這種 repo-based 做法,還有一個原因:它比較扛得住 OS 升級。Ubuntu 22.04、24.04、26.04 本來就不是同一個環境,如果你的 Docker 是從一堆混雜套件拼起來的,OS 一升級,之前那些亂七八糟的選擇就會全部浮出來。很多人這時候會怪新版本 Ubuntu,其實常常是自己前面裝得太隨便。

Docker 官方 repo 至少讓路徑清楚一點。你可以在新 Ubuntu 版本上刷新 repo metadata,必要時重裝套件,然後回到一個已知狀態。我不是說升級會變輕鬆,還是要檢查,但它不會再像在垃圾堆裡找鑰匙。

也就是說,你的 container workflow 應該能跟著 OS 維護一起活下來。你如果跑的是 local dev machine、CI runner、或小型伺服器,Docker 安裝就該穩到不會因為 Ubuntu 升級而整套重來。

實操寫法:升級 Ubuntu 前先記錄 Docker 版本和已裝套件。升級後刷新 repo 設定、必要時重裝官方套件,再驗證一次指令。若你有 automation,把這些檢查直接寫進 playbook,不要靠記憶。

把更新流程寫成規則,不要寫成手藝

我覺得這篇最有價值的地方,不是 Docker 本身,而是它逼你不要把 setup 當成一次性的手工活。我看過太多系統,之所以難維護,不是因為技術很複雜,是因為只有某個人記得六個月前手動改過什麼。那種系統不是運作中,是在等事故單。

Matija 的文章有用,因為它把流程收斂成幾個固定動作:官方 repo、一致套件、版本檢查、必要時處理 mismatch。這就是我想留在任何會重複碰到的機器上的做法。以後再回來看,也要一眼就知道該怎麼走,不要有神秘套件,也不要有「先 curl 再 pipe bash」那種讓人心累的東西。

實操寫法:把安裝與更新步驟放進內部文件、shell script,或 provisioning tool。版本檢查命令就放在安裝命令旁邊。團隊裡任何一個人要更新 Docker,都應該不用猜哪個來源才安全。

再講白一點,如果你現在那台機器已經很亂,不要想著遮掩。直接整理掉。把壞掉的 Docker install 清乾淨,通常比你之後追 weird behavior 省時間得多。

可抄的模板

# Ubuntu 上用 Docker 官方 APT repo 更新 Docker
# 適用 Ubuntu 22.04 / 24.04 / 26.04

set -euo pipefail

# 1) 移除可能衝突的舊套件
sudo apt-get remove -y docker docker-engine docker.io containerd runc || true

# 2) 安裝前置套件
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

# 3) 加入 Docker 官方 GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# 4) 加入 Docker 官方 APT repo
. /etc/os-release
ARCH=$(dpkg --print-architecture)
CODENAME=${UBUNTU_CODENAME:-$VERSION_CODENAME}
echo \
  "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  ${CODENAME} stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 5) 安裝 Engine、Compose、Buildx
sudo apt-get update
sudo apt-get install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

# 6) 驗證版本
docker version
docker compose version
docker buildx version

# 7) 可選:讓目前使用者不用 sudo 跑 Docker
sudo usermod -aG docker "$USER"

echo "請登出再登入,群組權限才會生效。"

這段我會直接放進 repo 或內部 runbook。它不花俏,但它做對了幾件事:同一個來源、插件一起裝、版本可以驗證。這才是我想要的 Docker 更新方式。

原始靈感來自 Matija 的 Update Docker to Latest Version on Ubuntu;我這篇是把他的做法拆成可執行的版本,裡面有原創整理,也有從原文延伸出的實作模板。