iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
Kubernetes

Kubernetes學習心得分享系列 第 3

Day 03:【底層】Container Runtime 的演進:Docker vs. containerd

  • 分享至 

  • xImage
  •  

前言

寫這篇想要分享的重點:
搞懂 Kubernetes 底層如何透過 CRI(Container Runtime Interface)操作容器引擎,並釐清為什麼 Docker 會從 K8s 的核心運作流程中「被排除掉」,以及工程師在前線要如何用 CLI 工具進行除錯。

這篇想要講什麼:

  1. Container Runtime 演進史:從 Docker 到 CRI、CRI-O 與 containerd。
  2. 為什麼 K8s 要移除 Dockershim?這對維運會有影響嗎?
  3. 維運CLI 工具比較:crictl vs. nerdctl vs. ctr

為何要寫這篇:
前兩天我們了解了 Control Plane 與 Worker Node 的組件分工。今天我們要深入 Worker Node 的底層,去看看 kubelet 到底是如何指揮 Container Runtime 把容器跑起來的。


名詞對應

Container Runtime: 容器執行環境 / 容器運行時
CRI (Container Runtime Interface): 容器執行環境介面 / 容器運行時介面
OCI (Open Container Initiative): 開放容器倡議 / 開放容器標準
Deprecate / Remove: 棄用 / 移除
Socket: UNIX Socket 檔 / 虛擬通訊插座


1. Container Runtime 的演進史:從獨霸到標準化

在 K8s 剛誕生時,Docker 稱霸了整個容器界。但隨著 K8s 發展,社群希望能夠支援更多不同的容器技術(例如 CoreOS 的 rkt),因而產出了標準化的介面(interface)。

+-----------------------------------------------------------------------+
|                              kubelet                                  |
+-----------------------------------------------------------------------+
                                   |
                                   | (CRI 介面規範)
                                   v
+-----------------------------------------------------------------------+
|                           containerd                                  |
|   (負責管理 Image 拉取、網路配置、Lifecycle)                              |
+-----------------------------------------------------------------------+
                                   |
                                   | (OCI 介面規範)
                                   v
+-----------------------------------------------------------------------+
|                             runc                                      |
|   (真正向 Linux Kernel 申請 cgroups / namespace 生成 Container)         |
+-----------------------------------------------------------------------+

