为什么nginx 的日志就无法正常执行logrotate呢?nginx的logrotate配置没问题,手动的执行logrotate也没有问题,而且crond程序每天也都正常执行,包括系统本身的日志都正常轮替? 诡异……
问题
最近遇到一个很诡异的问题,nginx 的日志使用logrotate
不按计划执行。多次排查,经过几天的观察也无效果。
分析
先分成几步吧。一步一步找问题。我先列出以下几个点:
- logrotate 运行机制
- nginx logrotate配置文件
- 手动执行
- selinux
Nginx日志logrotate(轮替)
Nginx的日志,默认使用rpm或yum安装的情况下,是自动会添加logrotate文件的,我们不用特意的配置。但在编译的nginx中,我们需要手动添加logrotate文件的,不然日志是无法切割的。
运行机制
首先,系统在启动时,会自动加载运行crond
,默认系统也已经安装了logrotate
程序。它会根据设置对指定的文件进行轮替切割。即 crond + logrotate 实现了日志的自动轮转,不用我们写脚本控制日志的轮替了。
默认的cron
配置位于 /etc
目录下:
ls /etc/cron*
cron.d/ cron.daily/ cron.deny cron.hourly/ cron.monthly/ crontab cron.weekly/
从上面文件夹的名字可以看出,默认的cron
计划可以按天、小时、周、月来执行。
logrotate配置
默认logrotate的cron文件位于/etc/cron.daily/logrotate
下。即每天执行。
可以看下文件内容:
#!/bin/sh
/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0
其中需要注意的是,上面的这个文件/etc/logrotate.conf
,该文件是logrotate服务的主配置文件。
我们看下该文件的内容:
# see "man logrotate" for details
# rotate log files weekly
weekly
# keep 4 weeks worth of backlogs
rotate 4
# create new (empty) log files after rotating old ones
create
# use date as a suffix of the rotated file
dateext
# uncomment this if you want your log files compressed
#compress
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
monthly
create 0664 root utmp
minsize 1M
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}
# system-specific logs may be also be configured here.
然后我们可以关注下 include
指令,这里是rpm安装包安装完后,会把自己的logrotate
配置放入到该子目录中,是不是很像nginx
的虚拟主机配置?
这个文件是默认的配置,当然我们可以在子文件中,添加相关的选项覆盖默认的配置。
Nginx logrotate配置
我们看下/etc/logrotate.d/nginx
的内容:
"/data/nginx/logs/*.log"
{
daily
rotate 7
missingok
dateext
compress
delaycompress
sharedscripts
create 0640 nginx nginx
postrotate
if [ -f /usr/local/nginx/logs/nginx.pid ]; then kill -USR1 `cat /usr/local/nginx/logs/nginx.pid` ; fi
endscript
}
里面的指令网上一查就知道了,不过这里还是简单说明记录下。
daily 每日执行
rotate 保留轮替的7份,先进先出,超过7就删除之前的文件
missingok 忽略错误
dateext 定义日期后缀格式,这里也可以修改默认值*dateext format -%Y-%m-%D*
compress 是否压缩
delaycompress 延迟压缩
create 定义新日志文件的属性
postrotate 轮转日志文件之后执行的脚本
sharedscripts 如果该文件中定义了多个文件需要logrotate,那么该指令只会执行一次postrotate脚本
测试验证
可以通过手动执行验证logrotate配置
logrotate -d /etc/logrotate.conf
-d:
开启debug模式,不会实际执行轮转文件
在这里都是没有问题的,在第二天观察的时候,发现还是不行。然后又修修补补,各种改nginx的logrotate文件,发现还是各种不行。
检查selinux
在和朋友聊了这么诡异的问题之后,突然聊到了selinux
, 对,就是我们在接触linux时,一般各种文档都会提示禁用selinux
.
检查下是否开启了selinux
:
# sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 31
果然确实是开启的状态。看下审计日志(拒绝和关联的系统调用记录到/var/log/audit/audit.log)
grep nginx /var/log/audit/audit.log | grep logs
输出如下面的内容:
type=AVC msg=audit(1574651401.550:22184): avc: denied { getattr } for pid=26928 comm="logrotate" path="/data/nginx/logs/access.log" dev="sda3" ino=68228788 scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
type=AVC msg=audit(1574651401.567:22185): avc: denied { getattr } for pid=26928 comm="logrotate" path="/data/nginx/logs/access.log" dev="sda3" ino=68228788 scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
可以把上面的时间戳复制下,通过以下命令看下具体发生的时间:
date -d "@1574651401.567"
调试下selinux,安装selinux tools 工具
:
yum install policycoreutils-python -y
我们使用刚安装好的selinux工具,audit2allow
可以从拒绝的操作的日志中生成SELinux策略允许规则。
grep nginx /var/log/audit/audit.log | audit2allow -m nginx -a
或者直接使用以下命令,可以看到系统目前出现过的audit日志
audit2allow -w -a
我们这里先直接关闭selinux
吧。验证下。
setenforce 0
永久关闭selinux
,需要修改selinux的配置文件/etc/sysconfig/selinux
:
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
验证
第二天再看下,日志已经成功轮替了,确认了下就是selinux
的“锅”. 另外文章底部的参考链接有开启selinux
让日志logrotate正常
工作的方式。有需要的可以看下。