實現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 "[email protected]"
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

至此,實現了容器內服務日誌的自動輪轉。

本文地址:https://www.linuxprobe.com/docker-logrotate-crontab.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章