zoukankan      html  css  js  c++  java
  • docker中实现服务日志轮转

    问题背景

    通常我们一个完整的应用镜像有两部分组成,一个是运行时环境,一个是应用程序。我们以php应用为例,一个完整的php应用需要包含openresty + php两个服务来配置运行时环境,然后再加上php代码,来完成一整个php应用的发布。php代码产生的日志由程序自行控制,一般都会按天滚动,在日志量较大的情况下,也可能按小时滚动,或者按照单个日志文件的大小来实现滚动。而nginx和php服务的日志默认情况下并不支持这种滚动,所以默认情况下,一个openresty+php容器在其生命周期内,就只会写一个日志文件,如果该容器长时间运行,openresty与php服务的访问日志就会变的非常巨大,给我们日志清理造成了不便。

    logrotate + crontab

    虽然默认情况下,openresty和php等服务的访问日志并不会自动滚动,但我们却可以使用一些第三方工具来实现。在传统的应用部署中,我们使用logrotate + crontab来实现openresty 与php等服务的日志滚动。而事实上,这一方案在容器环境下仍然适用。我们的解决方案是,在每个服务的基础镜像中配置好logrotate和crontab,这样在容器运行起来后,就会自动根据配置好的轮转策略实现日志滚动。

    配置详细说明

    我们仍然以openresty+php为例,给出一个openresty+php的基础镜像的Dockerfile示例如下:

    MAINTAINER yanwei "yanwei@douyu.tv"
    ENV NGINX_HOME /usr/local/ngx_openresty
    ENV PHP_HOME /usr/local/php7
    RUN groupadd -g 571 www && 
        useradd -u 571 -g 571 www && 
        mkdir -p /home/www/server /home/www/logs/applogs /home/www/logs/srvlogs && 
        yum install -y iproute cronie logrotate
    ADD lib64.tar.gz /
    ADD openresty.tar.gz /
    ADD phpfpm7.tar.gz /
    ADD php.ini $PHP_HOME/etc/php.ini
    ADD phpfpm.conf $PHP_HOME/etc/phpfpm.conf
    ADD nginx.conf $NGINX_HOME/nginx/conf/nginx.conf
    ADD libnsssysinit.so /usr/lib64/libnsssysinit.so
    ADD build.sh /
    ADD run.sh /
    ADD crontab /etc/crontab
    ADD logrotate /etc/cron.daily/logrotate
    ADD logrotate.conf /etc/logrotate.conf
    RUN chown www -R /home/www $NGINX_HOME $PHP_HOME  && 
        chmod +x /build.sh /run.sh /etc/cron.daily/logrotate /usr/lib64/libnsssysinit.so
    EXPOSE 80
    ENTRYPOINT ["/build.sh"]
    CMD ["/run.sh"]
    
    

    在上面的dockerfile中,我们通提取.so文件并打入到镜像中的方式来完成了openresty和php的安装。其中lib64.tar.gz即openresty和php7所依赖的全部.so文件,opernsty.tar.gz和phpfpm7.tar.gz为编译安装后的openresty和php7的代码文件。我们需要注意的大概有如下几个文件:

    build.sh
    run.sh
    crontab
    logrotate
    logrotate.conf
    

    其中run.sh为容器启动时,执行的相关命令,内容如下:

    #!/bin/bash
    PHP_HOME=/usr/local/php7
    /usr/sbin/crond
    $PHP_HOME/sbin/php-fpm -c $PHP_HOME/etc/php.ini -y $PHP_HOME/etc/phpfpm.conf
    /usr/local/ngx_openresty/nginx/sbin/nginx -c /usr/local/ngx_openresty/nginx/conf/nginx.conf -g "daemon off;"
    
    

    这个文件中,启动了三个服务,分别为crond,php-fpm以及openresty。这很好理解,我们需要openresty和php环境以提供基本的php应用的web功能,需要crontab来实现服务的日志轮转。

    logrotate.conf提供logrotate的轮转配置文件,存放到镜像的/etc目录下,内容如下:

    {NGINX_ACCESS_LOG}
    {
            daily
            create 0644 www www
            rotate 7
            missingok
            notifempty
            dateext
            nocompress
            sharedscripts
            postrotate
                    if [ -f /usr/local/ngx_openresty/nginx/var/nginxd.pid ]; then
                    kill -USR1 `cat /usr/local/ngx_openresty/nginx/var/nginxd.pid`
    		fi
            endscript
    }
    {PHPFPM_ACCESS_LOG}
    {PHPFPM_SLOW_LOG}
    {
            daily
            create 0644 www www
            rotate 2
            missingok
            notifempty
            dateext
            nocompress
            sharedscripts
            postrotate
                    if [ -f /usr/local/php7/var/run/php-fpm.pid ]; then
                    kill -USR1 `cat /usr/local/php7/var/run/php-fpm.pid`
                    fi
            endscript
    }
    

    在该配置文件中,定义了对如下三个日志文件做轮转:

    {NGINX_ACCESS_LOG}
    {PHPFPM_ACCESS_LOG}
    {PHPFPM_SLOW_LOG}
    

    可以看到,这三个日志文件在这里并非真正意义上的日志文件路径,而是使用了三个占位符,由于在我们的镜像中,日志文件的路径并不固定,只有在容器启动的那一刻才能确定具体的日志路径。所以我这里采用了docker-entrypoint的方式,在启动的时候,执行build.sh脚本来实现日志路径的替换。build.sh中关于日志部分的定义如下:

    ##############################
    #      log configration      #
    ##############################
    
    PHP_HOME=/usr/local/php7
    phpConfigFile=$PHP_HOME/etc/php.ini
    phpfpmConfigFile=$PHP_HOME/etc/phpfpm.conf
    nginxConfigFile=/usr/local/ngx_openresty/nginx/conf/nginx.conf
    logRotateFile=/etc/logrotate.conf
    
    logDir=/home/www/logs
    appLogDir=${logDir}/applogs
    srvLogDir=${logDir}/srvlogs
    
    if [ ! -z ${POD_NAME} ];then
        host_name=${POD_NAME}
    else
        host_name=$(hostname)
    fi
    
    if [ ! -z $APP_NAME ];then
      export APP_LOG_ROOT_PATH=${appLogDir}/${APP_NAME}/${host_name}
      SRV_LOG_ROOT_PATH=${srvLogDir}/${APP_NAME}/${host_name}
    else
      echo "You must specific variable name APP_NAME"
      exit 1
    fi
    
    nginxLogDir=${SRV_LOG_ROOT_PATH}/nginx
    phpLogDir=${SRV_LOG_ROOT_PATH}/php
    mkdir -p $phpLogDir $nginxLogDir $APP_LOG_ROOT_PATH
    chown www.www -R $phpLogDir $nginxLogDir $APP_LOG_ROOT_PATH
    
    if [ ${LOG_FORMAT}x == "did_format"x ];then
        sed -i "s/{NGINX_LOGFORMAT}/did_format/g" $nginxConfigFile
    else
        sed -i "s/{NGINX_LOGFORMAT}/real_ip/g" $nginxConfigFile
    fi
    
    nginxAccessLog=${nginxLogDir}/nginx.access.log
    nginxErrorLog=${nginxLogDir}/nginx.error.log
    phpfpmErrorLog=${phpLogDir}/phpfpm.error.log
    phpfpmAccessLog=${phpLogDir}/phpfpm.access.log
    phpfpmSlowLog=${phpLogDir}/phpfpm.slow.log
    phpErrorLog=${phpLogDir}/php.error.log
    
    sed -i "s@{NGINX_ERROR_LOG}@${nginxErrorLog}@g" $nginxConfigFile
    sed -i "s@{NGINX_ACCESS_LOG}@${nginxAccessLog}@g" $nginxConfigFile
    sed -i "s@{PHPFPM_ERROR_LOG}@${phpfpmErrorLog}@g" $phpfpmConfigFile
    sed -i "s@{PHPFPM_ACCESS_LOG}@${phpfpmAccessLog}@g" $phpfpmConfigFile
    sed -i "s@{PHPFPM_SLOW_LOG}@${phpfpmSlowLog}@g" $phpfpmConfigFile
    sed -i "s@{PHP_ERROR_LOG}@${phpErrorLog}@g" $phpConfigFile
    
    sed -i "s@{NGINX_ACCESS_LOG}@${nginxAccessLog}@g" $logRotateFile
    sed -i "s@{PHPFPM_ACCESS_LOG}@${phpfpmAccessLog}@g" $logRotateFile
    sed -i "s@{PHPFPM_SLOW_LOG}@${phpfpmSlowLog}@g" $logRotateFile
    
    exec "$@"
    

    定义好了日志轮转的配置文件,接下来就要配置相关计划任务。在我们的配置中,采用了一天一轮转的策略,所以在镜像的/etc/cron.daily中添加logrotate文件,内容如下:

    #!/bin/sh
    
    /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status -f /etc/logrotate.conf
    EXITVALUE=$?
    if [ $EXITVALUE != 0 ]; then
        /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
    fi
    exit 0
    
    

    这个脚本比较简单,就是通过logrotate执行轮转。其中-f表示强制轮转,-s用于记录每一次轮转的状态。

    最后定义具体crontab的执行时间,文件为/etc/crontab,内容如下:

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    
    # For details see man 4 crontabs
    
    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    0 0 * * * root /usr/bin/run-parts /etc/cron.daily
    

    至此,实现了容器内服务日志的自动轮转。

  • 相关阅读:
    成为专业程序员路上用到的各种优秀资料、神器及框架
    深度学习的57个专业术语
    Tensorflow实现Mask R-CNN实例分割通用框架,检测,分割和特征点定位一次搞定(多图)
    Python抓取视频内容
    Dataflow编程模型和spark streaming结合
    开启mysql的远程访问
    OpenSSL拒绝服务漏洞(CNVD-2016-01479)
    多款Apple产品libxml2内存破坏漏洞
    Mozilla Network Security Services拒绝服务漏洞
    Linux kernel 'mq_notify'内存错误引用漏洞
  • 原文地址:https://www.cnblogs.com/breezey/p/8812138.html
Copyright © 2011-2022 走看看