Docker生产环境必做的那些事:资源限制、日志管控、配置清单一次说清
「Docker避坑指南」系列第④篇(终篇),聚焦生产环境资源管控和日志管理,附完整 daemon.json 配置清单。
前三篇讲的主要是”装上能跑”的问题,这篇讲的是”跑起来不出事”。
有次一个容器发生内存泄漏,32GB的内存被慢慢吃干净了,服务器直接卡死。重启之后,又碰到磁盘被日志塞满的问题。这两件事前后脚发生,那天晚上真的很难熬。
事后复盘,发现根本原因是:从来没给容器设置过任何资源上限。Docker默认不限制容器能用多少资源,一个容器真的可以把整台机器的CPU、内存、磁盘全部吃完。
坑①:容器内存泄漏,把整台服务器拖死
为什么会这样:
Docker本身不限制容器资源,如果你启动容器时没有设置上限,一个有内存泄漏的程序可以无限制地申请内存,直到系统OOM。
预防做法——启动时设置内存上限:
# 限制容器最多使用512MB内存,内存+swap总共1GBdocker run -m 512m --memory-swap 1g nginx
同样地,CPU也要限制:
# 最多使用1.5个CPU核心docker run --cpus="1.5" nginx# 或者用相对份额(默认是1024,这里设512相当于争抢时最多拿50%)docker run --cpu-shares=512 nginx
在docker-compose里设置资源限制:
version: '3'services: web: image: nginx deploy: resources: limits: cpus: '1.5' memory: 512M reservations: cpus: '0.5' memory: 256M
监控容器资源使用情况:
# 实时查看所有容器的资源消耗docker stats# 只看一次快照,不滚动docker stats --no-stream --format \"table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
我的经验:内存限制设为正常使用量的1.5-2倍,留一点余量,不要卡得太死,否则业务高峰期容器会被OOM Kill。
坑②:日志容器几小时写满500GB磁盘
事故过程:
一个负责接收日志的容器,某天收到的日志量异常大,几个小时后磁盘就满了,所有服务连带着出问题。
这个故障完全可以靠配置来预防。
第一层防护:全局限制容器日志大小
在 daemon.json 里配置,所有容器默认继承这个日志限制:
{"log-driver": "json-file","log-opts": {"max-size": "100m","max-file": "3","compress": "true" }}
每个容器最多3个日志文件,每个100MB,压缩存储,最坏情况占300MB左右。
第二层防护:限制容器可写层大小(需要xfs文件系统)
docker run --storage-opt size=10G nginx
第三层防护:磁盘监控告警脚本
#!/bin/bashUSAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')if [ $USAGE -gt 80 ]; thenecho"告警:磁盘使用率 ${USAGE}%,请及时清理!"# 可以接入钉钉/企微机器人发告警fi
第四层防护:定时自动清理
# 添加到crontab,每天凌晨3点执行0 3 * * * docker system prune -f --volumes --filter "until=72h"
until=72h 表示只清理3天前停止的资源,不会误删最近的。
坑③:日志文件几十GB,查日志直接卡死
容器跑了一段时间,日志文件动辄几十GB,docker logs 命令执行了半天没响应。
查日志的正确姿势:
# 只看最后100行,不要一次全加载docker logs --tail 100 container_name# 实时跟踪(Ctrl+C退出)docker logs -f container_name# 查看特定时间段docker logs --since "2026-02-20T10:00:00" --until "2026-02-20T11:00:00" container_name# 加时间戳,方便对照docker logs -t container_name
如果日志量实在太大,考虑用日志驱动转发出去:
# 发到本机syslogdocker run --log-driver=syslog nginx# 发到远程日志服务器(ELK、Loki等)docker run --log-driver=syslog \ --log-opt syslog-address=tcp://192.168.1.100:514 \ nginx
日志发到专门的日志系统之后,本地就不用存了,磁盘压力小很多,查询也方便。
生产环境 daemon.json 完整配置清单
这是我目前在生产环境用的配置,融合了前面说的各种优化点,经过多年验证:
{"registry-mirrors": ["https://docker.rainbond.cc","https://docker.1ms.run","https://docker.m.daocloud.io" ],"log-driver": "json-file","log-opts": {"max-size": "100m","max-file": "3","compress": "true" },"storage-driver": "overlay2","storage-opts": ["overlay2.override_kernel_check=true" ],"default-ulimits": {"nofile": {"Name": "nofile","Hard": 64000,"Soft": 64000 } },"live-restore": true,"userland-proxy": false,"dns": ["223.5.5.5", "8.8.8.8"],"max-concurrent-downloads": 10,"max-concurrent-uploads": 5,"default-address-pools": [ {"base": "172.17.0.0/16","size": 24 } ]}
几个关键配置说明:
live-restore: true
— Docker重启时不停止正在运行的容器,减少业务中断 userland-proxy: false
— 关闭用户态代理,性能更好,推荐生产环境开启 default-ulimits
— 提高文件描述符上限,避免高并发时”too many open files” default-address-pools
— 固定容器网络IP段,避免和内网地址冲突
安装后必做的10件事(速查)
docker --version && docker run hello-world
— 验证安装 sudo usermod -aG docker $USER
— 配置免sudo -
配置 registry-mirrors— 镜像加速 -
配置 log-opts— 限制日志大小 -
配置 live-restore: true— 减少重启中断 sysctl net.ipv4.ip_forward=1
— 开启IP转发 sudo systemctl enable docker
— 设置开机自启 docker network create mynet
— 创建自定义网络 -
所有生产容器加 -m内存限制 - 配置定时清理任务到crontab
写在最后
这个系列写了4篇,把我这几年在Docker运维中踩过的坑基本都梳理了一遍。
回过头来看,大多数坑的根源都一样:Docker的默认配置是为了”能跑起来”而设计的,不是为了”生产可用”。
从安装的第一天起,就应该按照生产标准配置——限制资源、配好日志、理解权限、选对驱动。这些事情早做一个小时,可能省的是后面好几个不眠夜。
如果这个系列对你有帮助,欢迎转发收藏。
夜雨聆风