高層級 (High-Level) vs. 低層級 (Low-Level) Runtime

  • Low-Level Runtime(如 runc

    • 職責:專門負責向 Linux Kernel 申請 cgroupsnamespaces,真正建立並隔離出容器環境。它只關心怎麼把容器 Run 起來,完全不管 Image 是從哪裡下載的。
  • High-Level Runtime(如 containerdCRI-O

    • 職責:負責高層級的容器管理,包含去 Registry 拉取 Image(Pull Image)、管理快取、解壓縮、設定網路,最後再呼叫低層級的 runc 來真正啟動容器。

觀念補充:Kubernetes 的「Interface(介面)」設計

為什麼 Kubernetes 不把容器引擎、網路外掛跟儲存系統直接寫在裡面?

因為 K8s 採用了 「聲明式介面(Interface)」 設計。這就像在主機板上插顯示卡、記憶體一樣,只要硬體廠商遵守 PCIe 介面規範,不管你是 NVIDIA 還是 AMD 都可以直接插上去使用。

在 K8s 裡面,最關鍵的介面規範有以下四大核心:

+-----------------------------------------------------------------------------------+
|                                  Kubernetes                                       |
+-----------------------------------------------------------------------------------+
       | (標準化規範)                 | (標準化規範)                 | (標準化規範)
       v                              v                              v
+--------------+               +--------------+               +--------------+
|     CRI      |               |     CNI      |               |     CSI      |
| (容器執行介面) |               | (網路外掛介面) |               | (儲存設備介面) |
+--------------+               +--------------+               +--------------+
       |                              |                              |
       v (實例)                       v (實例)                       v (實例)
  containerd / CRI-O             Calico / Flannel               AWS EBS / GCP PD
       |
       | (呼叫 OCI 標準)
       v
+--------------+
|     OCI      | ---> 向 Linux Kernel 申請資源 (runc / crun)
| (底層容器標準) |
+--------------+

1. CRI (Container Runtime Interface)(容器執行介面)

  • 職責:定義了 kubelet 與底層容器執行引擎(Container Runtime)溝通的標準語言。
  • 解決的問題:讓 K8s 不用為了支援 Docker、containerd 或 CRI-O 而一直修改 core code,只要 Runtime 實作了 CRI 介面就可以直接替換使用。

2. CNI (Container Network Interface)(網路外掛介面)

  • 職責:定義了 K8s 如何為 Pod 配置網路、分配 IP 與建立跨節點網路隧道(Tunnel)
  • 常見實作Calico(支援強大 NetworkPolicy)、Flannel(極簡輕量)、Cilium(基於 eBPF 高性能網路)。
  • 工廠比喻「廠房內配線與電話通訊規範」。K8s 只要求 Pod 啟動時要有 IP 且能互相打通,具體怎麼拉線(VLAN, VXLAN, BGP)由 CNI 外掛決定。

3. CSI (Container Storage Interface)(儲存設備介面)

  • 職責:定義了 K8s 如何與外部儲存系統(Block Storage, File System)對應,處理 Volume 的 Mount / Unmount / Snapshot。
  • 常見實作:AWS EBS CSI Driver、GCP Persistent Disk。
  • 工廠比喻「倉庫外接貨架規範」。無論底層是雲端硬碟還是當地端 SAN 儲存,只要實作 CSI,Pod 就能掛載持久化資料(PersistentVolume)。

4. OCI (Open Container Initiative)(底層容器標準)

  • 職責:由 Linux 基金會維護的國際容器標準,包含「Image 格式規範」與「Container Runtime 執行規範(如 runc)」。
  • 區別:CRI 是 K8s 與 High-Level Runtime (containerd) 的溝通介面;而 OCI 則是 High-Level Runtime 與 Low-Level Runtime (runc) 的溝通標準。

整理一下:

規範名稱 全名 負責管什麼? 常見實作
CRI Container Runtime Interface 生命週期:Pod 內容器的建立、啟動、停止 containerdCRI-O
CNI Container Network Interface 網路連線:Pod IP 分配、跨節點網路打通 CalicoFlannelCilium
CSI Container Storage Interface 資料持久化:掛載硬碟、雲端儲存空間 AWS EBS DriverLonghorn
OCI Open Container Initiative 底層規格:標準容器格式與 Linux 内核隔離 runccrun

雖然看起來很抽象難懂, 不過理解越多K8S之後就會越來越理解他們為何存在, 因為東西太多了就是要先設好規範才方便抽換/開發新組件


2. 為什麼 K8s 要移除 Dockershim?

許多人在 K8s 1.24 推出時被「K8s 拔掉 Docker」的標題嚇到,以為以後不能用 Docker 包 Image 了。這完全是個誤解!

根本原因:翻譯官(Dockershim)太累了

  • Docker 當初設計時是一個給人類使用的完整產品(包含 CLI、Build、Volume、Swarm 等),它本身並沒有實作 CRI 介面
  • 為了讓 K8s 能用 Docker,K8s 官方只好自己寫了一個名為 dockershim 的轉接器(Adapter),幫 kubelet 把 CRI 指令翻譯成 Docker API,Docker 再去呼叫 containerd

智慧工廠比喻:
廠長(kubelet)只會官方語言(CRI)。但 Docker 這台舊機台語言不通,工廠只好硬塞一個翻譯機(dockershim)才能操作。最後 K8s 團隊發現:「欸?Docker 內部明明也是用 containerd 在做事,那我幹嘛不直接跳過 Docker,讓 kubelet 直接與 containerd 溝通就好了?」

棄用 Dockershim 對開發者有影響嗎?

  • 應用程式開發者(App Developer)沒差! 你還是可用 docker build 包 Image,只要符合 OCI 規範,containerd 都能跑。
  • Cluster 維運工程師(Infra/DevOps)有差! SSH 進到 Worker Node 後,不能再直接下 docker ps 去看 K8s 的容器了,必須改用針對 CRI 的工具。

3. 維運工具:crictl vs. nerdctl vs. ctr

當 SSH 進到 Worker Node 進行現場除錯時,你會發現下 docker ps 什麼都看不到,這時你有以下三款工具可以使用:

crictl(K8s 官方維運除錯)

  • 定位:專門為 CRI 設計的 CLI 工具,透過 CRI Socket 直接操作 Runtime。
  • 特點:它懂 K8s 的概念!你可以直接下指令列出 Pod(crictl pods,而不是只看到一堆亂亂的 Container。
  • 常用指令對照
    • 看容器:crictl ps
    • 看 Pod:crictl pods
    • 看 Log:crictl logs <container-id>
    • 進容器:crictl exec -it <container-id> sh

nerdctl(Docker 指令無痛轉移工具)

  • 定位:contaiNERD client,致力於提供跟 docker CLI 一模一樣的使用體驗。
  • 特點:支援 nerdctl runnerdctl build,連語法參數都跟 Docker 幾乎一樣。如果你習慣 Docker 的操作,在 Worker Node 上裝 nerdctl 會非常順手。
  • 注意:查看 K8s 的容器時,需要加上 --namespace k8s.io 參數(例如 nerdctl -n k8s.io ps)。

ctrcontainerd 原生工具)

  • 定位containerd 附帶的原始 CLI。
  • 特點:非常偏向底層,十分困難(例如連拉取 Image 都必須寫全域名稱)。通常只有在開發 containerd 外掛或極度底層除錯時才會用到。

整理一下:

工具名稱 主要用途 是否懂 K8s Pod 概念? 適合情境
crictl K8s 官方 CRI 除錯工具 YES(支援 crictl pods 日常 K8s Node 故障除錯用
nerdctl Docker 風格的替代工具 NO(需指定 -n k8s.io 命名空間) 習慣 Docker 指令、需在節點上 Build Image
ctr containerd 原生開發工具 NO 極底層 Runtime 除錯(平時少用)

結語

本篇總結:

  • Kubernetes 的強大源於 高度解耦與標準化的 Interface 設計(CRI, OCI, etc...)。

  • 移除 Dockershim 並非棄用 Docker 產出的 Image,而是讓 kubelet 能夠透過 CRI 介面直接與 containerd溝通,省去翻譯轉接工作;維運時,運用 crictlnerdctl 迅速進行除錯。

下一篇預告:
釐清了 Container Runtime 的底層機制與介面規範後,明天 Day 04 我們將回歸工作負載核心,探討 【核心】最小部署單位:Pod 的概念與 YAML 撰寫基礎!我們將說明Pod 的共享資源與生命週期狀態(Pending/Running/CrashLoopBackOff),並掌握K8S四個基本 YAML 結構與快速生成YAML技巧!

Takeaway

  • High-Level vs Low-Level Runtimecontainerd 負責拉取 Image 與網路配置,再指派 runc 向 Linux Kernel 申請資源生成容器。
  • K8s 四大 Interface:CRI(管容器)、CNI(管網路)、CSI(管儲存)、OCI(底層容器規格)— 標準訂好,組件就能自由替換。
  • 移除 Dockershim 的真相:只是拿掉中間轉接的翻譯官(Dockershim),不影響 docker build 打包與運行,應用程式開發者完全不受影響。
  • 維運 CLI 排查工具:首選 crictl(直觀看 Pod / 專為 CRI 設計);習慣 Docker 指令可用 nerdctl -n k8s.ioctr 則留給極底層除錯。

上一篇
Day 02:【架構】 Kubernetes Cluster 全貌:Control Plane 與 Worker Node
下一篇
Day 04:【核心】最小部署單位:Pod 的概念與 YAML 撰寫基礎
系列文
Kubernetes學習心得分享6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言