nerdctl
nerdctl 是 containerd 的命令行客户端工具,它提供了与 Docker CLI 兼容的用户体验。
什么是 nerdctl
- containerd 的 CLI 工具:nerdctl 全称是 “non-enterprise control”(或 containerd ctl)
- Docker 兼容:命令语法与 docker 命令高度兼容,降低学习成本
- CNCF 项目:由 containerd 社区开发和维护
- 功能丰富:支持 Docker 不支持的一些高级功能
主要特性
1. Docker 兼容性
nerdctl 的命令与 docker 几乎完全兼容,可以无缝切换:
# Docker 命令
docker run -d -p 80:80 nginx
docker ps
docker images
docker build -t myapp .
# nerdctl 命令(完全相同)
nerdctl run -d -p 80:80 nginx
nerdctl ps
nerdctl images
nerdctl build -t myapp .
2. 增强功能
nerdctl 支持一些 Docker 不支持的高级特性:
- 懒加载镜像(Lazy Pulling):使用 stargz/eStargz 格式,加快镜像拉取
- 镜像加密:支持加密容器镜像
- 镜像签名:支持 cosign 镜像签名验证
- P2P 镜像分发:支持 IPFS 分布式镜像存储
- Rootless 模式:无需 root 权限运行容器
- 多种运行时:可配置使用不同的 OCI 运行时(runc、crun、gVisor 等)
3. Kubernetes 一致性
- 与 Kubernetes 使用相同的 containerd 运行时
- 本地开发环境与生产环境(K8s)保持一致
- 便于调试 Kubernetes 相关问题
与 Docker 的对比
| 特性 | Docker | nerdctl |
|---|---|---|
| 底层运行时 | dockerd + containerd | containerd 直接 |
| 守护进程 | 需要 dockerd | 只需 containerd |
| 命令兼容性 | - | 兼容 docker 命令 |
| 镜像格式 | OCI | OCI + 增强格式(stargz) |
| 镜像加密 | ❌ | ✅ |
| 懒加载 | ❌ | ✅ |
| Rootless | 部分支持 | 完整支持 |
| K8s 一致性 | 不同运行时 | 相同运行时 |
| 资源占用 | 较高 | 较低 |
为什么使用 nerdctl?
- 学习成本低:如果熟悉 docker 命令,可以直接使用 nerdctl
- 性能更好:直接使用 containerd,减少中间层
- 与 K8s 一致:本地环境和 Kubernetes 使用相同的容器运行时
- 更轻量:不需要额外的 dockerd 守护进程
- 功能更强:支持镜像加密、懒加载等高级特性
安装 nerdctl
Arch Linux 安装
pacman -S nerdctl
Ubuntu/Debian 手动安装
# download latest version of nerdctl from https://github.com/containerd/nerdctl/releases
nerdctl_version="2.1.3"
curl -LO "https://github.com/containerd/nerdctl/releases/download/v${nerdctl_version}/nerdctl-${nerdctl_version}-linux-amd64.tar.gz"
sudo tar Cxzvf /usr/bin/ nerdctl-${nerdctl_version}-linux-amd64.tar.gz
# 验证安装
nerdctl --version
sudo nerdctl info
sudo nerdctl pull hello-world
sudo nerdctl run hello-world
# 使用 nerdctl 运行容器测试网络, 测试 CNI plugin
nerdctl run -it --rm busybox
# 在容器中执行
ping -c 2 baidu.com
配置 Rootless 模式(免 sudo)
Rootless 模式允许普通用户无需 sudo 权限直接使用 nerdctl,这是推荐的使用方式。
什么是 Rootless 模式
- 无需 root 权限:普通用户可以直接运行容器
- 提高安全性:容器运行在用户命名空间中,即使容器被攻破也不会影响系统
- 用户隔离:每个用户有独立的容器环境
- 完整功能:支持几乎所有 nerdctl 功能(网络、卷、构建等)
前置要求
1. 检查系统支持
# 检查内核是否支持用户命名空间
cat /proc/sys/kernel/unprivileged_userns_clone
# 应该返回 1
# 如果返回 0,需要启用(需要 root 权限)
sudo sysctl kernel.unprivileged_userns_clone=1
# 永久启用(重启后保持)
echo 'kernel.unprivileged_userns_clone=1' | sudo tee /etc/sysctl.d/99-rootless.conf
2. 检查必要的工具
# 检查是否已安装 rootless 工具
which containerd-rootless-setuptool.sh
which rootlesskit
which slirp4netns
# Arch Linux 安装依赖(如果缺失)
sudo pacman -S rootlesskit slirp4netns fuse-overlayfs
sudo apt update && sudo apt install -y rootlesskit slirp4netns uidmap
安装配置步骤
步骤 1:运行安装脚本
# 以普通用户身份运行(不要用 sudo)
containerd-rootless-setuptool.sh install
脚本会自动完成:
- 创建
~/.config/containerd/config.toml配置文件 - 创建
~/.config/systemd/user/containerd.servicesystemd 用户服务 - 配置网络(使用 slirp4netns)
- 配置存储驱动
步骤 2:配置环境变量
安装完成后,脚本会提示添加环境变量。将以下内容添加到 ~/.bashrc 或 ~/.zshrc:
# nerdctl rootless 配置
export PATH="$HOME/bin:$PATH"
export CONTAINERD_ADDRESS="$XDG_RUNTIME_DIR/containerd/containerd.sock"
export CONTAINERD_NAMESPACE="default"
然后重新加载配置:
# bash 用户
source ~/.bashrc
# zsh 用户
source ~/.zshrc
步骤 3:启动 containerd 服务
# 启动 containerd 用户服务
systemctl --user start containerd.service
# 设置开机自启动
systemctl --user enable containerd.service
# 检查服务状态
systemctl --user status containerd.service
# 启用 lingering(即使退出登录也保持服务运行)
sudo loginctl enable-linger $USER
步骤 4:验证配置
# 测试 nerdctl(注意:不需要 sudo)
nerdctl version
nerdctl info
# 运行测试容器
nerdctl run --rm hello-world
# 运行一个简单的 nginx 容器
nerdctl run -d --name nginx -p 8080:80 nginx
nerdctl ps
# 测试访问
curl http://localhost:8080
# 清理测试容器
nerdctl stop nginx
nerdctl rm nginx
Rootless 模式常用命令
# 所有 nerdctl 命令都不需要 sudo
nerdctl pull nginx
nerdctl images
nerdctl run -d --name web -p 8080:80 nginx
nerdctl ps
nerdctl logs web
nerdctl exec -it web bash
nerdctl stop web
nerdctl rm web
# 网络管理
nerdctl network create mynet
nerdctl network ls
# 卷管理
nerdctl volume create myvol
nerdctl volume ls
# 构建镜像
nerdctl build -t myapp:latest .
管理 Rootless Containerd 服务
# 查看服务状态
systemctl --user status containerd
# 启动/停止/重启服务
systemctl --user start containerd
systemctl --user stop containerd
systemctl --user restart containerd
# 查看服务日志
journalctl --user -u containerd -f
# 检查 containerd 信息
nerdctl info | grep -i rootless
卸载 Rootless 模式
如果需要卸载 rootless 配置:
# 停止服务
systemctl --user stop containerd
systemctl --user disable containerd
# 运行卸载脚本
containerd-rootless-setuptool.sh uninstall
# 删除配置文件(可选)
rm -rf ~/.config/containerd
rm -rf ~/.local/share/containerd
Rootless 模式的限制
虽然 rootless 模式功能完整,但有一些限制需要注意:
-
端口限制:
- 不能直接绑定 1024 以下的特权端口(如 80、443)
- 解决方案:使用高端口映射(如 8080:80),然后用反向代理
-
性能影响:
- 网络性能可能略低于 root 模式(因为使用 slirp4netns)
- 文件系统性能略有影响(使用 fuse-overlayfs)
-
cgroup 限制:
- 需要 cgroup v2 支持
- 资源限制功能可能受限
-
某些高级功能:
- 不支持修改 iptables
- 不支持某些特权操作
-
VPN 兼容性问题:
- slirp4netns 可能与某些企业 VPN(如思科 AnyConnect)冲突
- 可能导致容器无法访问网络
- 解决方案见下文"VPN 环境下的网络配置"
VPN 环境下的网络配置
如果你的环境中有企业 VPN(如思科 AnyConnect、GlobalProtect 等),可能会遇到 rootless 容器网络不通的问题。
问题表现
# 容器无法访问外网
nerdctl run --rm busybox ping -c 3 8.8.8.8
# 100% packet loss
网络方案对比
Rootless containerd 支持多种网络驱动:
| 网络方案 | 说明 | VPN 兼容性 | 性能 | 配置难度 |
|---|---|---|---|---|
| slirp4netns | 用户态网络栈(默认) | ⚠️ 可能冲突 | 较低 | 简单 |
| vpnkit | Docker Desktop 使用的方案 | ✅ 较好 | 中等 | 中等 |
| lxc-user-nic | 需要系统配置 | ⚠️ 可能冲突 | 较好 | 复杂 |
| host 模式 | 使用宿主机网络 | ✅ 最好 | 最佳 | 简单 |
解决方案 1:切换到 vpnkit(推荐)
# 1. 安装 vpnkit
# Ubuntu/Debian
sudo apt install vpnkit
# 或从源码编译
# git clone https://github.com/moby/vpnkit.git
# 2. 配置 containerd rootless 使用 vpnkit
mkdir -p ~/.config/systemd/user/containerd.service.d
cat > ~/.config/systemd/user/containerd.service.d/vpn-compat.conf << 'EOF'
[Service]
# 使用 vpnkit 替代 slirp4netns
Environment=CONTAINERD_ROOTLESS_ROOTLESSKIT_NET=vpnkit
EOF
# 3. 重启 containerd 服务
systemctl --user daemon-reload
systemctl --user restart containerd.service
# 4. 验证
nerdctl run --rm busybox ping -c 3 8.8.8.8
解决方案 2:使用 host 网络模式
如果切换网络驱动仍有问题,可以使用 host 网络模式(与宿主机共享网络命名空间):
# 运行容器时指定 --network host
nerdctl run -d --name nginx --network host nginx
# 注意:host 模式下不需要端口映射
# 容器直接使用宿主机的端口
host 模式的特点:
- ✅ 完全绕过 VPN 限制
- ✅ 网络性能最佳
- ❌ 失去容器网络隔离
- ❌ 端口冲突风险
解决方案 3:回退到 root 模式
如果 rootless 模式的网络问题无法解决,可以回退使用 root 模式(sudo nerdctl):
# root 模式默认使用 CNI bridge,通常与 VPN 兼容性更好
sudo nerdctl run -d --name nginx -p 8080:80 nginx
# 或使用 host 网络
sudo nerdctl run -d --name nginx --network host nginx
网络诊断步骤
# 1. 测试宿主机网络
curl -I https://www.google.com
# 2. 测试 rootless 容器网络(默认网络)
nerdctl run --rm busybox ping -c 3 8.8.8.8
# 3. 测试 rootless 容器网络(host 模式)
nerdctl run --rm --network host busybox ping -c 3 8.8.8.8
# 4. 测试 root 模式容器网络
sudo nerdctl run --rm busybox ping -c 3 8.8.8.8
# 5. 检查当前网络配置
journalctl --user -u containerd.service | grep -i "net="
推荐方案总结
针对不同场景的推荐:
-
开发环境 + VPN:
- 优先使用 host 网络模式
- 简单直接,兼容性最好
-
需要网络隔离 + VPN:
- 尝试切换到 vpnkit
- 如果不行,使用 root 模式 + bridge
-
CI/CD 环境 + VPN:
- 使用 root 模式
- 配置 sudo 免密(仅 CI 用户)
-
多用户生产环境:
- 评估是否必须使用 VPN
- 或配置 VPN 路由表,排除容器网络段
Rootless vs Root 模式对比
| 特性 | Root 模式 (sudo) | Rootless 模式 |
|---|---|---|
| 安全性 | 低(容器以 root 运行) | 高(用户命名空间隔离) |
| 权限要求 | 需要 sudo | 无需 sudo |
| 端口绑定 | 支持所有端口 | 不支持 <1024 端口 |
| 性能 | 最佳 | 略有损失 |
| 配置复杂度 | 简单 | 需要额外配置 |
| 推荐场景 | 开发/测试环境 | 生产/多用户环境 |
故障排查
问题 1:命令找不到
# 检查环境变量
echo $PATH
echo $CONTAINERD_ADDRESS
# 重新加载配置
source ~/.bashrc # 或 ~/.zshrc
问题 2:服务启动失败
# 查看详细日志
journalctl --user -u containerd -n 50
# 检查配置文件
cat ~/.config/containerd/config.toml
# 手动启动测试
containerd-rootless.sh
问题 3:网络不通
# 检查 slirp4netns 是否安装
which slirp4netns
# 测试容器网络
nerdctl run --rm busybox ping -c 2 8.8.8.8
问题 4:存储空间问题
# 检查存储位置
nerdctl info | grep -i root
# Rootless 存储位置通常在
~/.local/share/containerd
# 清理未使用的镜像和容器
nerdctl system prune -a
容器开机自启动配置
为已存在的容器设置开机自启动
使用 nerdctl update 命令修改容器的重启策略:
# 设置容器开机自启动(除非手动停止)
sudo nerdctl update --restart unless-stopped <容器名称或ID>
# 示例
sudo nerdctl update --restart unless-stopped kafka
# 验证重启策略是否设置成功
sudo nerdctl inspect kafka | grep -A 5 restart.policy
创建容器时设置自启动
在运行容器时直接指定重启策略:
sudo nerdctl run -d \
--name my-container \
--restart unless-stopped \
<镜像名称>
重启策略说明
| 策略 | 说明 |
|---|---|
no |
默认值,容器退出时不自动重启 |
always |
容器退出时总是重启,包括手动停止后系统重启也会启动 |
unless-stopped |
容器退出时总是重启,但如果是手动停止的,系统重启后不会启动(推荐) |
on-failure[:max-retries] |
仅在容器非正常退出时重启,可选指定最大重试次数 |
常用命令
# 查看容器的重启策略
sudo nerdctl inspect <容器名称> | grep -i restart
# 取消容器的自启动
sudo nerdctl update --restart no <容器名称>
# 查看所有容器及其重启策略
sudo nerdctl ps -a --format "{{.Names}}\t{{.Status}}\t{{.Labels}}"
注意事项
unless-stopped是最常用的策略,适合大多数服务容器- 设置重启策略后,需要确保 containerd 服务本身已设置为开机启动
- 可以通过
sudo systemctl enable containerd确保 containerd 服务开机启动
常用命令
运行容器
# 运行容器
sudo nerdctl run -d --name nginx -p 80:80 nginx
# 查看容器
sudo nerdctl ps
# 查看镜像
sudo nerdctl images
# 构建镜像
sudo nerdctl build -t myapp:v1.0 .
# 推送镜像
sudo nerdctl push myapp:v1.0
# 查看日志
sudo nerdctl logs nginx
# 进入容器
sudo nerdctl exec -it nginx bash
# 导出镜像
sudo nerdctl save -o foo.tar foo:latest
网络管理
# 网络管理
sudo nerdctl network create mynet
sudo nerdctl network ls
nerdctl run --rm --network=kong-net busybox ping postgresql
数据卷管理
# 数据卷管理
sudo nerdctl volume create myvol
sudo nerdctl volume ls
高级用法
# 使用私有仓库
sudo nerdctl --insecure-registry push 127.0.0.1:5000/image_0:1.4
# Rootless 模式(无需 sudo)
nerdctl run -d nginx
总结
nerdctl 是 containerd 的命令行工具,提供与 Docker 兼容的命令接口,让用户可以:
- 像使用 docker 一样使用 containerd
- 获得更好的性能和更轻量的资源占用
- 享受与 Kubernetes 一致的运行时环境
- 使用镜像加密、懒加载等高级特性
如果您在使用 containerd 作为容器运行时,nerdctl 是最佳的命令行工具选择。