Docker 容器日志把磁盘写满了:从定位到限制的完整处理
先确认:真的是容器日志吗
磁盘告警时先别急着删东西,先确认占用方。df -h 看的是文件系统整体使用率,docker system df 看的是镜像、容器、卷的占用,而容器日志通常在 /var/lib/docker/containers/<容器ID>/ 下的 *-json.log 文件里。
df -h
docker system df
du -sh /var/lib/docker/containers/*/*-json.log | sort -rh | head -20
docker ps --size
如果某个容器的 json.log 达到几 GB 甚至几十 GB,基本可以确定是日志失控。还要注意一种情况:文件已删除但进程仍持有句柄,du 看不到,df 却不释放,这时可用 lsof | grep deleted 排查,重启对应进程或容器后空间才会真正释放。
定位:哪个容器、哪类日志在刷屏
- 按大小排序找出最大的日志文件,对应容器 ID 后用
docker ps换算成容器名。 - 用
docker logs --tail 200 容器名看最近日志:是正常业务日志、调试日志,还是异常循环报错?最常见的是三类:死循环重试、把请求体和返回体全量打印、第三方库默认开启 debug。 - 看增长速度:隔 10 秒再
ls -lh一次日志文件,算出每小时大约增长多少,这样才能定出合理的上限,而不是拍脑袋定一个数。
应急处理:先止血,再谈优化
线上磁盘只剩几百 MB 时,首选截断而不是直接删除正在写入的文件:
# 截断指定容器的日志文件,容器不用停
: > /var/lib/docker/containers/<容器ID>/<容器ID>-json.log
# 或
truncate -s 0 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log
截断后立即确认 df -h 是否回落。如果业务允许,重启不断刷错的容器也能暂时止血,但如果不修根因,日志很快又会长回来。应急时顺手把日志级别从 debug 调回 info,把明显无用的全量打印关掉,效果往往比单纯删文件好得多。
长期限制:给日志装上水位线
对新容器和已有编排,最直接的是在 Docker 层面做轮转。全局配置写在 /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
改完执行 systemctl restart docker 生效。注意:这个配置只对之后创建的容器生效,已有容器要重新创建才能用上新配置,例如用 Compose 重新部署:
services:
app:
image: my-app:latest
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
max-size 是单个文件上限,max-file 是保留文件数,两者相乘就是单个容器日志的上限。10m 乘 3 即约 30MB,对大多数业务足够;日志量大的服务可以放宽到 50m 乘 5,但不要不设上限。
应用层也要收敛
只靠 Docker 轮转还不够,应用层不收敛,轮转只会把磁盘问题变成日志丢失问题。建议做到四点:日志分级,生产默认 info,debug 只在排障时临时开;不要打印完整请求体、敏感信息和大对象;高频心跳、轮询类日志降级或采样;异常要节流,同一错误短时间内只记一次摘要,详情写到独立文件或监控里。
监控:别等磁盘 100% 才发现
给磁盘使用率设两档告警:80% 提醒清理和排查,90% 升级处理;同时定期跑 docker system df 和日志大小排序,纳入巡检。也可以把容器日志接入集中日志或对象存储,本地只保留最近几天的热日志,既方便排障,又不让单机磁盘成为瓶颈。
总结
处理顺序是:先用 df、docker system df 和 du 定位到具体日志文件,再用 docker logs 判断是正常量大还是异常刷屏;应急用截断止血;长期用 max-size 和 max-file 做轮转并重新创建容器;最后在应用层收敛日志级别和内容,并把磁盘水位告警做起来。这样磁盘才不会被日志悄悄写满。
- 点赞
- 收藏
- 关注作者
评论(0)