logrotate容器中Nginx日志的切割滚动

无论是对于系统还是对于应用而言,日志是一个极其重要的部分,在出现问题需要追踪的时候,日志文件就发挥它的价值了。

通常日志信息会保存在文件中,显然随着时间的推移,日志文件文件体积会变成很大、记录时间跨度也变得很大。

如果需要打开日志追溯问题时变得异常困难,所以我们需要对我们的日志进行管理,通过某种策略对日志进行分割以降低日志文件的体积和跨度。

对于系统日志而言,并没有做这样的策略。对于应用而已,我们会要求开发者将日志写入到以时间命令的日志文件中。

一个日志文件保存一天时间的日志,这是一种比较方便快捷的方式。

我们一般在容器中的nginx日志会通过卷的方式挂载在宿主机上,日志也会随着时间推移变的越来越大。

我们将在宿主机上进行日志切割容器中的nginx日志。

logrotate命令 linux系统默认安装了logrotate的工具。

# docker exec web logrotate -v
logrotate 3.7.4 - Copyright (C) 1995-2001 Red Hat, Inc.
This may be freely redistributed under the terms of the GNU Public License

Usage: logrotate [-dfv?] [-d|--debug] [-f|--force] [-m|--mail command]
        [-s|--state statefile] [-v|--verbose] [-?|--help] [--usage]
        [OPTION...] <configfile>

我们在容器里面定义的切割规则为:

