---
# System prepended metadata

title: containerd
tags: [k8s, tar file, container, image, containerd, 容器, ctr, Kubernetes, K8s, docker]

---

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 %}