使用 `docker diff` 分析容器运行时产生的写操作

解读

在国内一线互联网公司的 SRE/DevOps 面试中,这道题常被用来区分“只会敲命令”与“能定位线上问题”的候选人
面试官真正想听的是:

  1. 你能否快速判断容器是否出现“写层暴涨”(导致宿主机 inode 或磁盘耗尽,引发 Kubernetes Eviction);
  2. 你能否把 diff 输出与业务日志、metrics 对应,定位到具体进程或目录;
  3. 你能否给出闭环方案(临时止血 + 长期根治),而不是只贴命令。

知识点

  1. 写时复制(COW)机制:容器启动后,所有对 UnionFS 的写操作都落到最上层的可写层(RW Layer)docker diff 就是 diff 这个 RW 层与镜像只读层的快照。
  2. 三类符号
    A(Add)、D(Delete)、C(Change)——国内面试必须逐条解释,不能漏
  3. 性能陷阱docker diff加锁遍历整个 RW Layer,在 10GB+ 写层的大容器上执行可能触发秒级卡顿,线上慎用。
  4. 与 docker inspect 联动:通过 GraphDriver.Data.WorkDir 找到实际挂载点,再用 du -h --max-depth=1 精确量化,避免 diff 文本统计误差。
  5. 国内镜像源加速场景:很多公司把 /var/lib/docker 挂在机械盘,diff 结果若出现 /root/.cache/pip/tmp/chromium 等路径,基本可判定未配置 .dockerignore 或缓存卷,导致 CI 重复下载。
  6. 安全合规:若 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 + 日志未切割

步骤三:闭环治理

  1. 临时docker exec $CID sh -c '> /opt/tomcat/logs/catalina.out' 清空日志,禁止 rm 文件,否则 fd 未释放仍占空间。
  2. 长期
    • 在 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。

步骤四:复盘报告
把 diff 日志、量化结果、治理 PR 链接统一归档到 Confluence,@相关负责人 24h 内评审,符合阿里“1-5-10”应急规范(1min 发现、5min 定位、10min 恢复)。

拓展思考

  1. Kubernetes 场景docker diff 只适用于 dockershim 节点;若集群已切到 Containerd,需用 ctr container diffcrictl diff命令输出格式不同,面试时要主动提及,避免“只会 Docker 那一套”的印象。
  2. 只读根文件系统:把 securityContext.readOnlyRootFilesystem: true 作为默认 Policy,所有写路径必须显式声明 volumeMounts,上线前用 kubectl diff 对比 Helm chart,杜绝 diff 出现 A 类路径
  3. eBPF 深度追踪:用 bcc/tools/filelifekubectl trace 抓短生命周期文件,比 diff 更精准;可进一步定位到 Java GC 线程、Node.js 临时 buffer,实现代码级优化
  4. 成本治理:把 diff 结果接入内部 FinOps 平台,按“每 1GB 写层 ≈ 0.3 元/月”折算,超预算自动创建 Jira 工单,推动业务方改造,实现技术价值向成本价值转化