使用 `docker diff` 分析容器运行时产生的写操作
解读
在国内一线互联网公司的 SRE/DevOps 面试中,这道题常被用来区分“只会敲命令”与“能定位线上问题”的候选人。
面试官真正想听的是:
- 你能否快速判断容器是否出现“写层暴涨”(导致宿主机 inode 或磁盘耗尽,引发 Kubernetes Eviction);
- 你能否把 diff 输出与业务日志、metrics 对应,定位到具体进程或目录;
- 你能否给出闭环方案(临时止血 + 长期根治),而不是只贴命令。
知识点
- 写时复制(COW)机制:容器启动后,所有对 UnionFS 的写操作都落到最上层的可写层(RW Layer),
docker diff就是 diff 这个 RW 层与镜像只读层的快照。 - 三类符号:
A(Add)、D(Delete)、C(Change)——国内面试必须逐条解释,不能漏。 - 性能陷阱:
docker diff会加锁遍历整个 RW Layer,在 10GB+ 写层的大容器上执行可能触发秒级卡顿,线上慎用。 - 与 docker inspect 联动:通过
GraphDriver.Data.WorkDir找到实际挂载点,再用du -h --max-depth=1精确量化,避免 diff 文本统计误差。 - 国内镜像源加速场景:很多公司把
/var/lib/docker挂在机械盘,diff 结果若出现/root/.cache/pip、/tmp/chromium等路径,基本可判定未配置.dockerignore或缓存卷,导致 CI 重复下载。 - 安全合规:若 diff 出现
/etc/shadow、~/.ssh/authorized_keys被改动,立即触发安全工单,按等保 2.0 要求 24h 内溯源。
答案
步骤一:现场止血
# 1. 先通过容器名拿到 ID,避免 diff 误敲
CID=$(docker ps -af name=order-service -q --no-trunc | head -1)
# 2. 低峰期执行 diff,结果重定向到文件,防止终端刷屏
docker diff $CID > /tmp/diff_$(date +%F_%H-%M).log
步骤二:快速量化
# 3. 只统计大于 10M 的写操作,过滤噪音
awk '$1 ~ /^A|^C/ {print $2}' /tmp/diff_*.log | xargs -I{} docker exec $CID du -b {} 2>/dev/null | awk '$1>10485760{print}'
# 典型输出:
# 157286400 /tmp/heapdump.hprof
# 367001600 /opt/tomcat/logs/catalina.out
结论:heapdump 与 catalina.out 暴涨,判定为 OOM 自动 dump + 日志未切割。
步骤三:闭环治理
- 临时:
docker exec $CID sh -c '> /opt/tomcat/logs/catalina.out'清空日志,禁止 rm 文件,否则 fd 未释放仍占空间。 - 长期:
- 在 Dockerfile 里加
RUN ln -sf /dev/stdout /opt/tomcat/logs/catalina.out,把日志重定向到标准输出,宿主机统一用 journald 或 Loki 收集; - 添加
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump,并把/dump挂载为 emptyDir 卷,限制 1Gi,超过即触发告警; - 在 CI 中引入
dive镜像扫描,拒绝包含大于 50MB 单文件层的镜像推入 Harbor。
- 在 Dockerfile 里加
步骤四:复盘报告
把 diff 日志、量化结果、治理 PR 链接统一归档到 Confluence,@相关负责人 24h 内评审,符合阿里“1-5-10”应急规范(1min 发现、5min 定位、10min 恢复)。
拓展思考
- Kubernetes 场景:
docker diff只适用于 dockershim 节点;若集群已切到 Containerd,需用ctr container diff或crictl diff,命令输出格式不同,面试时要主动提及,避免“只会 Docker 那一套”的印象。 - 只读根文件系统:把
securityContext.readOnlyRootFilesystem: true作为默认 Policy,所有写路径必须显式声明 volumeMounts,上线前用kubectl diff对比 Helm chart,杜绝 diff 出现 A 类路径。 - eBPF 深度追踪:用
bcc/tools/filelife或kubectl trace抓短生命周期文件,比 diff 更精准;可进一步定位到 Java GC 线程、Node.js 临时 buffer,实现代码级优化。 - 成本治理:把 diff 结果接入内部 FinOps 平台,按“每 1GB 写层 ≈ 0.3 元/月”折算,超预算自动创建 Jira 工单,推动业务方改造,实现技术价值向成本价值转化。