5.5.4 日志轮转与持久化实践
日志轮转与持久化的目标是控制日志体积、避免磁盘耗尽、满足审计与排障留痕,并保证脚本运行中断时仍可追溯。建议统一日志路径与命名规范,如 /var/log/ops/脚本名/YYYYMMDD.log,目录权限建议 750,日志文件 640。
原理草图(日志产生 → 轮转 → 压缩 → 持久化/集中存储):
1) 使用 logrotate(推荐)示例#
安装与确认:
# 安装(基于 Debian/Ubuntu)
sudo apt-get update
sudo apt-get install -y logrotate
# 安装(基于 RHEL/CentOS)
sudo yum install -y logrotate
# 查看版本与主配置
logrotate --version
cat /etc/logrotate.conf
命令解释:logrotate --version 查看版本;主配置包含全局策略(如默认保留周期、压缩)。
创建业务脚本日志与轮转配置:
# 准备日志目录与权限
sudo install -d -m 750 -o root -g ops /var/log/ops/demo
sudo touch /var/log/ops/demo/demo.log
sudo chown root:ops /var/log/ops/demo/demo.log
sudo chmod 640 /var/log/ops/demo/demo.log
# 写入脚本日志示例(脚本将日志写入固定文件)
cat >/usr/local/bin/demo_job.sh <<'EOF'
#!/usr/bin/env bash
LOG=/var/log/ops/demo/demo.log
echo "$(date '+%F %T') [INFO] demo job running" >> "$LOG"
EOF
chmod +x /usr/local/bin/demo_job.sh
# 轮转配置(/etc/logrotate.d/demo_job)
cat >/etc/logrotate.d/demo_job <<'EOF'
/var/log/ops/demo/demo.log {
daily
size 50M
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root ops
copytruncate
postrotate
# 轮转后记录控制日志,便于审计
echo "$(date '+%F %T') rotated" >> /var/log/ops/demo/control.log
endscript
}
EOF
运行测试与预期效果:
# 强制执行(-f),并显示调试信息(-d 不实际执行)
sudo logrotate -f /etc/logrotate.d/demo_job
sudo logrotate -d /etc/logrotate.d/demo_job
# 预期:生成 demo.log.1 和 demo.log.1.gz 等文件
ls -lh /var/log/ops/demo/
命令解释:-f 强制轮转,-d 仅调试输出;copytruncate 适合无法通知服务重开文件句柄的场景,但存在丢日志风险。
2) 脚本内轮转(谨慎使用)示例#
适用于无 logrotate 或极简环境。核心是原子 mv、touch、加锁避免并发。
cat >/usr/local/bin/rotate_inline.sh <<'EOF'
#!/usr/bin/env bash
LOG=/var/log/ops/demo/inline.log
LOCK=/var/lock/inline.lock
MAX_MB=10
exec 200>"$LOCK"
flock -n 200 || exit 1
# 创建日志文件
touch "$LOG"
SIZE_MB=$(du -m "$LOG" | awk '{print $1}')
TODAY=$(date +%Y%m%d)
ARCHIVE="${LOG}.${TODAY}"
if [ "$SIZE_MB" -ge "$MAX_MB" ]; then
mv "$LOG" "$ARCHIVE"
touch "$LOG"
gzip -f "$ARCHIVE"
fi
echo "$(date '+%F %T') [INFO] inline log entry" >> "$LOG"
EOF
chmod +x /usr/local/bin/rotate_inline.sh
命令解释:flock -n 非阻塞加锁防止并发冲突;du -m 获取大小;mv 是原子替换;gzip -f 强制压缩。
3) 持久化与集中存储#
分离日志分区与挂载:
# 示例:将 /var/log 挂载到独立卷(假设 /dev/vdb1 已格式化)
sudo mkdir -p /var/log
sudo mount /dev/vdb1 /var/log
df -h /var/log
# 持久化配置(/etc/fstab)
echo "/dev/vdb1 /var/log ext4 defaults 0 2" | sudo tee -a /etc/fstab
命令解释:独立分区可避免日志撑满系统盘;df -h 验证挂载。
集中存储(rsyslog 远程转发示例):
# /etc/rsyslog.d/99-ops.conf
*.* @@10.0.0.10:514
命令解释:@@ 表示 TCP 传输;集中存储用于审计合规与防篡改。
容器场景建议写 stdout/stderr,由宿主采集;如需文件日志,挂载持久化卷并在宿主机统一轮转。
4) 常见问题与排错#
1) 轮转不生效
# 看 logrotate 运行日志或手动调试
sudo logrotate -d /etc/logrotate.d/demo_job
sudo grep -i logrotate /var/log/syslog /var/log/messages 2>/dev/null
排错点:配置语法错误、路径不匹配、权限不足。
2) 日志被清空或丢失
原因:copytruncate 在高并发写入时可能丢数据。
替代:服务支持 SIGHUP 重开日志。
# 例:nginx 重开日志
sudo nginx -s reopen
3) 权限错误
# 确认目录与文件权限
namei -l /var/log/ops/demo/demo.log
排错点:目录权限不足、属主组不匹配、SELinux 限制。
4) 磁盘满导致写入失败
df -h
df -i
排错点:空间或 inode 用尽,需清理旧日志或扩容。
5) 练习#
- 编写一个脚本,每分钟写 1 行日志到
/var/log/ops/lab/lab.log,并配置 logrotate:
- 超过 5MB 或每日轮转
- 保留 7 份并压缩
- 轮转后记录控制日志 - 将
/var/log挂载到独立分区并持久化配置到/etc/fstab。 - 模拟高频写入,比较
copytruncate与nginx -s reopen的效果差异。 - 使用
logrotate -d解释每个关键参数的执行行为。