Appearance
crictl 调试工具使用指南

概述
在 Kubernetes 节点上排查 Pod 启动失败、镜像拉取异常、容器状态问题时,选择一个趁手的调试工具至关重要。
crictl 是 Kubernetes 官方推荐的 CRI(Container Runtime Interface)兼容容器运行时调试工具,专为 Kubernetes 节点运维场景设计。本文档记录了我从 ctr 的困惑到使用 crictl 高效排查问题的完整实践,希望对你有帮助。
一、为什么用 crictl?
1.1 我的困境
在调试容器镜像来源时,我本想用 ctr 查看镜像元数据,却遇到了这些问题:
bash
# 想用 ctr 查看镜像列表,语法报错
ctr -n=k8s.io image ls docker.m.daocloud.io/library/nginx:1.31.3
# 报错: filters: parse error: expected an operator
# 想用 ctr 查看镜像详情,"info" 子命令根本不存在
ctr -n=k8s.io image info docker.m.daocloud.io/library/nginx:1.31.3
# 报错: No help topic for 'info'问题总结:
ctr是 containerd 的原生调试工具,非常底层,参数设计晦涩- 它的设计目标是调试 containerd 本身,而不是方便 Kubernetes 用户
- 命令语法反直觉,学习曲线陡峭
1.2 crictl 的定位
crictl 是 Kubernetes 官方 为 CRI 兼容的容器运行时(containerd、CRI-O 等)提供的统一调试工具。
| 特性 | 说明 |
|---|---|
| 统一接口 | 无论底层是 containerd 还是 CRI-O,命令完全一致 |
| Kubernetes 语义 | 命令结构(pods、ps、inspecti)与 kubectl 风格一致 |
| 专为排障设计 | 直接支持查看 Pod Sandbox、容器日志、镜像元数据等 K8s 运维场景 |
一句话定位:crictl 是 Kubernetes 节点排障的“瑞士军刀”。
二、crictl vs 其他工具
| 工具 | 定位 | 适用场景 |
|---|---|---|
crictl | Kubernetes 节点调试工具(CRI 标准接口) | K8s 节点排障首选,查看 Pod/容器/镜像状态 |
ctr | containerd 原生客户端(非常底层) | 调试 containerd 本身的问题,普通用户慎用 |
docker | Docker 引擎客户端(不兼容 CRI) | 开发环境构建镜像,K8s 节点上已不推荐使用 |
三、安装与配置
3.1 安装
CentOS 7 / RHEL 系列:
bash
# 添加 Kubernetes 官方源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
# 安装 crictl
yum install -y cri-toolsUbuntu / Debian 系列:
bash
# 下载二进制(版本号请替换为最新)
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.36.0/crictl-v1.36.0-linux-amd64.tar.gz
tar -zxvf crictl-v1.36.0-linux-amd64.tar.gz -C /usr/local/bin/
chmod +x /usr/local/bin/crictl验证安装:
bash
crictl version3.2 配置运行时端点
crictl 需要知道容器运行时的 socket 地址才能通信。
方式一:配置文件(推荐)
bash
cat > /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
pull-image-on-create: false
EOF方式二:环境变量
bash
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
export IMAGE_SERVICE_ENDPOINT=unix:///run/containerd/containerd.sock3.3 验证配置
bash
crictl info预期输出:JSON 格式的运行时信息,没有报错即为成功。
点击查看示例运行时信息
json
{
"cniconfig": {
"Networks": [
{
"Config": {
"CNIVersion": "0.3.1",
"Name": "cni-loopback",
"Plugins": [
{
"Network": {
"dns": {},
"ipam": {},
"type": "loopback"
},
"Source": "{\"type\":\"loopback\"}"
}
],
"Source": "{\n\"cniVersion\": \"0.3.1\",\n\"name\": \"cni-loopback\",\n\"plugins\": [{\n \"type\": \"loopback\"\n}]\n}"
},
"IFName": "lo"
},
{
"Config": {
"CNIVersion": "0.3.1",
"Name": "k8s-pod-network",
"Plugins": [
{
"Network": {
"dns": {},
"ipam": {
"type": "calico-ipam"
},
"type": "calico"
},
"Source": "{\"datastore_type\":\"kubernetes\",\"ipam\":{\"type\":\"calico-ipam\"},\"kubernetes\":{\"kubeconfig\":\"/etc/cni/net.d/calico-kubeconfig\"},\"log_file_path\":\"/var/log/calico/cni/cni.log\",\"log_level\":\"info\",\"mtu\":0,\"nodename\":\"k8s-master-239\",\"policy\":{\"type\":\"k8s\"},\"type\":\"calico\"}"
},
{
"Network": {
"capabilities": {
"portMappings": true
},
"dns": {},
"ipam": {},
"type": "portmap"
},
"Source": "{\"capabilities\":{\"portMappings\":true},\"snat\":true,\"type\":\"portmap\"}"
},
{
"Network": {
"capabilities": {
"bandwidth": true
},
"dns": {},
"ipam": {},
"type": "bandwidth"
},
"Source": "{\"capabilities\":{\"bandwidth\":true},\"type\":\"bandwidth\"}"
}
],
"Source": "{\n \"name\": \"k8s-pod-network\",\n \"cniVersion\": \"0.3.1\",\n \"plugins\": [\n {\n \"type\": \"calico\",\n \"log_level\": \"info\",\n \"log_file_path\": \"/var/log/calico/cni/cni.log\",\n \"datastore_type\": \"kubernetes\",\n \"nodename\": \"k8s-master-239\",\n \"mtu\": 0,\n \"ipam\": {\n \"type\": \"calico-ipam\"\n },\n \"policy\": {\n \"type\": \"k8s\"\n },\n \"kubernetes\": {\n \"kubeconfig\": \"/etc/cni/net.d/calico-kubeconfig\"\n }\n },\n {\n \"type\": \"portmap\",\n \"snat\": true,\n \"capabilities\": {\"portMappings\": true}\n },\n {\n \"type\": \"bandwidth\",\n \"capabilities\": {\"bandwidth\": true}\n }\n ]\n}"
},
"IFName": "eth0"
}
],
"PluginConfDir": "/etc/cni/net.d",
"PluginDirs": [
"/opt/cni/bin"
],
"PluginMaxConfNum": 1,
"Prefix": "eth"
},
"config": {
"cni": {
"binDir": "/opt/cni/bin",
"confDir": "/etc/cni/net.d",
"confTemplate": "",
"ipPref": "",
"maxConfNum": 1
},
"containerd": {
"defaultRuntime": {
"ContainerAnnotations": null,
"PodAnnotations": null,
"baseRuntimeSpec": "",
"cniConfDir": "",
"cniMaxConfNum": 0,
"options": null,
"privileged_without_host_devices": false,
"runtimeEngine": "",
"runtimePath": "",
"runtimeRoot": "",
"runtimeType": ""
},
"defaultRuntimeName": "runc",
"disableSnapshotAnnotations": true,
"discardUnpackedLayers": false,
"ignoreRdtNotEnabledErrors": false,
"noPivot": false,
"runtimes": {
"runc": {
"ContainerAnnotations": null,
"PodAnnotations": null,
"baseRuntimeSpec": "",
"cniConfDir": "",
"cniMaxConfNum": 0,
"options": {
"SystemdCgroup": true
},
"privileged_without_host_devices": false,
"runtimeEngine": "",
"runtimePath": "",
"runtimeRoot": "",
"runtimeType": "io.containerd.runc.v2"
}
},
"snapshotter": "overlayfs",
"untrustedWorkloadRuntime": {
"ContainerAnnotations": null,
"PodAnnotations": null,
"baseRuntimeSpec": "",
"cniConfDir": "",
"cniMaxConfNum": 0,
"options": null,
"privileged_without_host_devices": false,
"runtimeEngine": "",
"runtimePath": "",
"runtimeRoot": "",
"runtimeType": ""
}
},
"containerdEndpoint": "/run/containerd/containerd.sock",
"containerdRootDir": "/var/lib/containerd",
"device_ownership_from_security_context": false,
"disableApparmor": true,
"disableCgroup": false,
"disableHugetlbController": true,
"disableProcMount": false,
"disableTCPService": true,
"enableSelinux": false,
"enableTLSStreaming": false,
"enableUnprivilegedICMP": false,
"enableUnprivilegedPorts": false,
"ignoreImageDefinedVolumes": false,
"imageDecryption": {
"keyModel": "node"
},
"maxConcurrentDownloads": 3,
"maxContainerLogSize": 16384,
"netnsMountsUnderStateDir": false,
"registry": {
"auths": null,
"configPath": "",
"configs": null,
"headers": null,
"mirrors": {
"docker.io": {
"endpoint": [
"https://registry-1.docker.io"
]
}
}
},
"restrictOOMScoreAdj": false,
"rootDir": "/var/lib/containerd/io.containerd.grpc.v1.cri",
"sandboxImage": "registry.cn-beijing.aliyuncs.com/kubesphereio/pause:3.7",
"selinuxCategoryRange": 1024,
"stateDir": "/run/containerd/io.containerd.grpc.v1.cri",
"statsCollectPeriod": 10,
"streamIdleTimeout": "4h0m0s",
"streamServerAddress": "127.0.0.1",
"streamServerPort": "0",
"systemdCgroup": false,
"tolerateMissingHugetlbController": true,
"unsetSeccompProfile": "",
"x509KeyPairStreaming": {
"tlsCertFile": "",
"tlsKeyFile": ""
}
},
"golang": "go1.17.9",
"lastCNILoadStatus": "OK",
"lastCNILoadStatus.default": "OK",
"status": {
"conditions": [
{
"message": "",
"reason": "",
"status": true,
"type": "RuntimeReady"
},
{
"message": "",
"reason": "",
"status": true,
"type": "NetworkReady"
}
]
}
}四、核心命令实战
4.1 场景一:查看 Pod 和容器
查看所有 Pod Sandbox:
bash
crictl pods查看所有容器(包括已停止的):
bash
crictl ps -a查看正在运行的容器:
bash
crictl ps按命名空间过滤:
bash
crictl pods --namespace <namespace>💡 技巧:
crictl的命令风格和kubectl很像,上手很快。
4.2 场景二:排查镜像问题(核心实战)
查看所有已下载的镜像:
bash
crictl images查看镜像详细信息(JSON 格式):
bash
crictl inspecti <镜像名称:标签>实战:查看 nginx 镜像的详细信息
假设集群节点上已拉取 nginx:1.31.3 镜像,以下命令可以查看其元数据:
bash
crictl inspecti docker.m.daocloud.io/library/nginx:1.31.3观察输出的 JSON 信息,特别是 info.imageSpec.config.Labels 部分:
json
"Labels": {
"maintainer": "NGINX Docker Maintainers <[email protected]>"
}结论:maintainer 标签明确指出了镜像的维护者是 NGINX 官方团队。这就是 crictl 的价值所在——它能直接告诉我们镜像的“出身”,在需要确认镜像来源时特别管用。
4.3 场景三:调试容器
第一步:列出 Pod 中的所有容器
首先,需要找到目标 Pod 的 Sandbox ID。
bash
# 查看所有 Pod Sandbox
crictl pods --namespace <namespace>然后,列出该 Pod 下所有容器的 ID。
bash
# 使用上一步获取的 Pod Sandbox ID
crictl ps -a --pod <PodSandbox-ID>输出中的 CONTAINER 列就是容器 ID(缩写),例如 86a10f7dda626。
第二步:查看业务容器的日志
使用上一步获取的容器 ID 查看其标准输出日志:
bash
crictl logs <容器ID>4.4 场景四:清理空间
删除镜像:
bash
crictl rmi <image-id>删除容器:
bash
crictl rm <container-id>清理所有已停止的容器:
bash
crictl rm $(crictl ps -a -q --state=Exited)五、常用命令速查表
| 命令 | 用途 |
|---|---|
crictl pods | 列出所有 Pod Sandbox |
crictl ps -a | 列出所有容器(含已停止) |
crictl images | 列出所有镜像 |
crictl inspecti <镜像> | 查看镜像 JSON 元数据 |
crictl inspect <容器> | 查看容器 JSON 元数据 |
crictl logs <容器> | 查看容器日志 |
crictl exec -it <容器> sh | 进入容器执行命令 |
crictl rmi <镜像> | 删除镜像 |
crictl rm <容器> | 删除容器 |
crictl info | 查看运行时信息和配置 |
crictl version | 查看客户端和运行时版本 |
六、总结
| 关键结论 | 说明 |
|---|---|
crictl 是 K8s 节点排障的最佳工具 | 命令语义清晰,与 kubectl 风格一致 |
| 专门处理 CRI 兼容的运行时 | containerd、CRI-O 统一接口 |
inspecti 命令最实用 | 可以直接查看镜像的 Labels,验证来源 |
不要用 ctr 做日常排障 | 它太底层,只适合调试 containerd 本身 |
通过 crictl,我可以高效地验证镜像来源、排查容器问题。希望这篇文档也能帮你更高效地排查 Kubernetes 节点问题。
