Skip to content

crictl 调试工具使用指南

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 的定位

crictlKubernetes 官方 为 CRI 兼容的容器运行时(containerd、CRI-O 等)提供的统一调试工具

特性说明
统一接口无论底层是 containerd 还是 CRI-O,命令完全一致
Kubernetes 语义命令结构(podspsinspecti)与 kubectl 风格一致
专为排障设计直接支持查看 Pod Sandbox、容器日志、镜像元数据等 K8s 运维场景

一句话定位crictlKubernetes 节点排障的“瑞士军刀”

二、crictl vs 其他工具

工具定位适用场景
crictlKubernetes 节点调试工具(CRI 标准接口)K8s 节点排障首选,查看 Pod/容器/镜像状态
ctrcontainerd 原生客户端(非常底层)调试 containerd 本身的问题,普通用户慎用
dockerDocker 引擎客户端(不兼容 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-tools

Ubuntu / 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 version

3.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.sock

3.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 节点问题。

最后更新2026/07/31 07:51
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal