【k8s】crictl inspect vs docker inspect vs nerdctl inspect 查看挂载点
背景:
docker inspect:对接 Docker daemon(dockerd),读取 Docker 自己的元数据存储crictl inspect:对接 CRI runtime(containerd/cri-o),是 K8s 标准 CRI 接口工具,直接调用容器运行时,不走 dockerd
在 K8s 环境,现在绝大多数节点底层是
containerd;即使节点装了 docker,k8s 也不经过 dockerd,而是直接调用 containerd。
1、核心本质区别
- docker inspect:Docker 专属 API,输出 Docker 完整元数据(镜像、容器、HostConfig、GraphDriver、docker 网络、docker volume 等 docker 内部概念)。
- crictl inspect:CRI 标准接口输出,面向 K8s 的 Pod/Container 模型,输出 CRI 定义的结构体,没有 docker 那套 GraphDriver、HostConfig、Mounts 完整语义,字段集合不一样。
注意:
crictl inspect有两个对象:
crictl inspect <container-id>→ 查看容器crictl inspectp <pod-id>→ 查看 pod sandbox(沙箱,pause 容器)
2、输出结构对比
1)docker inspect(你前面看过的 JSON)
输出完整 docker 模型,包含大类:
Id、Created、State(PID、OOMKilled、ExitCode)Config:镜像原始配置 Env/Cmd/Entrypoint/VolumesHostConfig:docker run 参数,资源限制、端口映射、重启策略GraphDriver:overlay2 LowerDir / UpperDir / MergedDir / WorkDir(宿主机磁盘路径)Mounts:完整挂载列表 Source/Destination/ModeNetworkSettings:docker 网络、IP、PortBindings、SandboxKeyRootFS镜像分层 diffID
✅ 特点:Docker 的全部内部细节都能看到,docker 的概念全部保留。
2)crictl inspect <containerID>(CRI 输出)
CRI 把对象分成两层:PodSandbox (pause 沙箱) + 业务 Container
json
{
"status": {
"id": "容器ID",
"pid": 1234,
"state": { },
"createdAt": "...",
"sandboxId": "pause容器ID", // 归属哪个pod沙箱
},
"info": {
"config": { /* CRI容器配置:image、env、command、mounts、resource限制 */ },
"image": { /* 镜像信息 */ },
"sandboxConfig": { /* pod沙箱配置:pod namespace、hostname、dns、pod annotation */ }
}
}
crictl 缺失 docker 独有的字段(重点)
- ❌ 没有
HostConfig:CRI 模型不使用 docker HostConfig 这套结构;资源限制直接放在config.resources - ❌ 没有
GraphDriver:看不到 LowerDir、UpperDir、MergedDir 宿主机 overlay 磁盘路径!(这是最常踩坑点) - ❌ 没有 docker 风格
Mounts完整结构体;挂载在config.mounts,只有简单source,destination,readonly,缺少 docker 的 volume 驱动信息 - ❌ 没有 NetworkSettings:网络信息放在
inspectp(pod sandbox)里面,业务容器本身不带网络信息;网络属于 Pod 沙箱 pause 容器。
📌K8s 中网络、hostname、dns、pid/uts/net 命名空间全部归属于PodSandbox(pause),业务容器共享沙箱的命名空间。 所以看 Pod IP、网络 namespace 要执行:
crictl inspectp <pod-sandbox-id>,而不是看业务 container。
3、关键概念映射表(containerd 环境)
表格
| 功能 | docker inspect | crictl inspect / inspectp |
|---|---|---|
| 进程状态、PID、退出码 | State | status |
| 容器启动命令、环境变量 | Config.{Env,Cmd,Entrypoint} | info.config.{env,command} |
| CPU / 内存资源限制 | HostConfig | info.config.resources |
| overlay2 磁盘路径 (Lower/UpperDir) | GraphDriver.Data | ❌获取不到,CRI 接口不暴露 |
| 镜像分层 RootFS | RootFS | ❌CRI 不返回 RootFS diffID |
| 挂载卷信息 | Mounts[] | info.config.mounts[],信息精简 |
| Pod / 容器 IP、网络命名空间 | NetworkSettings | 在 crictl inspectp sandboxID(pause 沙箱),业务容器无网络 |
| 主机名、DNS 配置 | 容器内 Config | 归属 PodSandbox inspectp |
| 对象模型 | 单个容器(容器自带网络) | PodSandbox (pause) + 多个业务容器分离模型 |
重要:
crictl拿不到 overlay2 的 UpperDir 等底层存储路径;如果需要看 containerd 底层磁盘路径,需要去读 containerd 内部元数据,CRI 接口不给。- K8s 节点底层是 containerd,即使节点装了 docker,
docker ps / docker inspect看不到 k8s 的 pod 容器;dockerd 和 containerd 是两套完全独立容器存储。
4、实操示例(K8s containerd 节点)
bash
# crictl 列出pod沙箱
crictl pods
# 查看pod沙箱(pause):Pod IP、dns、网络命名空间,用 inspectp
crictl inspectp <pod-sandbox-id>
# 查看pod里面的业务容器:进程、env、command、挂载、资源
crictl inspect <container-id>
# crictl 看不到overlay UpperDir!!如果想找,只能查containerd内部数据库
什么时候用哪个
- docker inspect
- 纯 Docker 环境(非 K8s),排查 docker 容器、看 overlay 磁盘路径、docker volume、docker 端口映射。
- crictl inspect / inspectp
- K8s 节点,底层 containerd/cri‑o;排查 Pod 沙箱状态、容器进程、env、命令、挂载、资源;
- 缺点:拿不到底层存储驱动路径 RootFS/GraphDriver。
补充: containerd 环境,如果非要拿到容器 overlay2 UpperDir/LowerDir,CRI 工具 crictl 做不到;需要调用 containerd 原生工具
ctr:bash
ctr c info <container-id>
ctr是 containerd 原生 CLI,不是 CRI 标准工具,可以拿到存储层路径。
5、容易混淆区分小结
澄清误区:
ctr c info并不会直接输出 UpperDir/LowerDir 绝对路径字符串;只是可以拿到snapshotKey,再手动拼接宿主机快照目录,间接找到 overlay 文件。之前表格标记✅容易产生误导。
表格
| 工具 | 后端接口 | 适用对象 | 是否可直接输出 Overlay UpperDir/LowerDir 绝对路径 | 是否返回 snapshotKey | 是否可查看 OCI mounts (容器挂载) |
|---|---|---|---|---|---|
docker inspect | dockerd (Docker 专属 API) | docker run 创建的容器 | ✅ 直接在 GraphDriver.Data 返回完整路径 | ❌ docker 体系无 snapshotKey 概念 | ✅ Mounts字段 |
crictl inspect | CRI‑API (高层接口) | K8s Pod 容器 (containerd/cri‑o) | ❌ | ❌ CRI 接口屏蔽快照底层信息 | ✅ info.runtimeSpec.mounts |
nerdctl inspect(默认 dockercompat 模式) | containerd Native API | K8s‑CRI/nerdctl 创建容器 | ❌ | ❌ | ❌ K8s 容器 Mounts=null |
nerdctl container inspect --mode=native | containerd Native API | K8s‑CRI/nerdctl 创建容器 | ❌ | ❌ nerdctl 不输出 snapshotKey | ✅ spec.mounts |
ctr c info | containerd Native API(底层) | K8s‑CRI/ctr 创建容器 | ❌(间接获取,需 snapshotKey 拼接路径) | ✅ 返回 .snapshotKey | ✅ spec.mounts |
关键文字说明(消除误导)
-
docker inspect dockerd 直接把 overlay 的
UpperDir/LowerDir完整绝对路径放在 JSON 返回值,开箱即用,不需要二次查找。 -
ctr c info 返回字段:
.snapshotKey(快照唯一标识) 不会返回/var/lib/containerd/.../upper这种完整路径。 你需要手动拼接快照根目录:
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/${snapshotKey}/
进入该目录后,才可见 upper、lower、work、merged。
所以:
ctr→ 有钥匙 (snapshotKey),但不给你开好门(完整路径);docker inspect 直接把门打开给你完整路径。
一句话记忆:
docker inspect= docker 私有完整元数据;crictl inspect= K8s CRI 标准化精简输出,Pod 和容器分离,屏蔽底层存储细节;ctr= containerd 底层原生工具,可以看到更多底层细节。
6、nerdctl 命令
ctr ≠ nerdctl,二者是两套完全独立的客户端,只不过都可以调用 containerd‑native API。
containerd容器+nerdctl工具 需要注意model参数:
nerdctl -n k8s.io inspect xxx 看不到挂载点
nerdctl -n k8s.io inspect --mode=native xxx 可以看到挂载点
7、nerdctl 看不到 snapshotKey,ctr c info 可以,那么是工具的问题,还是 后面容器的问题?
完全是工具 (nerdctl) 本身的输出裁剪问题,和容器、containerd 后台没有任何关系。 你这个 K8s 容器本身确实存在 snapshotKey;containerd‑Native API 也返回了 snapshotKey;只是 nerdctl 主动选择不打印这个字段。
- ❌ 不是容器问题:Kubelet/CRI 创建出来的 Pod 容器,100% 都会分配 snapshotKey;
- ❌ 不是权限、命名空间 (k8s.io) 问题:
nerdctl和ctr使用完全一样的/run/containerd/containerd.sock访问后端。
只是由于某些字段是OCI标准字段和非标准字段,导致工具实现不同,containerd 原生 API,获取容器信息返回两块独立数据:
- OCI Runtime Spec(
.spec)- 进程、环境变量、mounts、namespace、cgroup
- 属于 OCI 标准,
--mode=native会完整输出这块内容
- containerd 扩展字段(非 OCI 标准)
.snapshotKey、.task、.shim、创建快照信息- 属于 containerd 内部私有元数据,不属于 OCI 规范
nerdctl container inspect --mode=native的设计定位:只输出 OCI‑spec 那一块标准内容,不输出 containerd 私有扩展字段GitHub。ctr c info是 containerd 底层调试工具,把 OCI spec + containerd 私有元数据全部打印出来,所以你能看到.snapshotKey
更多推荐
所有评论(0)