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
至此,实现了容器内服务日志的自动轮转。
docker中实现服务日志轮转的更多相关文章
- 滚动 docker 中的 nginx 日志
Nginx 自己没有处理日志的滚动问题,它把这个球踢给了使用者.一般情况下,你可以使用 logrotate 工具来完成这个任务,或者如果你愿意,你可以写各式各样的脚本完成同样的任务.本文笔者介绍如何滚 ...
- logrotate日志轮转
1)基本介绍 适合应用服务日志,系统日志按天切割 如果没有日志轮转,日志文件会越来越大 将丢弃系统中最旧的日志文件,以节省空间 logrotate本身不是系统守护进程,它是通过计划任务crond每天执 ...
- docker-compose EFK查看docker及容器的日志
上一篇<docker-compose ELK+Filebeat查看docker及容器的日志>已经演示了如何在docker中使用docker-compose创建容器,并将docker中的所有 ...
- 【docker】【redis】2.docker上设置redis集群---Redis Cluster部署【集群服务】【解决在docker中redis启动后,状态为Restarting,日志报错:Configured to not listen anywhere, exiting.问题】【Waiting for the cluster to join...问题】
参考地址:https://www.cnblogs.com/zhoujinyi/p/6477133.html https://www.cnblogs.com/cxbhakim/p/9151720.htm ...
- docker中怎样设置开机启动--随容器的启动而启动服务?
docker可以说给我们的部署带来极大的方便和可逢凶化吉性!(懂的同学自然懂) 在初步了解之后,我们就能简单使用docker了. 刚开始玩docker时,可以基于系统级别的镜像做定制,比如基于 ce ...
- 如何在Python中使用ZeroMQ和Docker构建微服务架构
@Container容器技术大会将于6月4日在上海光大会展中心国际大酒店举办,来自携程.PPTV.蚂蚁金服.京东.浙江移动.海尔电器.唯品会.eBay.道富银行.麻袋理财等公司的技术负责人将带来实践经 ...
- docker swarm英文文档学习-8-在集群中部署服务
Deploy services to a swarm在集群中部署服务 集群服务使用声明式模型,这意味着你需要定义服务的所需状态,并依赖Docker来维护该状态.该状态包括以下信息(但不限于): 应该运 ...
- docker微服务部署之:四、安装docker、docker中安装mysql和jdk1.8、手动构建镜像、部署项目
docker微服务部署之:三,搭建Zuul微服务项目 1.Centos7安装Docker 详见:Centos7安装Docker 2.Docker中安装jdk1.8 详见:使用Docker构建jdk1. ...
- python日志轮转RotatingFileHandler在django中的一个bug
简介 大量过时的日志会占用硬盘空间,甚至长时间运行不注意会占满硬盘导致宕机,那么就可以使用内建logging模块根据文件大小(logging.handlers.RotatingFileHandler) ...
随机推荐
- JS进阶系列之闭包
刚刚总结完作用域链,我觉得很有必要马上对闭包总结一下,因为,之前也写过自己对闭包的理解,那时候只知道,闭包就是可以访问别的函数变量的函数,就是在函数里面的函数就叫做闭包,可是并没有深入探究,为什么,可 ...
- sprint2(第九天)
今天是sprint2的最后一天,已经完成功能有可以实现点餐功能.菜品的添加和删减.菜品数量的增减.添加备注.查看订单详情.订单状态.提交订单.后厨可以查看订单信息,对菜品的状态进行操作,是否完成烹饪, ...
- Aspose.words Java基于模板生成word之循环图片
1.新建一个word文档 2.给插入图片的地方设置书签 3,设置书签 二,项目 1,2步的引入依赖以及加载授权文件同上一篇 3,获取图片路径插入到word中并生成新的word文档 新文档中,每行显示两 ...
- wdatepicker控件de使用小方法汇总
在总结wdatepicker控件的使用前,先插播一条吧,下午刚心血来潮百度的一条 问?C#中Int16.Int32.Int64.之间的区别,:::嘿嘿其实百度知道就有,但还是写上吧! Int16 表示 ...
- C++自学随笔
主要学习内容: 了解了IDE环境的含义 C++与C的区别: 新的数据类型:bool型 新的初始化方法:直接初始化int x(1024) 经过查找,了解了直接初始化与复制初始化的区别:"当用于 ...
- “吃神么,买神么”的第二个Sprint计划(计划过程内容)
“吃神么,买神么”项目Sprint计划 ——6.1(第二天)立会内容与进度 团队组员各自任务: 陈键.吴舒婷:继续完善前台设局与布局 林欢雯.冯美欣:开展后台的界面的设计与布局 任务的进度: 陈键. ...
- KEIL C51代码优化详细分析
阅读了<单片机与嵌入式系统应用>2005年第10期杂志<经验交流>栏目的一篇文章<Keil C51对同一端口的连续读取方法>(原文)后,笔者认为该文并未就此问题进行 ...
- Beta阶段——第一篇 Scrum 冲刺博客
i. 提供当天站立式会议照片一张: ii. 每个人的工作 (有work item 的ID) (1) 昨天已完成的工作: 数据存储方式改本地存储为数据库存储. (2) 今天计划完成的工作: 账单和剩余舍 ...
- 9th 学习博客:使用Codebloks实现C++的图形化界面
使用开发工具codeblocks,添加ResEdit.exe这个控件,可以很方便地进行图形化编辑,这是在网上找得教程,实现的是最基本的在对话框内添加按钮,并实现单击响应在控制台输出相应的文字. mai ...
- 如何提高cxgrid的刷新速度
如果View的类型是cxGridDBTableView: 1.cxGrid.DisableControls;cxGrid.EnableControls; 如仍觉得慢,可以把 cxGrid1DBTabl ...