# cat /etc/logrotate.d/nginx
/data/logs/*.log {  #表示nginx日志存储路径
daily   #指定转储周期为每天
rotate 5    #指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
missingok   #如果日志丢失,不报错继续滚动下一个日志
notifempty  #当日志文件为空时,不进行轮转
sharedscripts   #运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。
                #如果没有配置这个,那么每个日志轮转后都会执行一次脚本
dateext     #使用当期日期作为命名格式
postrotate  #在logrotate转储之后需要执行的指令,例如重新启动 (kill -HUP) 某个服务!必须独立成行
    if [ -f /opt/nginx/logs/nginx.pid ]; then
        kill -USR1 `cat /opt/nginx/logs/nginx.pid`
    fi
endscript   #postrotate结束标识符
}

然后在容器里面定义切割脚本:

[root@容器 ~]# cat log.sh
#!/bin/bash
/usr/sbin/logrotate -f /etc/logrotate.d/nginx

然后在宿主机定义crontab定时任务:

# m h  dom mon dow   command
1       0       *       *       *       sh /root/cron/log.sh
root@宿主机:~# cat ~/cron/log.sh
#!/bin/bash
docker exec web "/root/log.sh"

这样就完成了容器中nginx日志的切割滚动!

logrotate配置文件参数

| 配置                      | 说明                                                                                                                                                                                          |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| compress                | 通过gzip 压缩转储以后的日志                                                                                                                                                                            |
| nocompress              | 不做gzip压缩处理                                                                                                                                                                                  |
| copytruncate            | 用于还在打开中的日志文件,把当前日志备份并截断;是先拷贝再清空的方式,拷贝和清空之间有一个时间差,可能会丢失部分日志数据。                                                                                                                               |
| nocopytruncate          | 备份日志文件不过不截断                                                                                                                                                                                 |
| create mode owner group | 轮转时指定创建新文件的属性,如create 0777 nobody nobody                                                                                                                                                    |
| nocreate                | 不建立新的日志文件                                                                                                                                                                                   |
| delaycompress           | 和compress 一起使用时,转储的日志文件到下一次转储时才压缩                                                                                                                                                           |
| nodelaycompress         | 覆盖 delaycompress 选项,转储同时压缩。                                                                                                                                                                 |
| missingok               | 如果日志丢失,不报错继续滚动下一个日志                                                                                                                                                                         |
| errors address          | 专储时的错误信息发送到指定的Email 地址                                                                                                                                                                      |
| ifempty                 | 即使日志文件为空文件也做轮转,这个是logrotate的缺省选项。                                                                                                                                                           |
| notifempty              | 当日志文件为空时,不进行轮转                                                                                                                                                                              |
| mail address            | 把转储的日志文件发送到指定的E-mail 地址                                                                                                                                                                     |
| nomail                  | 转储时不发送日志文件                                                                                                                                                                                  |
| olddir directory        | 转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统                                                                                                                                                           |
| noolddir                | 转储后的日志文件和当前日志文件放在同一个目录下                                                                                                                                                                     |
| sharedscripts           | 运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本                                                                                                                              |
| prerotate               | 在logrotate转储之前需要执行的指令,例如修改文件的属性等动作;必须独立成行                                                                                                                                                   |
| postrotate              | 在logrotate转储之后需要执行的指令,例如重新启动 (kill -HUP) 某个服务!必须独立成行                                                                                                                                        |
| daily                   | 指定转储周期为每天                                                                                                                                                                                   |
| weekly                  | 指定转储周期为每周                                                                                                                                                                                   |
| monthly                 | 指定转储周期为每月                                                                                                                                                                                   |
| rotate count            | 指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份                                                                                                                                                          |
| dateext                 | 使用当期日期作为命名格式                                                                                                                                                                                |
| dateformat .%s          | 配合dateext使用,紧跟在下一行出现,定义文件切割后的文件名,必须配合dateext使用,只支持 %Y %m %d %s 这四个参数                                                                                                                        |
| size(或minsize) log-size | 当日志文件到达指定的大小时才转储,log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).当日志文件 >= log-size 的时候就转储。 以下为合法格式:(其他格式的单位大小写没有试过)size = 5 或 size 5 (>= 5 个字节就转储)size = 100k 或 size 100k size = 100M 或 size 100M |

logrotate配置文件实例

syslog
[root@gop-sg-192-168-56-103 logrotate.d]# cat syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
    missingok
    sharedscripts
    postrotate
    /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}
zabbix-agent
[root@gop-sg-192-168-56-103 logrotate.d]# cat zabbix-agent
/var/log/zabbix/zabbix_agentd.log {
    weekly
    rotate 12
    compress
    delaycompress
    missingok
    notifempty
    create 0664 zabbix zabbix
}
nginx
[root@gop-sg-192-168-56-103 logrotate.d]# cat nginx
/var/log/nginx/*.log /var/log/nginx/*/*.log{
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
        [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
    endscript
}
influxdb
[root@gop-sg-192-168-56-103 logrotate.d]# cat influxdb
/var/log/influxdb/influxd.log {
    daily
    rotate 7
    missingok
    dateext
    copytruncate
    compress
}

关于 USR1 信号解释

  • USR1 亦通常被用来告知应用程序重载配置文件;例如,向 Apache HTTP 服务器发送一个 USR1 信号将导致以下步骤的发生:停止接受新的连接,等待当前连接停止,重新载入配置文件,重新打开日志文件,重启服务器,从而实现相对平滑的不关机的更改。

  • 对于 USR1 和 2 都可以用户自定义的,在 POSIX 兼容的平台上,SIGUSR1 和 SIGUSR2 是发送给一个进程的信号,它表示了用户定义的情况。它们的符号常量在头文件 signal.h 中定义。在不同的平台上,信号的编号可能发生变化,因此需要使用符号名称。

kill -HUP pid
killall -HUP pName

其中 pid 是进程标识,pName 是进程的名称。

如果想要更改配置而不需停止并重新启动服务,可以使用上面两个命令。在对配置文件作必要的更改后,发出该命令以动态更新服务配置。根据约定,当你发送一个挂起信号 (信号 1 或 HUP) 时,大多数服务器进程 (所有常用的进程) 都会进行复位操作并重新加载它们的配置文件。

logrotate日志切割轮询

由于 logrotate 是基于 cron 运行的,所以这个日志轮转的时间是由 cron 控制的,具体可以查询 cron 的配置文件 /etc/anacrontab,过往的老版本的文件为(/etc/crontab)

查看轮转文件:/etc/anacrontab

[root@gop-sg-192-168-56-103 logrotate.d]# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22

#period in days   delay in minutes   job-identifier   command
1   5   cron.daily      nice run-parts /etc/cron.daily
7   25  cron.weekly     nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly        nice run-parts /etc/cron.monthly

使用 anacrontab 轮转的配置文件,日志切割的生效时间是在凌晨 3 点到 22 点之间,而且随机延迟时间是 45 分钟,但是这样配置无法满足我们在现实中的应用

现在的需求是将切割时间调整到每天的晚上 12 点,即每天切割的日志是前一天的 0-24 点之间的内容,操作如下:

mv /etc/anacrontab /etc/anacrontab.bak //取消日志自动轮转的设置

使用 crontab 来作为日志轮转的触发容器来修改 logrotate 默认执行时间

[root@gop-sg-192-168-56-103 logrotate.d]# vim /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
59 23 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly