容器内不应安装logrotate,因其违背不可变原则且存在权限、信号与生命周期问题;正确做法是优先使用docker原生日志驱动(如json-file)配置max-size和max-file实现自动轮转,应用层日志则由宿主机logrotate配合postrotate通知进程重开日志。

容器内确实没有 logrotate,也不该有——它本就是宿主机层面的日志治理工具。强行在容器里装 logrotate 不仅违背容器不可变原则,还会引入额外进程、权限冲突和生命周期管理问题。
为什么不能在容器里跑 logrotate
容器是进程隔离单元,不是轻量虚拟机。以下行为会直接出问题:
-
logrotate需要读写日志文件并执行copytruncate或重命名,但容器内日志通常由 Docker 的json-file驱动接管,真实文件在宿主机/var/lib/docker/containers/...下,容器内根本看不到 - 即使挂载了宿主机日志路径(如
/mydata/nginx/logs),容器内运行logrotate仍需 root 权限、信号转发能力(如kill -USR1)、以及对 Nginx/Apache 等主进程的 PID 可见性——这些在非特权容器中默认不可用 - 容器重启或重建后,
logrotate配置、定时任务(cron)全部丢失,无法持续生效
正确做法:用 Docker 原生日志驱动做基础轮转
优先启用 json-file 驱动的内置轮转,零依赖、无侵入、自动生效:
- 全局配置(推荐):修改
/etc/docker/daemon.json,添加:
{ "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "7" } }
- 单容器覆盖(调试或差异化需求):启动时加参数
docker run -d --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 nginx:alpine
- 注意:
max-size支持单位k、m、g;max-file是总文件数(含当前正在写的那个),超出后自动删除最老的 - 效果:日志存于宿主机
/var/lib/docker/containers/<id>/<id>-json.log</id></id>,轮转后生成-json.log.1、-json.log.2等,不需任何外部干预
需要更精细控制?交给宿主机 logrotate
当你要按天压缩、归档到 NFS、或触发远程通知时,才启用宿主机 logrotate,且必须匹配 Docker 日志路径:
- 确认宿主机已安装:
rpm -q logrotate(RHEL/CentOS)或dpkg -l | grep logrotate(Debian/Ubuntu) - 创建配置文件
/etc/logrotate.d/docker-json,内容为:
/var/lib/docker/containers/*/*-json.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
copytruncate
sharedscripts
postrotate
# Docker 守护进程会自动处理轮转,一般无需发信号
# 若你启用了 journald/syslog 驱动,则此处需对应 reload
endscript
}
-
copytruncate是关键:Docker 进程持续写入原文件,logrotate复制后立即清空,避免中断 - 不要写
create:Docker 自己管理文件创建和权限,宿主机手动 touch 会破坏所有权 - 测试配置是否合法:
logrotate -d /etc/logrotate.d/docker-json(调试模式)
应用层日志(如 Nginx access.log)怎么切
这类日志是你自己挂载进容器的(如 -v /mydata/nginx/logs:/var/log/nginx),它们**不在 Docker 日志驱动管辖范围**,必须由宿主机 logrotate 管理:
- 配置文件路径示例:
/etc/logrotate.d/nginx - 核心区别在于
postrotate必须通知应用重开日志文件:
/mydata/nginx/logs/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
sharedscripts
postrotate
test -f /mydata/nginx/logs/nginx.pid && kill -USR1 `cat /mydata/nginx/logs/nginx.pid`
endscript
}
-
nginx.pid必须由容器内 Nginx 主动写入挂载卷,且路径与配置一致;若用supervisord或自定义 entrypoint,需确保 PID 文件可被宿主机读取 - 别漏掉
sharedscripts:多个日志文件(access/error)共用一个postrotate,否则会重复发信号
真正容易被忽略的是路径归属和信号时机:宿主机 logrotate 操作的永远是挂载点下的文件,而 postrotate 发送的信号必须能被容器内对应进程接收——这意味着要么容器以 --pid=host 启动,要么 PID 文件必须落盘且路径可跨隔离访问。没对齐这两点,轮转就只是“看起来在跑”。











