[調度] 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 %}