containerd === ###### tags: `K8s` ###### tags: `Kubernetes`, `k8s`, `container`, `容器`, `containerd`, `docker`, `image`, `tar file`, `ctr` <br> [TOC] <br> ## DEMO ### pull image ``` $ sudo ctr image pull docker.io/library/ubuntu:latest ``` ### run image ``` $ sudo ctr run --rm -t docker.io/library/ubuntu:latest test-container bash ``` - 使用 `ubuntu:latest` 映像(來自 Docker Hub) - 容器名稱為 `test-container` - 執行 `bash` 指令 - `--rm` 表示容器結束後自動刪除 container metadata - 使用 `-t` 分配 TTY - 有 `-t` ![](https://hackmd.io/_uploads/BJvbhMhzgl.png) - 沒有 `-t` (沒有 user & host-name 資訊) ![](https://hackmd.io/_uploads/BygV2z2Mgl.png) ### list container ``` $ sudo ctr container list CONTAINER IMAGE RUNTIME test-container docker.io/library/ubuntu:latest io.containerd.runc.v2 ``` <br> <hr> <br> ## 操作對照 ### 🧾 containerd vs docker 指令對照表 > by gpt-4o (2025/06/03) | 功能 | `ctr` 指令 (containerd) | 對應的 `docker` 指令 | |-----|-------------------------|--------------------| | 列出容器 | `sudo ctr -n k8s.io containers list` | `docker ps -a` | | 列出執行中的容器 | `sudo ctr -n k8s.io tasks list` | `docker ps` | | 建立容器 | `sudo ctr -n k8s.io run <image> <name>` | `docker run --name <name> <image>` | | 進入容器 | `sudo ctr -n k8s.io task exec --exec-id <id> -t <name> sh` | `docker exec -it <name> sh` | | 啟動容器 | `sudo ctr -n k8s.io tasks start <name>` | `docker start <name>` | | 停止容器 | `sudo ctr -n k8s.io tasks kill -s SIGTERM <name>` | `docker stop <name>` | | 強制停止容器 | `sudo ctr -n k8s.io tasks kill -s SIGKILL <name>` | `docker kill <name>` | | 移除 task | `sudo ctr -n k8s.io tasks rm -f <name>` | `docker rm -f <name>` | | 移除容器 | `sudo ctr -n k8s.io containers rm <name>` | `docker rm <name>` | | 拉取映像檔 | `sudo ctr -n k8s.io images pull <image>` | `docker pull <image>` | | 查看映像檔列表 | `sudo ctr -n k8s.io images list` | `docker images` | | 刪除映像檔 | `sudo ctr -n k8s.io images rm <image>` | `docker rmi <image>` | | 查看 logs | ❌(需外部工具或重導) | `docker logs <name>` | <br> <hr> <br> ## 如何進入容器 debug ? - ### 方法一:使用 `ctr task exec`(推薦方式) 你可以用 `ctr task exec` 執行一個互動 shell 到你指定的 container(例如 `tj-munge`): ```bash sudo ctr -n k8s.io task exec --exec-id debug -t tj-munge /bin/bash ``` - 若容器中沒 `/bin/bash`,請改用 `/bin/sh` 或 `/busybox/sh`: ```bash sudo ctr -n k8s.io task exec --exec-id debug -t tj-munge /bin/sh ``` - ### ✅ 方法二:進入 container 的 namespace(nsenter 程序空間): ```bash # 找到該 container 的 pid sudo ctr -n k8s.io task ls # 例如看到類似這樣的輸出: # CONTAINER PID STATUS # tj-munge 12345 RUNNING # 用 nsenter 進入該 PID 的 namespaces sudo nsenter -t 12345 -a ``` - 這種方式是「完全進入該容器的 namespace」,你會看到跟 chroot 類似的效果,但不會改 rootfs,這比較進階,適合除錯。 - ### ⚠️ 如果 task 尚未啟動:需先啟動 container 的 task 容器可能只有 metadata,task 還沒啟動,這時你需先執行: ```bash # 啟動 container 對應的 task sudo ctr -n k8s.io task start tj-munge ``` 然後再執行方法一的 `ctr task exec` 來進入。 <br> <hr> <br> ## 如何將 docker image 轉換為 containerd imgae ```bash # docker image -> tar file $ docker save munge:0.5.15 -o munge-0.5.15.tar # tar file -> containerd imgae $ sudo ctr -n k8s.io image import munge-0.5.15.tar # 確認 image 清單 $ sudo ctr -n k8s.io images list | grep munge docker.io/library/munge:0.5.15 # (雖然多了 prefix: "docker.io/library/" ,但不影響) ``` - 一開始 K8s 找不到 `munge:0.5.15` `Failed to pull image "munge:0.5.15": failed to pull and unpack image "docker.io/library/munge:0.5.15": failed to resolve reference "docker.io/library/munge:0.5.15": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed` - 在 ctr 載入 image 後,K8s 發現 `munge:0.5.15` 已經存在 ![](https://hackmd.io/_uploads/SJcfyjSzlg.png) - **留意**:k8s 系統中,使用的 containerd namespace 是 k8s.io ``` $ sudo ctr namespace list NAME LABELS default k8s.io <-- moby ``` <br> ## 討論 ### 將 Docker 建立的 Image 匯入 containerd 並使用 `ctr` 執行 - ### Question 我使用 docker build -t tmp . 所產生的 image 如何在相同 OS 下,改用 ctr 執行? - ### gpt-4o (2025/05/29) 你用 `docker build -t tmp .` 建好的 image,預設會存在 Docker 的儲存路徑中,**並不會自動出現在 containerd 的 image store 裡**。要在相同 OS 下用 `ctr` 執行該 image,你需要讓 `containerd` 也能取得這個 image。 --- ### ✅ 目標:將 Docker image 匯入 containerd,並用 `ctr` 執行 --- - #### 🔧 步驟一:從 Docker 匯出 image 成 tar 檔 ``` docker save tmp -o tmp.tar ``` - #### 🔧 步驟二:使用 `ctr` 匯入 image ``` sudo ctr -n default images import tmp.tar ``` > 補充:這裡的 `-n default` 指的是 containerd 的 namespace,預設 namespace 是 `default`,你可以用 `ctr namespaces list` 查看。 --- #### 🔍 檢查匯入成功與否 ``` sudo ctr -n default images list ``` 你應該會看到 `docker.io/library/tmp:latest` 這樣的名字。 --- - #### 🔧 步驟三:用 `ctr` 執行 container ``` sudo ctr -n default run --rm -t docker.io/library/tmp:latest tmp-container-name ``` 說明: - `--rm`:執行後刪除 container - `-t`:附加終端 - `tmp-container-name`:container 的名稱(可隨意取) - #### 🧠 補充:為何不能直接共用 image? - Docker 使用的是 `dockerd` + `containerd` 的架構,但它有自己的 metadata 層。 - Docker 與你直接操作的 `ctr` 在儲存層並不共享 metadata(image name/tag 層級資訊不同),所以要匯出後再 import。 --- #### 🧼 結束後可以刪掉 tar 檔: ``` rm tmp.tar ``` --- ### ✅ 延伸:如果你常要轉換,可以寫個腳本自動化 export/import 需要的話我可以幫你寫出這個簡化工具。 要嗎?還是你想進一步在 containerd 下指定 volume、port、env 執行 container? <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}