容器销毁后能否提取容器内标准输出的日志?

容器销毁后能否提取容器内标准输出的日志?

答案是:不能。

应急响应中经常遇到的一类场景,容器内服务有漏洞,但是出事的容器被销毁重建了,此时应急取证需要提取容器中服务输出的日志,通常输出在容器的标准输出。

模拟docker容器销毁场景

  # 启动一个每秒往 stdout 打日志的容器
  docker run -d --name log-demo busybox:latest \
    sh -c 'i=0; while true; do echo "log line $i $(date +%T)"; i=$((i+1)); sleep 1; done'

  # 看 docker logs 读到的 stdout
  sleep 3
  docker logs log-demo

  # docker 这个容器的日志文件落在宿主机哪里
  docker inspect -f '{{.LogPath}}' log-demo

  #  输出如: /var/lib/docker/containers/<容器ID>/<容器ID>-json.log

我们创建一个只输出日志的容器来模拟。

然后模拟容器被销毁的场景。

  # 记下目录,删容器前后对比
  CID=$(docker inspect -f '{{.Id}}' log-demo)
  DIR=/var/lib/docker/containers/$CID
  ls -ld "$DIR"                      # 删除前:目录在

  # 删除容器 = 模拟 Pod/容器销毁
  docker rm -f log-demo

  # 验证:文件随容器一起消失,docker logs 也读不到
  ls -ld "$DIR"                      # 报「没有那个文件或目录」
  docker logs log-demo           

模拟k8s pod 销毁的场景

这里使用kind + Pod 场景来模拟复现。

  # 创建单节点集群,context 自动设为 kind-logdemo 
  kind create cluster --name logdemo --wait 60s

  # 集群已存在,确认 context 
  kubectl config get-contexts          # 看当前 context
  kubectl --context kind-logdemo get nodes

  # 创建一个每秒打 stdout 的 Pod
  kubectl --context kind-logdemo run log-demo --image=busybox:latest --restart=Never -- \
    sh -c 'i=0; while true; do echo "pod log line $i"; i=$((i+1)); sleep 1; done'

  kubectl --context kind-logdemo wait --for=condition=Ready pod/log-demo --timeout=60s
  sleep 3
  kubectl --context kind-logdemo logs log-demo

  # 查 Pod 落在哪个节点 + 它的 UID(路径里要用)
  kubectl --context kind-logdemo get pod log-demo \
    -o jsonpath='{.spec.nodeName}{"  uid="}{.metadata.uid}{"\n"}'
  #  节点名就是 docker 容器名:logdemo-control-plane

  # 进节点看真实日志路径(kind 用 docker 容器模拟节点) 
  NODE=logdemo-control-plane

  # /var/log/pods 下的 Pod 目录
  docker exec $NODE sh -c 'ls -la /var/log/pods/ | grep log-demo'

  # 真实日志文件:<container>/<重启次数>.log
  docker exec $NODE sh -c 'find /var/log/pods/default_log-demo_* -type f'
  docker exec $NODE sh -c 'tail -n 3 /var/log/pods/default_log-demo_*/log-demo/0.log'
  #  CRI 格式:2026-05-29T07:53:42.949Z stdout F pod log line 11

  # /var/log/containers 下的软链接(kubectl logs 的实际入口)
  docker exec $NODE sh -c 'ls -l /var/log/containers/ | grep log-demo'
  docker exec $NODE sh -c 'readlink -f /var/log/containers/log-demo*'

然后再模拟k8s pod被销毁的场景。

# 模拟pod被销毁
  kubectl --context kind-logdemo delete pod log-demo --grace-period=5

# 检查pod的日志是否还存在
  for i in $(seq 1 12); do
    docker exec $NODE sh -c 'ls /var/log/pods/ 2>/dev/null | grep -q log-demo ' \
      && echo "[$((i*5))s] 目录仍在" || { echo "目录已被清理,日志彻底消失"; break; }
    sleep 5
  done

真实文件由 kubelet 异步 GC,有十几秒延迟,这正是采集器必须实时跟读、不能等 Pod 删了再来收的原因。

用完想删集群:

kind delete cluster --name logdemo

总结

容器pod被销毁时,容器的标准输出日志几乎是实时被删除的,所以在应急场景下遇到类似情况没必要浪费时间获取已销毁的容器日志上。

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

发表评论