本文 首发于 🌱 煎茶转载 请注明 来源

适用场景:K3s 默认不附带 nerdctl,但其内置的 containerd 与 nerdctl 完全兼容。本教程讲解如何在 K3s 节点上以最小代价安装 nerdctl,并正确指向 K3s 的 containerd socket,无需重复安装 containerd 或 CNI。

一、背景与原理

工具说明
ctrcontainerd 内置调试工具,与 Docker CLI 不兼容,功能有限
crictlCRI 调试工具,K3s 自带,面向 Kubernetes 运维
nerdctlDocker 兼容 CLI,支持 run/build/compose推荐日常使用

K3s 的 containerd socket 路径为 /run/k3s/containerd/containerd.sock,而非标准路径 /run/containerd/containerd.sock。只需在配置中指向该路径,nerdctl 即可接管 K3s 容器管理。

K3s 已自带 CNI 插件(flannel/calico 等),查看 K3s 节点已有的 Pod 和镜像无需额外 CNI。若需要 nerdctl run 启动独立容器并连接网络,则需要补充安装 CNI 插件(见第四节)。

二、安装 nerdctl(仅二进制)

K3s 节点已有 containerd,只需下载 nerdctl 的精简包(不含 containerd/CNI,体积小)。

2.1 下载二进制

# 查询最新版本(或手动前往 https://github.com/containerd/nerdctl/releases 查看)
NERDCTL_VERSION=$(curl -s https://api.github.com/repos/containerd/nerdctl/releases/latest \
  | grep tag_name | cut -d '"' -f4 | tr -d 'v')

echo "最新版本: ${NERDCTL_VERSION}"

# 下载精简包(仅 nerdctl 二进制)
curl -LO "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz"

ARM64 节点(如树莓派、ARM 服务器)将 amd64 替换为 arm64

curl -LO "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-arm64.tar.gz"

2.2 解压并安装

# 解压到 /usr/local/bin
sudo tar Cxzvf /usr/local/bin nerdctl-${NERDCTL_VERSION}-linux-amd64.tar.gz nerdctl

# 验证安装
nerdctl --version

三、配置 nerdctl 指向 K3s containerd

nerdctl 默认连接 /run/containerd/containerd.sock,在 K3s 节点上需要修改为 K3s 专用路径。

3.1 创建配置文件

sudo mkdir -p /etc/nerdctl

sudo tee /etc/nerdctl/nerdctl.toml > /dev/null <<EOF
# nerdctl 全局配置,适配 K3s 节点
address        = "/run/k3s/containerd/containerd.sock"
namespace      = "k8s.io"
EOF

说明

  • address:K3s containerd 的 socket 路径
  • namespace:K3s 所有容器和镜像均存储在 k8s.io 命名空间下

3.2 验证连接

# 列出 K3s 命名空间下的所有容器(等同于 kubectl get pods 的容器视角)
sudo nerdctl ps -a

# 列出镜像
sudo nerdctl images

如果能看到 K3s 系统 Pod(如 coredns、traefik 等),说明配置成功。

四、安装 CNI 插件(按需,用于 nerdctl run)

如果只需要查看 K3s 已有容器和镜像,可跳过此节。

只有当你需要用 nerdctl run 启动独立容器(即非 Kubernetes 管理的容器)时,才需要 CNI 插件。K3s 自带的 CNI 仅供 Kubernetes 使用,nerdctl 的独立容器网络需要单独配置。

4.1 下载官方 CNI 插件

CNI_VERSION=$(curl -s https://api.github.com/repos/containernetworking/plugins/releases/latest \
  | grep tag_name | cut -d '"' -f4)

curl -LO "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz"

# 安装到标准路径
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-${CNI_VERSION}.tgz

4.2 创建默认网络配置

sudo mkdir -p /etc/cni/net.d

sudo tee /etc/cni/net.d/10-nerdctl-bridge.conflist > /dev/null <<EOF
{
  "cniVersion": "1.0.0",
  "name": "nerdctl-bridge",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "nerdctl0",
      "isGateway": true,
      "ipMasq": true,
      "ipam": {
        "type": "host-local",
        "ranges": [
          [{"subnet": "10.88.0.0/16"}]
        ],
        "routes": [{"dst": "0.0.0.0/0"}]
      }
    },
    {
      "type": "portmap",
      "capabilities": {"portMappings": true}
    },
    {
      "type": "firewall"
    }
  ]
}
EOF

注意:此桥接网络(10.88.0.0/16)仅供 nerdctl 管理的独立容器使用,不会影响 K3s 自身网络。

4.3 验证独立容器运行

# 注意:启动独立容器时需使用默认命名空间(不加 --namespace k8s.io)
# 或在 nerdctl.toml 中临时切换,推荐直接在命令行覆盖:
sudo nerdctl --namespace default run -d --name test-nginx -p 8080:80 nginx:alpine

# 确认运行
sudo nerdctl --namespace default ps
curl http://localhost:8080

五、常用命令速查

所有命令均需 sudo(或将当前用户加入 containerd 相关权限组)。

查看 K3s 容器和镜像

# 列出所有容器(K3s 管理)
sudo nerdctl ps -a

# 列出镜像
sudo nerdctl images

# 查看容器日志
sudo nerdctl logs <容器ID或名称>

# 进入容器终端
sudo nerdctl exec -it <容器ID或名称> sh

镜像管理

# 拉取镜像(拉取后可直接被 K3s Pod 使用)
sudo nerdctl pull nginx:alpine

# 查看镜像详情
sudo nerdctl inspect <镜像ID>

# 删除镜像
sudo nerdctl rmi <镜像ID>

# 从 tar 包导入镜像(常用于离线环境)
sudo nerdctl load < image.tar

# 导出镜像为 tar 包
sudo nerdctl save nginx:alpine -o nginx.tar

构建镜像(需安装 BuildKit,见第六节)

sudo nerdctl build -t myapp:v1 /path/to/dockerfile-dir

配合 kubectl 使用本地镜像

# 构建并打 tag 到 k8s.io 命名空间
sudo nerdctl --namespace k8s.io build -t myapp:local .

# 然后在 Pod spec 中指定 imagePullPolicy: Never 即可使用本地镜像
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp
    image: myapp:local
    imagePullPolicy: Never
EOF

六、可选:安装 BuildKit(支持 nerdctl build)

nerdctl 构建镜像需要 BuildKit daemon。

BUILDKIT_VERSION=$(curl -s https://api.github.com/repos/moby/buildkit/releases/latest \
  | grep tag_name | cut -d '"' -f4)

curl -LO "https://github.com/moby/buildkit/releases/download/${BUILDKIT_VERSION}/buildkit-${BUILDKIT_VERSION}.linux-amd64.tar.gz"

sudo tar Cxzvf /usr/local buildkit-${BUILDKIT_VERSION}.linux-amd64.tar.gz

# 创建 systemd 服务
sudo tee /etc/systemd/system/buildkit.service > /dev/null <<EOF
[Unit]
Description=BuildKit
After=network.target containerd.service

[Service]
ExecStart=/usr/local/bin/buildkitd \
  --addr unix:///run/buildkit/buildkitd.sock \
  --containerd-worker-addr /run/k3s/containerd/containerd.sock
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now buildkit

Refs