必须用copytruncate,它是唯一保持日志文件inode不变的方案:先复制内容再截断原文件,不重建文件,故路径、权限、属主及inode全部保留;而默认重命名+create会生成新inode。

logrotate 怎么保持日志文件 inode 不变
必须用 copytruncate,这是唯一能确保原日志文件 inode 编号不变的方案。默认的重命名 + create 方式会创建新文件,inode 必然改变;而 copytruncate 本质是先复制内容、再截断原文件,不重建文件,只清空内容,所以路径、权限、属主、inode 全部保留。
为什么不用 postrotate + kill 发送信号
发送信号(如 kill -USR1)让程序重新打开日志,确实能避免复制开销,但前提是程序得支持——很多老旧脚本、容器内无特权进程、或没实现日志重载逻辑的二进制程序根本收不到或忽略信号。一旦信号失败,logrotate 会继续创建新文件,而原进程仍在往旧 inode 写,导致新日志“消失”。copytruncate 绕过这个依赖,对程序完全透明。
使用 copytruncate 的实际配置要点
在 /etc/logrotate.d/your-app 中写入时注意以下几点:
-
copytruncate必须和rotate、daily等轮转条件共存,不能单独使用 - 不要同时写
create—— 它和copytruncate冲突,logrotate 会报错或行为未定义 - 如果日志量极大(比如 >1GB),需评估磁盘 I/O 峰值:每次轮转都要读+写全量数据,可能卡住其他服务
-
missingok和notifempty建议加上,防止因路径不存在或日志为空导致轮转中断
示例配置:
/var/log/myapp/app.log {
daily
rotate 7
compress
delaycompress
copytruncate
missingok
notifempty
}
验证 inode 是否真没变
轮转前后执行:ls -i /var/log/myapp/app.log。如果输出的数字一致,说明成功;若变了,大概率是误启用了 create 或漏写了 copytruncate,又或者程序自己重建了日志文件(比如某些应用检测到文件为空就主动 reopen)。
特别注意:copytruncate 无法 100% 避免日志丢失——复制完成到截断之间的极短窗口(通常毫秒级)内新写入的内容会被清掉。生产环境若对日志完整性要求极高,应优先推动程序升级支持信号重载,而非依赖 copytruncate。


















