先执行 nerdctl info,确认 nerdctl 已经连上 containerd;如果这一步失败,先处理 PATH、socket、权限和服务状态,不要急着修改 Compose YAML。连通后再用下面这条最短链路验证镜像、容器和端口:
command -v nerdctl
nerdctl version
nerdctl info
nerdctl pull nginx:alpine
nerdctl run -d --name web -p 8080:80 nginx:alpine
nerdctl ps
nerdctl logs web
curl -I http://127.0.0.1:8080
root 模式下,后续命令应始终使用同一权限,例如全部通过 sudo nerdctl 执行;rootless 模式则应始终使用安装 rootless containerd 的普通用户,不要在同一排错链路里混用 sudo nerdctl 和普通用户 nerdctl。这两种模式默认连接的 socket、用户服务和网络环境不同,混用时很容易出现“命令能执行,但连接的不是同一个 containerd”。
本文从 CSDN《【云原生】nerdctl 部署及使用指南》提到的部署与使用问题切入,但不沿用其中的历史版本号作为当前版本。正文统一使用 <VERSION>、<ARCH> 等占位符;唯一原样保留的终端告警来自参考资料,其余故障均通过可复查的检查命令定位。
先分清安装包、权限和 containerd 连接
nerdctl 本身是 containerd 的客户端,主要适用于 Linux。开始安装前,先确定采用 root 还是 rootless 模式:root 模式连接系统级 containerd 服务,rootless 模式连接普通用户自己的 containerd 服务。两者的安装脚本、服务启动方式和 socket 地址不同,装好后再切换模式,通常意味着要重新检查环境变量和权限。
官方发布包含 minimal 和 full 两种形态。minimal 主要提供 nerdctl 二进制及 rootless 辅助脚本;full 还包含 containerd、CNI、runc、BuildKit 等组件。全新主机没有 containerd 时可以选择 full,主机已经运行 containerd 时则应选择 minimal,避免覆盖现有二进制、服务配置或数据目录。
全新主机可以按当前 Release 页面提供的文件名安装 full 包:
sudo tar -xf "nerdctl-full-<VERSION>-linux-<ARCH>.tar.gz" -C /usr/local/
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
这里的 enable 会让 containerd 随系统启动,--now 则会立即启动服务。如果解压后提示找不到服务单元,不要反复执行 enable,应先检查发行包实际包含的 systemd unit,再按对应版本的 containerd 安装文档补齐:
sudo systemctl cat containerd
sudo systemctl status containerd --no-pager
已有 containerd 时只安装 nerdctl:
tar -xf "nerdctl-<VERSION>-linux-<ARCH>.tar.gz"
sudo install -m 0755 nerdctl /usr/local/bin/nerdctl
参考资料中出现过 v1.2.1、v1.5.0 等历史版本,但它们只能说明当时的安装方式,不能据此判断当前最新版。下载前应从官方 Release 页面确认文件名、版本号、CPU 架构以及校验信息。
rootless 模式允许普通用户运行容器,安装脚本和 socket 地址需要按当期 rootless 文档配置。常见流程如下:
containerd-rootless-setuptool.sh install
systemctl --user status containerd --no-pager
systemctl --user start containerd
安装脚本如果已经启动并配置了用户服务,不需要重复执行安装。安装后重新打开登录 shell,再检查当前用户服务与 CONTAINERD_ADDRESS:
systemctl --user status containerd --no-pager
journalctl --user -u containerd -n 200 --no-pager
printf 'CONTAINERD_ADDRESS=%s\n' "${CONTAINERD_ADDRESS:-<unset>}"
rootless 环境不要再默认连接 /run/containerd/containerd.sock。如果环境变量没有进入当前 shell,应按官方 rootless 配置重新设置,而不是手工改成系统级 socket。
安装完成后,分别检查二进制是否进入 PATH、nerdctl 客户端能否运行,以及 containerd daemon 是否可以访问。
command -v nerdctl
nerdctl version
nerdctl info
如果提示 nerdctl: command not found,先检查文件和 PATH,不要因此下载第二份不同版本的二进制:
command -v nerdctl
ls -l /usr/local/bin/nerdctl
printf '%s\n' "$PATH"
如果二进制存在,但 nerdctl info 报连接失败,root 模式检查系统服务和默认 socket:
sudo systemctl status containerd --no-pager
sudo journalctl -u containerd -n 200 --no-pager
sudo ls -l /run/containerd/containerd.sock
sudo nerdctl info
rootless 模式则检查用户服务及当前环境变量:
systemctl --user status containerd --no-pager
journalctl --user -u containerd -n 200 --no-pager
printf 'CONTAINERD_ADDRESS=%s\n' "${CONTAINERD_ADDRESS:-<unset>}"
需要显式指定地址时,可以把全局参数放在子命令前:
nerdctl --address /run/containerd/containerd.sock info
nerdctl --address "$CONTAINERD_ADDRESS" info
第二条只适用于已经正确导出 CONTAINERD_ADDRESS 的 rootless 环境。
权限问题可以先用下面两条命令对照:
nerdctl info
sudo nerdctl info
如果只有 sudo nerdctl info 成功,说明当前用户没有访问目标 socket 的权限。此后 root 模式的拉取、运行、Compose 和网络命令都应保持相同权限,不要只给某一条命令加 sudo。如果 nerdctl info 已经成功,但创建容器时提示运行时不可用,还要确认 runc 是否存在及其版本是否兼容:
command -v runc
nerdctl info
minimal 包并不等于完整运行时环境。已有 containerd 的主机还可能缺少 runc、CNI 或 BuildKit,这些组件缺失通常属于主机 provisioning 问题,而不是 Compose 文件问题。
跑起第一个容器,再单独处理构建链路
第一个容器不需要复杂参数,显式设置容器名、端口和重启策略,后续定位会更直接:
nerdctl pull nginx:alpine
nerdctl run -d \
--name web \
-p 8080:80 \
--restart=always \
nginx:alpine
这种后台运行、命名容器和发布端口的方式与常见的 Docker CLI 操作接近,也便于按常见习惯检查运行状态、日志和端口。如果提示容器名已经存在,换一个名称,或者先检查并清理旧容器,不要重复启动同名实例。
容器级验证按下面顺序执行:
nerdctl ps
nerdctl ps -a
nerdctl logs web
nerdctl exec -it web sh
nerdctl inspect web
nerdctl port web
nerdctl ps 中看不到容器时,先用 ps -a 确认它是不是已经退出。容器提前退出时,先看日志和 inspect 中的退出状态、启动命令,再检查 containerd 日志。进程自身启动失败、配置错误或端口冲突,都可能让容器在 daemon 已经正常工作时立即退出,不能直接归因于 containerd 服务异常。
端口不可达也要分层检查。先确认发布关系,再看宿主监听地址和端口占用:
nerdctl port web
ss -lntp
curl -I http://127.0.0.1:8080
如果 nerdctl port 没有显示预期映射,应检查 run 时的 -p 参数。如果映射存在但 ss 中没有对应监听,继续检查容器状态;如果容器已经退出,端口自然不会监听。如果本机 curl 成功、远程访问失败,则重点检查绑定地址和宿主防火墙,而不是重新构建镜像。
端口映射会真实占用宿主的 8080 端口。启动前可以用 ss -lntp 确认它是否已被其他进程使用。--restart=always 也会改变容器的恢复行为:daemon 或主机重启后,nerdctl 会按重启策略尝试恢复容器,因此它适合长期服务,但不适合临时排障容器。
镜像构建是另一条链路。nerdctl build 并不只是读取 Dockerfile,它依赖 buildctl 客户端以及可用的 buildkitd worker;手工安装 BuildKit 时,只放一个 buildctl 二进制并不够,服务端和 worker 同样需要配置。full 安装包已经包含 BuildKit 相关组件。
执行构建:
nerdctl build -t app:test .
参考资料中的真实告警是:
WARN[0000] unable to determine buildctl version: exec: "buildctl": executable file not found in $PATH
这条告警表示构建客户端无法从 PATH 找到 buildctl。它不是业务代码报错,也不能单凭这条告警断定 Dockerfile 有语法问题;应继续看构建命令的最终退出状态和后续错误。如果后面明确因找不到 buildctl 而失败,再处理 PATH 或安装问题。
可以依次检查客户端、服务端和 worker:
command -v buildctl
buildctl --version
systemctl status buildkitd --no-pager
buildctl debug workers
systemctl status buildkitd 只适用于由 systemd 管理的 buildkitd;如果是手工启动或放在容器中运行,需要按该部署方式检查进程、socket 和 worker 地址。若 command -v buildctl 有结果,但 worker 列表为空,问题更可能在 buildkitd 服务端或其 worker 配置,而不是 PATH。
排障结束后,如果不再需要测试容器,再显式停止并删除:
nerdctl stop web
nerdctl rm web
这不会自动处理所有镜像、卷或网络。尤其是数据卷,应在确认数据不再需要后单独删除,不要把容器清理和存储清理混成一个动作。
Compose 与网络必须使用同一个 containerd 上下文
nerdctl 从 0.8 起兼容 Docker Compose 语法,但不包含 Swarm,其 Compose 实现遵循 Compose Specification,而不是把 Docker Swarm 编排能力搬到 containerd 上。因此,应准备兼容的 Compose v2;它不提供 docker stack deploy 一类功能。
先确认 Compose 命令和 nerdctl Compose 子命令都可用:
command -v docker-compose
docker-compose version
nerdctl compose version
这里的 docker-compose 指的是当前发行方式提供的独立 Compose v2 可执行文件。如果机器使用的是 Docker CLI 插件,也可以检查:
docker compose version
不同 nerdctl 版本查找 Compose 二进制或插件的方式可能不同,最终应按对应版本的官方 Compose 文档确认,不能只看到某个 docker-compose 二进制就认为组合一定兼容。
一个最小 Compose 文件如下:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
networks:
- app
api:
image: your-api-image:tag
networks:
- app
networks:
app:
name: app-net
your-api-image:tag 必须替换成实际存在且当前节点可以拉取的镜像。验证配置时先不要直接启动:
nerdctl compose config
配置解析通过后再启动:
nerdctl compose up -d
nerdctl compose ps
nerdctl compose logs -f
nerdctl compose exec web sh
停止并清理项目资源:
nerdctl compose down
down 会处理该 Compose 项目管理的容器和项目网络,但默认不会删除命名卷。卷需要单独确认后删除:
nerdctl volume ls
nerdctl volume rm <VOLUME_NAME>
<VOLUME_NAME> 必须来自实际列表,不要把占位符直接执行。
Compose 报错可以按层次处理。找不到 Compose 时检查可执行文件和 PATH;配置解析失败时先运行 nerdctl compose config;连接 containerd 失败时检查当前用户、CONTAINERD_ADDRESS 以及 root/rootless 上下文;构建失败时回到 BuildKit 链路检查 buildctl 和 buildkitd,不要把 buildctl 缺失归因于 YAML。
网络问题还要区分默认 bridge、自定义 bridge 和 host 三种模式。普通单容器可以使用默认 bridge;需要稳定服务名解析的多容器环境,应使用同一个自定义 bridge 网络。Compose 自己会创建和管理项目网络,本文示例中的 app-net 已经被 Compose 声明,因此不要在执行 compose up 前再手动创建同名网络。
直接使用 nerdctl 启动容器时,自定义网络需要显式创建:
nerdctl network create app-net
nerdctl network ls
nerdctl network inspect app-net
然后把需要互通的容器加入同一个网络:
nerdctl run -d \
--name peer \
--network app-net \
nginx:alpine
容器加入同一个网络,只是满足了互通的前提;还要确认服务使用的是预期名称。Compose 中应优先使用 web、api 这样的服务名,而不是依赖 Compose 自动生成的容器名称。服务启动后检查:
nerdctl compose ps
nerdctl inspect "$(nerdctl compose ps -q web)"
nerdctl inspect "$(nerdctl compose ps -q api)"
nerdctl network inspect app-net
如果 api 无法通过服务名访问,依次确认两点:第一,两个服务是否都加入了同一个项目网络;第二,访问使用的是不是 Compose 服务名。只检查容器是否处于 running 状态,并不能证明 DNS 和网络附件已经正确。
host 网络只适合支持该模式的 Linux 环境,而且容器直接使用宿主的网络空间。此时不要再依赖 -p 做端口发布:
nerdctl run -d \
--name web-host \
--network host \
nginx:alpine
host 模式下,容器内服务监听的端口就是宿主端口,因此也更容易与宿主现有服务发生端口冲突。rootless 环境是否支持 host 网络,以及支持到什么程度,需要按当期官方文档和当前内核环境验证。
端口绑定还要区分“容器端口”和“宿主监听地址”。未指定宿主 IP 时,发布端口通常会绑定到所有可用宿主地址,但最终应以本机实际输出为准:
nerdctl port web
ss -lntp
如果只需要本机访问,可以明确绑定回环地址:
nerdctl run -d \
--name web-loopback \
-p 127.0.0.1:8080:80 \
nginx:alpine
这种配置下,远程主机无法直接访问 8080,即使容器和端口映射本身都正常。若 web-loopback 已经存在,应换名或先清理旧容器。
自定义 bridge 网络依赖 CNI 组件。full 包包含 CNI 相关文件;如果使用 minimal 包,或者主机已有 containerd,需要另外确认 CNI 插件文件、containerd 使用的插件目录以及网络配置是否一致。如果 nerdctl network create 失败,应检查:
nerdctl info
nerdctl network ls
sudo systemctl cat containerd
sudo journalctl -u containerd -n 200 --no-pager
这类失败通常属于 CNI 插件缺失、插件目录不一致或网络配置没有初始化。不要反复创建随机网络名来规避这个错误,因为后续 Compose 仍可能因为找不到预期网络而失败。
rootless 下的端口发布、host 网络和 CNI 驱动支持情况可能随 nerdctl、BuildKit、内核及 cgroup 配置变化。rootless 排查应继续使用普通用户上下文和 journalctl --user,不要为了看日志临时切到 root socket 后继续执行其他命令。
排障时按下面的顺序检查:
nerdctl info
nerdctl network ls
nerdctl network inspect app-net
nerdctl compose ps
nerdctl port web
ss -lntp
先确认连接的是哪一个 containerd,再确认网络是否存在、容器是否加入网络,最后检查端口发布和宿主防火墙。服务名解析、容器互通和外部端口可达是三个不同问题,混在一起排查时很容易把 DNS、路由和端口绑定重复检查很多遍。
nerdctl 是 containerd 的客户端,不是 containerd 的替代品;minimal 安装仍然要求主机具备兼容的 containerd、运行时和网络组件。本文涉及的 Compose 只覆盖单机 Compose Specification 场景,不包含 Swarm,也不能据此推断具备 Kubernetes 编排能力。
尚未统一覆盖的部分包括 rootless 的 host 网络与端口细节、不同内核和 cgroup 配置、CNI 插件版本、存储驱动,以及 macOS、Windows 等非原生 Linux 环境。发布或迁移前,应以官方 Release、rootless 和 Compose 文档复核 <VERSION>、<ARCH>、Compose v2 的安装方式以及具体参数;资料中的 v1.2.1、v1.5.0 等历史版本不应再被当作当前最新版。












暂无评论内容