跳到主要內容
Joey
EN
← 回到文章

軟體開發

Kubernetes 是什麼?它跟 Docker 到底差在哪?

從一個 API 的三個副本開始,理解 Kubernetes 如何維持期望狀態,以及它與 Docker 分別解決什麼問題。

今天分享的主題是 Kubernetes。

核心差異可以先濃縮成一句話:Docker 負責把應用程式包好並執行,Kubernetes 負責多個容器跨機器之後的協調。

兩者不是互相取代的產品。它們處理的是不同階段的問題。

如果一個服務只跑在一台機器上,Docker 或 Docker Compose 通常已經足夠。當服務開始需要多個副本、多台機器、持續更新與故障替換,問題才從「container 能不能跑」變成「整個系統能不能維持原本的狀態」。

這正是 Kubernetes 要處理的事情。

一個 container 很好管理,三個就開始需要協調

假設一個購物網站有一支 API。

開發者寫好 Dockerfile,建出 image,再把 image 跑成 container。程式在筆電、測試機與 production 使用相同環境,減少了「本機能跑,上線卻壞掉」的落差。

Docker 本來就是用來開發、散布與執行應用程式的平台。Docker 官方文件也是這樣定義的。

後來流量增加,API 擴成三個 containers,分散在兩台機器上。這時會出現幾個新的問題:

  • 一台機器故障後,缺少的副本要補到哪裡?
  • 新版本如何逐步替換舊版本,避免三個副本同時停止?
  • 新 container 取得不同 IP 後,流量要送到哪裡?
  • 某個副本雖然還活著,卻無法正常回應時,是否還能繼續接收流量?

在規模不大時,這些工作確實可以用 shell script、排程工具與 load balancer 處理。這個做法沒有錯,而且通常更直接。

但隨著服務、機器與部署次數增加,每一項例外都需要新的判斷。container 本身仍然正常運作,複雜度卻轉移到副本、版本與網路之間的協調。

Kubernetes 將這些協調工作放進同一套控制機制。

Kubernetes 管的是期望狀態

Kubernetes 最重要的概念不是 Pod,也不是 YAML,而是 desired state,也就是系統應該維持的狀態。

以剛才的 API 為例,設定可以寫成:「執行三個副本,使用 v2 image。」

Kubernetes 會持續比較期望狀態與目前狀態:

  • 實際有三個副本,不需要調整。
  • 只剩兩個副本,建立一個新的。
  • 某個副本未通過健康檢查,停止把流量送過去。
  • image 改成 v3,逐步建立新版並移除舊版。

Kubernetes 官方把 object 稱為「意圖的紀錄」。spec 保存期望狀態,status 記錄目前狀態,control plane 則持續讓兩者靠近。Kubernetes objects 描述的就是這個 reconciliation 過程。

因此,YAML 只是常見的設定格式。Kubernetes 的核心價值,是背後持續檢查與修正狀態的控制機制。

三個物件構成最低限度的心智模型

Kubernetes 有很多物件。入門階段先掌握 PodDeploymentService,已經足以理解一個普通 API 如何運行。

Pod 是最小部署單位

Kubernetes 不直接把單一 container 當成最小部署單位,而是管理 Pod

一個 Pod 可以包含一個或多個 containers。這些 containers 共享網路與部分儲存資源,也會被一起排到同一台 Node。最常見的情況仍是一個 Pod 放一個主要 container。Kubernetes Pods 有完整定義。

Pod 的設計讓必須一起運行的 containers 維持在同一個部署單位。例如主要應用程式旁邊可以放一個 sidecar,協助處理 log 或其他輔助工作。

不過,Pod 不是一台永久存在的主機。Pod 失敗或被替換後,名稱與 IP 都可能改變。

Deployment 維持副本與版本

三個 API Pods 通常不會由開發者逐一建立,而是交給 Deployment 管理。

Deployment 會記錄 image、版本與副本數。少一個 Pod 時,controller 會建立新的;版本改變時,Deployment 可以逐步 rollout 新版,再移除舊版。Kubernetes Deployment 負責的就是這組 Pods 的更新與副本管理。

Deployment 不會讓 container 永遠不失敗。它處理的是失敗之後,如何讓實際副本數回到宣告的狀態。

Service 提供穩定入口

Pod 會被建立與替換,IP 也會改變。如果其他服務直接依賴某個 Pod IP,Pod 一旦被替換,原本的連線資訊就會失效。

Service 為一組 Pods 提供穩定的網路入口,再把流量送到符合條件的後端。Kubernetes Service 解決的是服務發現與穩定存取問題。

整條路徑可以整理成:

[ KUBERNETES FLOW ]
Image ──▶ Deployment (replicas: 3)
                 creates / replaces
                          │
                          ▼
               ┌─────────────────────┐
               │ Pod A  Pod B  Pod C │
               │  v2     v2     v2   │
               └──────────▲──────────┘
                  routes requests
                          │
Client ──▶ Service ───────┘

Pod 失敗後,Deployment 補上新的 Pod。新 Pod 的 IP 即使改變,其他服務仍透過同一個 Service 存取 API。

Docker 與 Kubernetes 處理不同層次

兩者的差異可以整理成這張表:

問題 Docker Kubernetes
主要工作 建置、散布與執行應用程式 管理叢集中的容器化工作負載
常見單位 Dockerfile、image、container、network、volume Pod、Deployment、Service 與其他 API objects
關心的事情 應用程式如何在一致的環境執行? 多個副本跨機器後,如何維持期望狀態?
常見範圍 container 的建置與執行 副本、排程、更新、故障替換與服務發現

實務上,常見流程是先用 Docker 工具建置 image,再交給 Kubernetes 叢集中的 container runtime 執行。

「Kubernetes 1.24 移除了 Docker」是一個容易造成誤解的說法。移除的是 Kubernetes 內建的 dockershim,不是 Docker image 格式。官方的 Dockershim Removal FAQ 明確說明,docker build 產生的 images 仍能在 CRI implementations 上執行。

另一個常見說法是「Docker 是命令式,Kubernetes 才是宣告式」。這也不精確。Docker Compose 同樣能用 YAML 宣告多容器應用。真正的差異不是設定檔格式,而是 Kubernetes 會在叢集層持續執行 reconciliation。

Self-healing 維持的是運行狀態

Kubernetes 提供的 self-healing 包含重新啟動失敗的 container、替換失敗的 Pod,以及停止把流量送給尚未 ready 的副本。Kubernetes overview 列出的也是這些具體行為。

這些能力可以處理基礎設施與執行層的故障,但不會修正應用程式邏輯。

例如購物網站把 100 元的商品算成 1000 元,Kubernetes 不會理解價格算錯。它只會維持指定的副本數。這代表 self-healing 保護的是工作負載的運行狀態,不是程式的正確性。

Kubernetes 也不會自動包辦 CI/CD、資料庫、監控與告警。Kubernetes 官方同樣強調,它不是一套包含所有平台能力的一體式 PaaS。

什麼時候值得使用 Kubernetes?

Kubernetes 的能力伴隨額外成本。團隊需要維護 control plane、權限、網路、叢集升級、憑證、觀測與資源限制。它把常見的協調問題放進一套共同機制,但不會讓營運工作消失。

如果系統只有一個小型服務、一台機器,而且可以接受人工部署,Docker Compose 通常更直接。

當系統需要多台機器、多個副本、頻繁 rollout、自動故障替換與穩定的 service discovery,Kubernetes 的複雜度才可能值得。

最後可以把選擇方式濃縮成兩個問題:目前缺少的是「把程式一致地跑起來」,還是「讓多個執行中的副本長期維持期望狀態」?

前者主要是 Docker 的工作。後者才是 Kubernetes 開始發揮價值的地方。