Ubuntu服务器运行一段时间后,/var/log目录经常会把磁盘撑满,尤其是/var/log/journal和nginx、mysql等应用日志。清理日志不是简单删除文件,直接rm虽然释放了空间,但会导致正在写入日志的进程失去文件句柄,后续日志无法正常记录,甚至需要重启服务才能恢复。更稳妥的做法是使用truncate命令清空文件内容,既释放空间又不破坏文件句柄。

先查看磁盘占用情况,定位哪些日志文件体积异常。执行du -sh /var/log/* 2>/dev/null | sort -rh | head -20,可以按大小排序显示前20个日志文件或目录。常见的空间大户包括syslog、kern.log、daemon.log、auth.log以及journal目录。对于单个大文件,用truncate -s 0 /var/log/syslog这样的命令清空,比删除再重建更安全。如果是压缩过的旧日志,比如syslog.2.gz这类文件,直接rm删除即可,它们已经不参与实时写入。

systemd-journald的日志清理需要单独处理。Ubuntu默认将journal日志存放在/var/log/journal目录下,并且设置了大小上限,但很多服务器因为长期运行,journal目录仍然可能达到数百MB甚至GB级别。查看当前journal占用空间用journalctl --disk-usage。清理方法有两种:一是只保留最近两天的日志,执行journalctl --vacuum-time=2d;二是限制journal目录最大占用空间,执行journalctl --vacuum-size=200M。这两个命令可以组合使用,也可以写入定时任务定期执行。如果要永久限制journal大小,需要编辑/etc/systemd/journald.conf,设置SystemMaxUse=200M和SystemKeepFree=1G,然后重启systemd-journald服务。

日志轮转机制的配置与优化

Ubuntu系统自带的logrotate工具负责日志轮转,配置文件位于/etc/logrotate.conf和/etc/logrotate.d/目录下。默认配置通常每周轮转一次,保留4周的日志。对于日志增长很快的服务器,这个默认策略远远不够。以nginx为例,如果每天产生数GB访问日志,一周才轮转一次,磁盘很容易被写满。需要针对具体应用调整轮转策略。

修改/etc/logrotate.d/nginx配置文件,可以设置每天轮转、保留7天、压缩旧日志。示例配置如下:

/var/log/nginx/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

这里的关键参数中,daily表示每天轮转,rotate 7表示只保留7个历史文件,compress表示压缩轮转后的日志,delaycompress表示延迟一轮压缩,避免压缩正在被读取的文件。create指定新建日志文件的权限和属主,sharedscripts和postrotate确保nginx在日志轮转后重新打开日志文件。对于mysql慢查询日志、php错误日志等,都可以采用类似策略。轮转后手动执行logrotate -f /etc/logrotate.conf可以立即生效,验证配置是否正确。

安全留存规范的核心原则

日志清理不能只考虑释放空间,安全留存同样重要。很多安全合规要求日志必须保留至少6个月甚至更长时间,这与磁盘空间限制形成矛盾。解决思路是分级存储:本地保留近期热数据,远端或对象存储保留长期冷数据。Ubuntu服务器上可以用rsync配合定时任务,将轮转后的压缩日志同步到备份服务器或对象存储。

具体操作上,先确定哪些日志属于安全审计范畴。auth.log记录用户登录、sudo操作,syslog记录系统级事件,kern.log记录内核消息,这些都属于核心安全日志。应用日志中,nginx的access.log和error.log、mysql的慢查询日志和错误日志也需要留存。建议将这些日志在logrotate轮转压缩后,通过rsync同步到独立存储。示例同步命令:

rsync -avz --remove-source-files /var/log/nginx/*.gz backup@192.168.1.100:/data/logs/nginx/

使用--remove-source-files参数可以在同步成功后删除本地压缩日志,进一步释放本地空间。但要注意,这个参数会删除所有已同步的.gz文件,如果同步过程中断,可能导致数据丢失。更保险的做法是同步完成后单独执行清理,或者使用--remove-source-files配合--ignore-errors参数。

审计日志的防篡改与完整性保护

安全留存不仅仅是保存日志文件,还要确保日志内容不被篡改。Ubuntu自带的auditd审计系统可以记录更细粒度的系统调用和文件访问事件,但audit日志本身也需要保护。对于关键日志,建议启用日志文件的不可变属性。使用chattr +a /var/log/auth.log命令可以设置append-only属性,日志只能追加不能修改或删除。不过这个属性会影响logrotate的正常轮转,需要在轮转前移除属性,轮转后重新设置。

另一种做法是定期计算日志文件的哈希值并保存。例如每天对auth.log计算SHA256值,将结果追加到独立的校验文件中。如果日志被篡改,哈希值就会不匹配。这个校验文件本身应该存储在只读介质或远端服务器上。对于高安全要求的场景,可以考虑部署集中式日志服务器,使用rsyslog或syslog-ng将日志实时转发到远端,本地只保留短期副本。Ubuntu配置rsyslog远程转发很简单,在/etc/rsyslog.d/目录下新建配置文件,添加*.* @日志服务器IP:514即可。

定时清理任务的自动化部署

手动清理日志只能解决一时之需,建立自动化清理机制才能长期维持磁盘健康。建议在crontab中设置定期任务,每周执行一次日志清理和同步。编辑/etc/crontab或使用crontab -e添加以下内容:

# 每周日凌晨2点清理journal日志
0 2 * * 0 root journalctl --vacuum-time=7d --vacuum-size=500M

# 每周日凌晨3点执行logrotate强制轮转
0 3 * * 0 root /usr/sbin/logrotate -f /etc/logrotate.conf

# 每周日凌晨4点同步压缩日志到备份服务器
0 4 * * 0 root rsync -avz /var/log/nginx/*.gz backup@192.168.1.100:/data/logs/nginx/

在部署自动化任务前,务必先在测试环境验证每条命令的执行效果。特别是rsync同步任务,需要提前配置SSH密钥认证,避免交互式密码输入导致任务失败。对于生产环境,建议将清理策略写成脚本,加入错误处理和日志记录,便于追踪执行情况。脚本示例:

#!/bin/bash
# 日志清理与同步脚本
LOG_FILE="/var/log/cleanup.log"
echo "$(date '+%Y-%m-%d %H:%M:%S') 开始执行日志清理" >> $LOG_FILE

# 清理journal日志
journalctl --vacuum-time=7d --vacuum-size=500M >> $LOG_FILE 2>&1

# 强制轮转
/usr/sbin/logrotate -f /etc/logrotate.conf >> $LOG_FILE 2>&1

# 同步nginx日志
rsync -avz /var/log/nginx/*.gz backup@192.168.1.100:/data/logs/nginx/ >> $LOG_FILE 2>&1

# 删除7天前的本地压缩日志
find /var/log/nginx/ -name "*.gz" -mtime +7 -delete >> $LOG_FILE 2>&1

echo "$(date '+%Y-%m-%d %H:%M:%S') 日志清理完成" >> $LOG_FILE

这个脚本将清理、轮转、同步、删除四个步骤串联起来,每一步都有日志记录。将脚本保存为/usr/local/bin/log_cleanup.sh,赋予执行权限chmod +x /usr/local/bin/log_cleanup.sh,然后在crontab中设置每周执行一次即可。

磁盘空间监控与告警

清理策略部署后,还需要监控磁盘使用率,避免日志异常增长时无法及时发现。Ubuntu服务器可以安装监控工具,或者使用简单的shell脚本配合cron实现告警。以下脚本检查根分区使用率,超过80%时发送邮件告警:

#!/bin/bash
USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $USAGE -gt 80 ]; then
    echo "警告:服务器磁盘使用率已达${USAGE}%" | mail -s "磁盘空间告警" admin@example.com
fi

将这个脚本加入crontab,每小时执行一次。对于更复杂的监控需求,可以考虑部署Prometheus配合node_exporter,或者使用Zabbix等监控平台。监控指标不仅要关注磁盘使用率,还要关注日志增长速度。如果某类日志在短时间内异常增长,往往意味着系统遭受攻击或应用出现故障,需要立即排查。

特殊日志文件的处理注意事项

部分Ubuntu服务器运行着容器化应用,Docker容器的日志默认存储在/var/lib/docker/containers/目录下,以json格式保存。这些日志不受logrotate管理,需要单独配置。Docker提供了日志驱动配置,可以在daemon.json中设置max-size和max-file参数限制单个容器的日志大小。修改/etc/docker/daemon.json:

{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "3"
    }
}

修改后重启Docker服务生效。对于已经存在的容器,需要重新创建才能应用新配置。另外,Ubuntu的apt包管理器日志位于/var/log/apt/目录,包括history.log和term.log,这些日志记录了软件安装卸载历史,对于故障排查和安全审计有价值,但体积通常不大,可以保留较长时间。如果磁盘紧张,也可以适当清理超过一年的旧日志。

最后需要强调的是,日志清理策略应该与安全留存策略同步制定。清理不是目的,在保障安全审计需求的前提下合理释放磁盘空间才是目标。建议每季度审查一次日志留存策略,根据实际磁盘容量和安全合规要求动态调整。对于关键业务服务器,日志留存时间不应少于30天,核心安全日志建议保留90天以上。通过本地轮转压缩、远端同步归档、定期清理释放三层机制,可以在磁盘空间和安全留存之间取得平衡。