[調度] CRI === ###### tags: `K8s` ###### tags: `Kubernetes`, `k8s`, `CRI`, `Container Runtime Interface` <br> [TOC] <br> ## 術語 - CRI: Container Runtime Interface <br> ## 討論 ### 🔍 Kubernetes 使用 image 時會呼叫 docker 嗎? - ### gpt-4o (2025/04/24) 這是一個常見但經常被誤解的問題,以下幫你詳細說明 Kubernetes 在使用 image 時到底是使用哪個工具處理的。 --- ### ✅ 問題核心 > **Kubernetes 在使用 image 時,是用自己的 OCI 工具,還是用 docker?** **簡短答案:** Kubernetes **不會直接使用 `docker` CLI**,而是透過一個叫做 **CRI(Container Runtime Interface)** 的介面,來呼叫底層的 container runtime,如: - `containerd` - `CRI-O` - (舊版)`docker`(透過 `docker-shim`,但已淘汰) --- ### 🧠 詳細說明 #### 1. Kubernetes 並不綁定 docker Kubernetes 使用 CRI(Container Runtime Interface)與底層 container runtime 溝通,它本身不執行 `docker pull` 或 `docker run`。 也就是說: - `kubectl apply` - `kubectl create` - `kubectl run` 這些都**不會呼叫 docker CLI**,而是透過 CRI 去讓 container runtime 去處理 image 的拉取與容器啟動(image pull & create container)。 --- #### 2. `docker-shim` 已於 Kubernetes v1.24 移除 在舊版 Kubernetes(v1.23 以前),Kubelet 可以透過 `docker-shim` 呼叫 Docker Engine。 > ✅ 但從 **v1.24 開始,官方已移除 `docker-shim`** 所以從 v1.24 起,**Kubernetes 無法再使用 Docker 當作 container runtime。** 現在主流的 container runtimes 是: - `containerd`(Docker 內部其實也是用它) - `CRI-O`(Red Hat 系列偏好) - `gVisor`(Google 用於高安全環境) --- #### 3. 那為什麼我還能在 node 上用 `docker`? 你可能自己安裝了 Docker Engine,因此你在 K8s 的 master 或 node 上可以執行: ``` docker ps docker run ``` 但這只是這台機器額外裝了 Docker Engine,**Kubernetes 並不會透過它來啟動 Pod。** --- ### ✅ 總結圖示:Kubernetes container 執行流程 ``` kubectl │ ▼ kubelet │ ▼ Container Runtime Interface (CRI) ├── containerd ├── CRI-O └── [X] docker-shim (v1.24+ 移除) ``` --- ### 🔍 那 `docker` CLI 是做什麼的? `docker` CLI 只是你自己操作的命令列工具,跟 Kubernetes 沒有直接關聯。你能用 `docker ps`,只是因為你裝了 Docker Engine 而已。 但: - Kubernetes 的 `Pod` 並不是由這個 `docker` CLI 啟動 - Kubernetes 使用自己的 CRI 註冊好的 runtime --- ### ✅ 如何查出我的節點正在用哪個 runtime? 可以執行以下指令: ``` kubectl get node <your-node-name> -o json \\ | jq '.status.nodeInfo.containerRuntimeVersion' ``` 可能會回傳: - `containerd://1.6.15` - `cri-o://1.23.2` - `docker://20.10.7`(如果你是舊版 Kubernetes) --- ### ✅ 結論整理 | 問題 | 回答 | |------|------| | Kubernetes 會不會使用 `docker` CLI? | ❌ 不會 | | Kubernetes 如何處理 image 與 container? | ✅ 透過 CRI 與 container runtime(如 containerd) | | `docker` CLI 在 node 上還能用? | ✅ 可以,因為 Docker Engine 仍可裝 | | Kubernetes 還支援 Docker 嗎? | ❌ v1.24 起已移除 docker-shim | --- ### 💡 延伸應用 若你要在安裝流程中依據 runtime 調整邏輯,例如: - containerd 就走 A 路徑 - docker (若是舊版) 就警告 - cri-o 用特定 image 轉換方式 可以透過前述指令去動態偵測,並搭配條件判斷處理。 需要我幫你寫一段判斷 runtime 的 Python 程式嗎?😄 <br> ### shim 是什麼縮寫?實際意思是什麼? - ### gpt-4o (2025/04/24) `shim` 並不是縮寫,而是一種「軟體設計概念」 ### 👉 `shim` 的原始意義: > 在英文中,**shim** 是指「墊片、間隔片」,用來填補機械零件之間的空隙。 > 在 **軟體領域** 中,`shim` 通常指的是: > > **「一個介於兩個系統之間,用來做兼容或轉接的小層程式碼。」** --- ### 🧠 軟體中的 shim 是什麼? | 特性 | 說明 | |----------|--------------------------------------------| | 類型 | 一種 adapter pattern(轉接器設計模式) | | 功能 | 幫助「新系統」與「舊系統」之間做兼容 | | 常見用途 | API 相容層、底層切換、版本轉換、相依解耦等 | | 類似詞彙 | Adapter, Middleware, Proxy | --- ### 🔧 Kubernetes 中的 `docker-shim` 是什麼? 早期 Kubernetes 支援的 container runtime 是 Docker, 但 Kubernetes 本身並不直接控制 Docker,而是透過 **CRI(Container Runtime Interface)**。 因此,為了解耦 Kubernetes 和 Docker,官方就做了一個中間層 **`docker-shim`**: > `docker-shim` 的作用: > **將 kubelet 的 CRI 請求轉換成 Docker Engine 可以理解的命令** 流程圖簡化如下: ``` Kubernetes → CRI → docker-shim → Docker Engine ``` --- ### 🔥 為何 `docker-shim` 被移除? | 原因 | 說明 | |-----|------| | Docker 並非原生 CRI runtime | 本質不符合 K8s 要求的 CRI 標準 | | Docker 本身就使用 containerd | 多一層轉接等於效率變差、維護成本變高 | | containerd/CRI-O 已成主流 | Kubernetes 官方推薦直接使用 containerd 或 CRI-O | > ✅ 自 **Kubernetes v1.24** 起,`docker-shim` 已完全 **移除** --- ### ✅ 總結說明 | 問題 | 答案 | |--------------------------|------------------------------------------------------------------| | `shim` 是縮寫嗎? | ❌ 不是,是代表一種「中介轉接層」的軟體設計概念 | | `docker-shim` 是什麼? | 將 CRI 呼叫轉成 Docker CLI 語法的轉接層 | | 現在還需要 docker-shim? | ❌ 不再需要,自 K8s v1.24 起被移除 | | 替代方案 | ✅ 使用 `containerd`、`CRI-O` 等原生支援 CRI 的 container runtime | --- 如果你想了解 docker-shim 的原始碼架構,或需要流程圖解釋其運作原理,也可以提出,我可以補上 🔧 <br> ### - ### gpt-4o (2025/04/24) <br> ### 🔍 CRI-O 使用 image 的方式與 Docker 有什麼不同? - ### gpt-4o (2025/04/24) 本文說明 CRI-O 在 Kubernetes 中處理 image 的方式、與 Docker 的差異,以及你提到的「特定 image 轉換方式」是什麼意思。 --- ### ✅ CRI-O 是什麼? - **CRI-O** 是符合 Kubernetes CRI(Container Runtime Interface)的 container runtime。 - 它不需要 Docker,且設計上是為了讓 K8s 可以直接透過它執行 container。 - CRI-O **不需要 Docker**,它使用更底層的技術,如: - `runc`: 執行 container - `skopeo`, `podman`, `buildah`: 管理與轉換 image --- ### ✅ Docker 與 CRI-O 處理 image 的差異 | 項目 | Docker | CRI-O | |------|--------|--------| | 支援格式 | 主要支援 Docker image 格式 | 支援 Docker image + OCI 格式 | | 拉取 image | `docker pull` | `crictl pull` / `podman pull` | | 匯入 image tar | `docker load -i xxx.tar` | ❌ 無對應指令(需轉換) | | 管理工具 | `docker` CLI | `crictl`, `podman`, `skopeo` | --- ### ❗ 為何 CRI-O 不能用 `docker load`? - 在 Docker 裡可以用: ``` docker load -i myimage.tar ``` - 但在 CRI-O 中: - **沒有等效的 `crictl load`**,所以無法直接匯入 `.tar` - 必須透過轉換工具,如 `skopeo`, `podman` --- ### ✅ 如何讓 CRI-O 使用 image tar? #### 方法 1:使用 `skopeo` 轉換 image tar 到目標格式或 registry ``` # Copy image tar into CRI-O compatible registry or storage skopeo copy docker-archive:myimage.tar \ dir:/var/lib/containers/storage/converted-image # or skopeo copy docker-archive:myimage.tar \ docker://localhost:5000/myimage:tag ``` 這會將 image 推送到本地 registry,K8s 就可以從那裡拉。 或者如果你有一個私有 registry: ``` skopeo copy docker-archive:myimage.tar \ docker://localhost:5000/myimage:tag ``` 這樣就可以讓 CRI-O 從 registry 中 pull 這個 image。 #### 方法 2:使用 `podman` 載入再推送 因為 `podman` 與 CRI-O 使用相同儲存後端,你可以: ```bash # 先用 podman 載入 podman load -i myimage.tar # 然後用 podman push 到本地 registry podman push localhost/myimage:tag \ docker://localhost:5000/myimage:tag ``` 再由 Kubernetes 使用該 registry 來抓 image。 --- ### ✅ 結論整理 | 問題 | 回答 | |------|----| | CRI-O 支援 docker image 嗎? | ✅ 可以,但更偏好 OCI 格式 | | 可以直接 docker load 嗎? | ❌ 不行,要用 podman, skopeo 來轉換 | | K8s 如何讓 CRI-O 用到某個 image? | 推 image 到 registry,再讓 Pod pull | | 有沒有直接從 tar 載入的做法? | 用 skopeo copy 或 podman load + push | ### 📦 CRI-O image 處理流程與 Docker 對照 ```text Docker: docker load → local image store → run CRI-O: tar image → (skopeo/podman push) → registry → kubelet/cri-o pull ``` <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}