你想逐台将 **Kubernetes 集群从 Docker 切换为 containerd + crictl** 管理容器,并**迁移已有镜像**,这是当前主流做法,兼容未来版本的 Kubernetes(1.24+ 完全移除 dockershim)。
下面是一步步 **安全、兼容、可操作的完整替换方案**,附带镜像导入方式。
---
## ✅ 总体思路(生产环境推荐顺序)
1. ✅ 安装 containerd 和 crictl
2. ✅ 配置 containerd + systemd 服务
3. ✅ 配置 crictl 与 containerd 对接
4. ✅ 导出 Docker 镜像,导入到 containerd
5. ✅ 替换 kubelet 使用 containerd 的 CRI socket
6. ✅ 验证 kubelet、Pod 运行正常后,卸载 Docker(可选)
---
## 🧱 步骤详解
### ✅ Step 1:安装 containerd(所有节点执行)
```bash
# 如果你用的是 yum 系统(CentOS / RHEL)
yum install -y containerd
# 或使用官方版本
containerd_version="1.7.13"
wget https://github.com/containerd/containerd/releases/download/v${containerd_version}/containerd-${containerd_version}-linux-amd64.tar.gz
tar -xvf containerd-${containerd_version}-linux-amd64.tar.gz
cp bin/* /usr/bin/
```
---
### ✅ Step 2:配置 containerd 并启动
```bash
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
```
修改 `/etc/containerd/config.toml` 中:
```toml
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.6"
```
然后启动服务:
```bash
systemctl daemon-reexec
systemctl enable --now containerd
```
---
### ✅ Step 3:安装 `crictl` 并配置使用 containerd
```bash
# 下载 crictl
version="v1.28.0"
curl -LO https://github.com/kubernetes-sigs/cri-tools/releases/download/${version}/crictl-${version}-linux-amd64.tar.gz
tar -xvf crictl-${version}-linux-amd64.tar.gz -C /usr/local/bin
# 配置 crictl 连接 containerd
cat <<EOF > /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
EOF
```
验证:
```bash
crictl info
```
---
### ✅ Step 4:迁移镜像(从 Docker → containerd)
```bash
# 1. 导出 Docker 镜像为 tar 包
docker save nginx:1.23 -o nginx.tar
# 2. 使用 ctr 或 nerdctl 导入
ctr -n k8s.io images import nginx.tar
# 或者更像 Docker 的方式
# nerdctl load -i nginx.tar
```
验证镜像是否成功导入:
```bash
crictl images | grep nginx
```
---
### ✅ Step 5:配置 kubelet 使用 containerd
编辑 `/var/lib/kubelet/kubeadm-flags.env` 或 systemd 配置中 `kubelet` 启动参数:
```bash
--container-runtime=remote \
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
```
重启 kubelet:
```bash
systemctl daemon-reexec
systemctl restart kubelet
```
---
### ✅ Step 6:验证集群正常运行
```bash
kubectl get nodes
kubectl get pods -A
```
验证 Pod 的容器是否由 containerd 启动:
```bash
crictl ps
```
---
## ✅ 可选 Step 7:卸载 Docker(替换完成后)
```bash
systemctl disable --now docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
```
---
## 🔄 一台台替换注意事项(生产级)
* ❗ **不要同时使用 Docker 和 containerd 运行 kubelet**(会冲突);
* ✅ 先在 1\~2 个节点测试替换流程;
* ✅ `crictl` 替代 `docker ps` / `docker exec` 等;
* ✅ kubeadm 集群无需重新初始化,仅 kubelet 切 socket 即可;
* ✅ 镜像迁移使用 `docker save` + `ctr import` 最稳妥;
---
## 🛠 工具对照表
| 功能 | Docker 命令 | containerd + crictl |
| ------ | ----------------- | ------------------- |
| 查看容器列表 | `docker ps` | `crictl ps` |
| 查看镜像 | `docker images` | `crictl images` |
| 进入容器 | `docker exec -it` | `crictl exec -it` |
| 拉取镜像 | `docker pull` | `crictl pull` |
| 删除容器 | `docker rm` | `crictl rm` |
| 删除镜像 | `docker rmi` | `crictl rmi` |
---
## 📦 Bonus:一键迁移脚本(示意)
```bash
#!/bin/bash
set -e
# 导出镜像
docker images --format '{{.Repository}}:{{.Tag}}' | while read img; do
fname=$(echo $img | tr '/:' '_').tar
docker save $img -o /tmp/$fname
ctr -n k8s.io images import /tmp/$fname
done
```
---
如果你提供你当前的系统版本、kubeadm 版本,我可以为你**生成专用的一键替换脚本**,是否需要?
正确答案是:
> ❌ **`crictl` 无法导入镜像**
> ✅ **导入镜像应使用 `ctr` 或 `nerdctl`(containerd 原生工具)**
---
## 🔍 为什么 `crictl` 不能导入镜像?
`crictl` 是 **Kubernetes 的 CRI(Container Runtime Interface)客户端**,它基于 GRPC 与 containerd 交互,用于**管理容器和镜像元数据**,但它本身不处理镜像文件导入或构建。
> 它是控制而不是构建或传输工具。
---
## ✅ 正确的镜像导入方式(containerd):
### 方法 1:使用 `ctr`(containerd 官方工具)
```bash
# 导出 Docker 镜像
docker save nginx:1.21 -o nginx.tar
# 导入到 containerd(k8s.io namespace 是 Kubelet 使用的默认)
ctr -n k8s.io images import nginx.tar
# 查看是否导入成功
crictl images | grep nginx
```
---
### 方法 2:使用 `nerdctl`(推荐,兼容 docker 命令)
```bash
nerdctl load -i nginx.tar
nerdctl images
```
> `nerdctl` 是 containerd 的 CLI 替代 `docker`,可以用 `docker-compose`,支持 build / push / load 等。
---
## 💡 crictl 的作用总结
| 能力 | 是否支持 | 工具 |
| ------------- | ----- | ---------------------- |
| 容器管理(ps、exec) | ✅ 支持 | `crictl` |
| 镜像查看/拉取 | ✅ 支持 | `crictl images/pull` |
| 镜像导入 `.tar` | ❌ 不支持 | `ctr` / `nerdctl` |
| 镜像构建(build) | ❌ 不支持 | `nerdctl` / `buildkit` |
| 用于 Kubernetes | ✅ 支持 | `crictl` |
---
## ✅ 结论(你应该这样做)
* 如果你有 `.tar` 镜像文件(如从 Docker 导出),想导入给 containerd/k8s 使用:
* ✅ 用:`ctr -n k8s.io images import`
* 或 ✅ 用:`nerdctl load -i xxx.tar`
* **不要尝试用 `crictl` 载入镜像,它不支持。**
---
如你希望我给你一个自动从 Docker 导出并批量导入 containerd 的脚本,我可以帮你写。是否需要?
要列出 `containerd` 中的所有 **namespaces**,你可以使用 `ctr` 命令如下:
---
### ✅ 命令:
```bash
ctr namespaces list
```
---
### ✅ 示例输出:
```text
NAME LABELS
default -
k8s.io -
myns -
```
---
### ✅ 各命名空间含义说明:
| Namespace | 说明 |
| --------- | ------------------------------------------------ |
| `default` | containerd 默认使用的 namespace(非 Kubernetes) |
| `k8s.io` | **Kubelet 默认使用的 namespace**,Kubernetes 中所有容器都在这里 |
| `myns` | 你自己运行的其他容器(例如通过 `ctr -n myns` 启动的) |
---
### ✅ 你可以切换 namespace 执行操作:
```bash
# 查看 k8s 所在 namespace 的容器镜像
ctr -n k8s.io images list
# 查看 default namespace 的镜像
ctr -n default images list
```
---
如你需要查看某个 namespace 中的容器:
```bash
ctr -n k8s.io containers list
```
---
如你想在默认之外运行容器(建议明确指定 `-n`):
```bash
ctr -n myns run -d docker.io/library/nginx:latest mynginx
```
---
需要我给你写一个脚本自动遍历所有 namespace 并列出每个镜像吗?
这是个非常好的问题。我们来详细解释你看到的这两个 namespace —— `k8s.io` 和 `moby` —— 的区别,以及 containerd / crictl 对 namespace 的处理。
---
## 🔍 你看到的两个 namespace:
```
# ctr namespaces list
NAME LABELS
k8s.io -
moby -
```
| Namespace | 来源/含义 |
| --------- | ---------------------------------------------------------- |
| `k8s.io` | **Kubernetes 的默认 namespace**,`kubelet` 使用 containerd 时指定的 |
| `moby` | Docker 使用 containerd 时创建的 namespace("moby" 是 Docker 的项目代号) |
---
## 🤔 为什么会有 `moby`?
Docker 自 18.09 起,默认使用 containerd 作为内部 runtime,但它仍通过 Docker Engine(dockerd)管理容器。Docker 使用 containerd 时会将所有内容放在 namespace `moby` 中。
### 所以:
* 如果你 **安装过 Docker**,并且其后台默认使用 containerd,那么 containerd 中就会有 `moby` 命名空间;
* 即使你后来停止了 Docker,`moby` namespace 也会保留原来管理过的容器、镜像记录;
* 所以 `ctr -n moby images ls` 能看到 Docker 存过的镜像。
---
## ✅ containerd 工具的 namespace 支持
| 工具 | 是否支持命名空间 | 如何指定 namespace |
| --------- | ------------------- | -------------------------------------------------- |
| `ctr` | ✅ 支持 | `ctr -n <namespace>`,默认是 `default` |
| `crictl` | ❌ 不支持手动指定 namespace | 固定使用 `k8s.io`,不可更改 |
| `nerdctl` | ✅ 支持(间接) | 通过 `--namespace` 参数,如 `nerdctl --namespace=k8s.io` |
### 示例:
```bash
# 查看 Kubernetes 使用的镜像
ctr -n k8s.io images list
# 查看 Docker 使用 containerd 时存储的镜像
ctr -n moby images list
# 使用 nerdctl 查看指定 namespace
nerdctl --namespace=k8s.io images
```
---
## ✅ Kubernetes 强制使用 `k8s.io` namespace
在 `containerd` 的配置 `/etc/containerd/config.toml` 中,你会看到如下字段(Kubernetes 使用时必须设置):
```toml
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.6"
...
```
Kubelet 启动时使用参数:
```bash
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
```
此时默认会访问 containerd 的 `k8s.io` namespace,因此:
> crictl 始终操作的是 `k8s.io` 命名空间,**不支持切换**。
---
## ✅ 总结
| 工具 | 默认 namespace | 是否可切换 namespace | 典型用途 |
| --------- | ------------ | ------------------ | ---------------- |
| `ctr` | default | ✅ 支持 | 调试 containerd 内部 |
| `crictl` | `k8s.io` | ❌ 不支持 | Kubelet 专属 CLI |
| `nerdctl` | `default` | ✅ `--namespace` 支持 | Docker 替代品 |
| `docker` | `moby`(内部) | ❌ 不适配 CRI | 非标准 runtime 已淘汰 |
---
如果你希望统一所有容器资源到 `k8s.io` namespace,也可以将 Docker 的镜像导入进去:
```bash
ctr -n moby images export all-docker.tar $(ctr -n moby images ls -q)
ctr -n k8s.io images import all-docker.tar
```
是否需要我为你写一个“跨 namespace 镜像同步”的自动脚本?
`/etc/crictl.yaml` 是 `crictl` 工具的配置文件。`crictl` 是一个用于与容器运行时(如 containerd 或 CRI-O)交互的命令行工具。它支持管理容器、镜像、网络和卷等资源。`crictl.yaml` 文件允许用户自定义与容器运行时的交互配置,如容器运行时的 API 地址、调试级别等。
### `/etc/crictl.yaml` 配置文件结构
`crictl.yaml` 文件通常包括以下几部分内容:
* **runtime-endpoint**:指定容器运行时的 API 地址。通常是 `containerd` 或 `cri-o` 的 gRPC 服务地址。
* **image-endpoint**:指定镜像服务的 gRPC 地址。
* **timeout**:容器操作的超时时间。
* **debug**:开启或关闭调试模式。
### 配置示例
```yaml
# CRI runtime endpoint
runtime-endpoint: unix:///var/run/containerd/containerd.sock
# Image service endpoint
image-endpoint: unix:///var/run/containerd/containerd.sock
# Timeout for containerd client operations
timeout: 10s
# Enable debugging mode
debug: true
```
### 配置项详解
1. **runtime-endpoint**
* **类型**:字符串(URL)
* **说明**:指定容器运行时(如 `containerd` 或 `cri-o`)的 API 地址。通常使用 Unix 套接字(如 `/var/run/containerd/containerd.sock`)或 TCP 地址(如 `tcp://localhost:1234`)。
示例:
* `unix:///var/run/containerd/containerd.sock`:指向 containerd 的 Unix 套接字。
* `tcp://localhost:1234`:指向一个 TCP 地址,通常在 Kubernetes 集群中的远程节点上。
2. **image-endpoint**
* **类型**:字符串(URL)
* **说明**:指定镜像服务的 API 地址。通常与 `runtime-endpoint` 地址相同。用于管理容器镜像的操作(拉取、推送、列出等)。
3. **timeout**
* **类型**:字符串(时间格式)
* **说明**:指定与容器运行时通信时的超时时间。默认值为 `10s`,表示 10 秒。
4. **debug**
* **类型**:布尔值
* **说明**:开启或关闭调试模式。如果设置为 `true`,则在运行时会输出更多调试信息,通常用于故障排查。
### 配置文件示例:适用于 `containerd` 和 `cri-o`
1. **适用于 `containerd` 的配置:**
```yaml
runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
timeout: 15s
debug: false
```
2. **适用于 `cri-o` 的配置:**
```yaml
runtime-endpoint: unix:///var/run/crio/crio.sock
image-endpoint: unix:///var/run/crio/crio.sock
timeout: 20s
debug: true
```
### 使用 `crictl` 工具时检查配置
`crictl` 工具会根据 `/etc/crictl.yaml` 配置文件中的设置与容器运行时(如 `containerd` 或 `cri-o`)进行通信。确保在配置文件中设置正确的运行时和镜像端点,以便 `crictl` 能够正常与容器运行时交互。
```bash
# 验证容器运行时状态
crictl info
```
### 常见问题排查
1. **容器运行时 API 地址错误**:如果 `runtime-endpoint` 配置不正确,`crictl` 会无法连接到容器运行时,常见错误信息如“连接失败”。
2. **镜像拉取失败**:如果 `image-endpoint` 配置有误,`crictl` 在尝试拉取镜像时会失败,检查镜像端点是否正确。
3. **超时问题**:如果容器运行时响应较慢,尝试增加 `timeout` 配置项的值,尤其是在高负载或远程节点上运行时。
### 小结
* `/etc/crictl.yaml` 是 `crictl` 配置文件,用于配置与容器运行时(如 `containerd` 或 `cri-o`)的连接信息。
* 关键配置项包括 `runtime-endpoint`、`image-endpoint`、`timeout` 和 `debug`。
* 确保配置文件中的 API 地址与运行时的实际地址一致,以便 `crictl` 能够正常工作。
如果你有多个容器运行时,确保每个运行时的配置都正确,并通过 `crictl` 验证连接和操作是否正常。
在 `containerd` 中,裸容器(bare container)通常指的是没有依赖于 Kubernetes 等容器编排工具的容器实例。它们是直接通过 `containerd` 管理的容器。`containerd` 提供了一个轻量级的容器管理功能,能够启动、停止、调度和管理容器,主要用于支持容器化的应用和服务。
### containerd 管理裸容器的基本步骤
#### 1. 安装 `containerd`
首先,需要确保已安装 `containerd`。在多数 Linux 发行版上,你可以通过以下命令安装:
```bash
# 对于基于 Debian 或 Ubuntu 的系统
sudo apt-get install containerd
# 对于基于 RHEL 或 CentOS 的系统
sudo yum install containerd
```
安装完成后,可以通过 `systemctl` 启动并启用 `containerd` 服务:
```bash
# 启动 containerd
sudo systemctl start containerd
# 设置 containerd 在开机时自动启动
sudo systemctl enable containerd
```
#### 2. 配置 `containerd`
`containerd` 的配置文件通常位于 `/etc/containerd/config.toml`。你可以通过编辑此配置文件来进行定制设置(如存储路径、日志配置、网络插件等)。
```bash
# 编辑配置文件
sudo nano /etc/containerd/config.toml
```
例如,配置存储路径,镜像存储等内容,之后保存文件并重启 `containerd`:
```bash
# 重启 containerd 服务
sudo systemctl restart containerd
```
#### 3. 启动和管理裸容器
容器的生命周期管理可以使用 `ctr`,`containerd` 附带的命令行工具。`ctr` 提供了一个轻量级的接口来直接管理容器和镜像。
##### a. 拉取镜像
首先需要从镜像仓库拉取镜像。`containerd` 可以使用 Docker 镜像仓库,也可以配置使用私有仓库。
```bash
# 拉取 Docker Hub 上的镜像
sudo ctr images pull docker.io/library/alpine:latest
```
##### b. 创建和启动裸容器
使用 `ctr` 工具启动裸容器。创建容器时需要指定镜像和容器配置。以下是一个基本的创建容器的命令:
```bash
# 创建并启动一个容器
sudo ctr container create \
--name my_container \
--runtime io.containerd.runc.v1 \
docker.io/library/alpine:latest \
/bin/sh
```
* `--name` 指定容器的名称。
* `--runtime` 指定容器使用的运行时,默认使用 `runc`。
* `docker.io/library/alpine:latest` 是镜像的完整名称。
* `/bin/sh` 是容器启动时执行的命令。
##### c. 启动容器
通过 `ctr` 启动已创建的容器:
```bash
# 启动容器
sudo ctr task start my_container
```
此时,容器将启动并运行。
##### d. 进入容器
如果你希望进入容器并进行交互,可以使用 `ctr` 提供的附加功能:
```bash
# 进入容器并获得 shell
sudo ctr task exec --stdin --tty my_container /bin/sh
```
##### e. 停止容器
当容器运行完成后,可以使用以下命令停止容器:
```bash
# 停止容器
sudo ctr task kill my_container
```
##### f. 删除容器
删除容器时,可以通过以下命令删除已停止的容器:
```bash
# 删除容器
sudo ctr container delete my_container
```
### 4. 使用 containerd 监控容器状态
你可以使用 `ctr` 查询当前运行的容器和任务(即容器的进程)。例如,查看容器状态:
```bash
# 查看所有正在运行的容器
sudo ctr task list
# 查看所有镜像
sudo ctr images list
```
### 5. 进一步配置和优化裸容器
裸容器的使用非常简单,但在生产环境中可能需要进行更细致的配置和优化,以下是一些常见的配置项:
* **日志管理**:可以配置容器的日志输出,确保容器的输出被正确捕获。
* **资源限制**:可以配置 CPU、内存、网络等资源限制,确保容器不会过度占用主机资源。
* **网络配置**:如果容器需要访问外部网络,确保配置正确的网络插件(例如 CNI)。
### 总结
通过 `containerd` 管理裸容器主要包括以下几个步骤:
1. 安装和配置 `containerd`。
2. 使用 `ctr` 工具拉取镜像、创建容器、启动容器、进入容器、停止容器。
3. 使用 `ctr` 查看容器和镜像的状态。
`containerd` 作为一个容器运行时,提供了非常灵活的工具来管理裸容器。如果你不依赖 Kubernetes 等编排工具,`containerd` 提供的直接控制和高效性是非常合适的选择。
### 检查 `containerd` 配置文件是否正确
`containerd` 使用的配置文件通常是 `/etc/containerd/config.toml`,用于配置诸如镜像拉取、运行时选项、存储驱动等。为了确保 `containerd` 配置文件正确且有效,可以通过以下几种方法进行检查:
### 1. **检查配置文件的语法是否正确**
`containerd` 配置文件是 TOML 格式,您可以通过检查文件的语法是否符合 TOML 格式,来确认配置文件没有明显的语法错误。如果配置文件存在语法错误,`containerd` 启动时会输出相关错误。
```bash
# 查看 containerd 启动日志,检查是否有配置相关的错误信息
journalctl -u containerd -f
```
如果日志中有关于 `config.toml` 文件的错误,通常会显示某些字段无效或语法错误的详细信息。
### 2. **检查配置文件的有效性**
您可以手动检查配置文件中的关键部分,确认各个配置项是否按照需要设置。例如:
* **私有仓库配置**:
```toml
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."myprivateregistry.com"]
endpoint = ["https://myprivateregistry.com"]
```
* **认证信息**:
```toml
[plugins."io.containerd.grpc.v1.cri".registry.configs."myprivateregistry.com".auth]
username = "my-username"
password = "my-password"
```
* **存储驱动配置**:
```toml
[plugins."io.containerd.snapshotter.v1.overlayfs"]
root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs"
```
* **运行时配置**:
```toml
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
runtime = "io.containerd.runc.v1"
```
确保各个配置项的值符合您的需求,并且没有遗漏或错误的配置。
### 3. **使用 `containerd` 命令行工具检查**
`containerd` 提供了多种命令行工具来检查当前的配置及其状态。
* **检查 `containerd` 的版本:**
```bash
containerd --version
```
* **查看正在运行的容器任务:**
```bash
ctr task list
```
该命令列出当前所有容器任务。您可以通过这个命令检查是否正在运行您的容器。
* **检查当前镜像:**
```bash
ctr image list
```
该命令会列出当前加载的所有镜像,您可以检查是否有来自私有仓库的镜像。
* **拉取镜像:**
```bash
ctr image pull myprivateregistry.com/my-image:latest
```
如果您配置了私有仓库,尝试拉取一个镜像,检查是否能成功拉取。如果拉取失败,查看日志中的详细错误信息。
### 4. **使用 `systemctl` 检查 `containerd` 服务状态**
您可以通过 `systemctl` 查看 `containerd` 服务的状态,以确保服务正常运行。
```bash
sudo systemctl status containerd
```
如果服务没有启动,或者有异常,使用以下命令重新启动:
```bash
sudo systemctl restart containerd
```
### 5. **查看 `containerd` 的日志**
`containerd` 启动时会输出日志,您可以查看其日志文件,以便找到可能存在的配置错误。
```bash
journalctl -u containerd -f
```
如果配置文件中的某些部分存在问题,`containerd` 会在启动时输出错误日志,帮助您定位问题所在。
---
### `citr` 配置文件作用
`citr` 是 `containerd` 的一个重要部分,用于配置和管理容器镜像仓库。`citr` 不是 `containerd` 的默认配置文件,而是一个类似于镜像的元数据存储工具。其作用如下:
* **管理镜像元数据**:`citr` 用于管理与容器镜像相关的元数据和其他配置信息。
* **镜像配置**:它可以帮助在镜像拉取、推送、存储等操作时管理镜像的元数据、认证信息等。
不过,`citr` 并不是所有 `containerd` 安装中都需要的文件,它通常是作为容器镜像存储和拉取的一部分出现,主要应用于一些特殊场景或工具集成。
### 总结
1. **检查 `containerd` 配置文件是否正确**:可以通过查看日志、检查配置项是否存在错误,或者使用命令行工具验证配置是否生效。
2. **`citr` 配置文件**:`citr` 主要用于镜像的元数据存储,它并非 `containerd` 的标准配置文件。如果您使用 `containerd` 进行容器管理,`citr` 主要用于与容器镜像相关的配置,但并不是必需的配置项。