Python定时任务执行shell脚本切割Nginx日志(慎用)
缘起
我们有一个Nginx服务用来接收埋点上报数据,输出的日志文件比较大,Nginx没有自带日志分割组件,这样输出的日志文件就比较大,抽取日志就比较麻烦。 网上切割日志的方式一般就两种:logratate和crontab+shell脚本 我这里探索的是第二种方式,中间踩了一些坑,记录一下。
环境
- aliyunk8s
- openresty 1.7.x
- python2.7
- 容器基础镜像为debian10
过程
1. crontab + shell
首先写分割日志的脚本如下(文件名为cut_and_del_log_file.sh
):#!/bin/bash # 初始化 LOGS_PATH=/opt/app/logs CURRENT_TIME=$(date +%Y%m%d%H%M%S) logFileList=(access error)
for fileIterm in ${logFileList[@]} do currentLogFileBaseName=${fileIterm} currentPathFileName=${LOGS_PATH}/${currentLogFileBaseName}.log echo "["${CURRENT_TIME}"]" "当前处理文件 "${currentPathFileName} if [ -s $(echo $currentPathFileName) ]; then afterReNameFileName=${LOGS_PATH}/${currentLogFileBaseName}_${CURRENT_TIME}.log echo "["${CURRENT_TIME}"]" "移动后文件名 "${afterReNameFileName} mv ${currentPathFileName} ${afterReNameFileName} fi done
#向nginx主进程发送USR1信号,重新打开日志文件,否则会继续往mv后的文件写数据的。原因在于:linux系统中,内核是根据文件描述符来找文件的。如果不这样操作导致日志切割失败。
kill -USR1 ps axu | grep "nginx: master process" | grep -v grep | awk '{print $2}'
#删除2天前的日志 cd ${LOGS_PATH} find . -mtime +2 -name "*.log" | xargs rm -f
exit 0
使用crontab 执行这段脚本就大功告成了,但是,遇到的第一个问题是我在容器里执行脚本的时候报错:
```log
Syntax error: "(" unexpected
查了下是因为debian系统默认使用dash替换bash,可以通过:
dpkg -reconfigure
然后输入no
就可以了,但无论是dockerfile还是启动脚本,都做不到,然后采用第二种方法,执行以下脚本:
rm /bin/sh
ln -s /bin/bash /bin/sh
直接进入docker容器内部执行没问题,但是发布的时候也不能进容器去做这个操作啊,于是决定放在dockerfile里面,但是执行完rm /bin/sh
就会提示无法执行ln
命令,原因是sh
找不到了,妹的。于是我放在了容器启动脚本中,但是也没用,因为提示没有rm
权限(我们k8s里面启动的默认账户不是root),于是想到了一个办法,既然先删除后链接不行,那就执行更新好了,dockerfile添加命令:
RUN ln -snf /bin/bash /bin/sh
于是完美解决这个问题。 然后又遇到了crontab启动权限问题 我的dockerfile中crontab配置脚本是
# op_user是我将来启动容器的用户 如果你使用root的话 op_user替换成root即可
RUN echo "0 */4 * * * sh /opt/app/cut_and_del_log_file.sh > /opt/app/logs/cut.log 2>&1" > /var/spool/cron/crontabs/op_user
容器启动脚本是:
ENTRYPOINT ["sh","/opt/app/start.sh"]
/opt/app/start.sh
这个文件内容是:
nohup service cron start &
nginx -g "daemon off;"
然后提示我没权限启动cron
,服了,这定时任务,crontab
没机会了。
2. python + shell
于是使用了python
,首先dockerfile安装python环境:
# 安装python环境和pip
RUN apt-get update -y && apt-get install python2.7 python-pip --no-install-recommends -y
# 安装python组件schedule
RUN pip install schedule -i http://mirrors.cloud.aliyuncs.com/pypi/simple --trusted-host mirrors.cloud.aliyuncs.com
python脚本如下(文件名为 loopCut.py
):
# -*- coding: UTF-8 -*-
import schedule
from datetime import datetime
import os
def job():
now = datetime.now()
dateTimeStr = now.strftime("%Y-%m-%d %H:%M:%S")
print("start cut log shell ",dateTimeStr)
os.system("sh /opt/app/cut_and_del_log_file.sh >> /opt/app/logs/cut.log")
print("end cut log shell")
def func():
schedule.clear()
schedule.every(4).hours.do(job)
while True:
schedule.run_pending()
func()
容器中启动脚本为:
nohup python loopCut.py 2>&1 &
nginx -g "daemon off;"
dockerfile中的ENTRYPOINT
命令不变,发布后可以正确切割日志了
至此搞定此项任务。
------------------------------------------------20230216分界线------------------------------------------------
python这个schedule框架似乎有点问题,发布后会吃满一个CPU核心资源,慎用
------------------------------------------------20230313分界线------------------------------------------------
最后还是说服了security团队和运维团队的人,给加了crontab的支持
将以下内容保存为文件schedulefile
0 */4 * * * sh /opt/app/cut_and_del_log_file.sh > /opt/app/logs/cut.log 2>&1
然后dockerfile加上:
# 安装cron
RUN apt-get update -y && apt-get install --fix-missing cron -y
# 拷贝上面的文件到 /opt/app/下
COPY schedulefile /opt/app/
# 将上面的文件内容应用到crontab
RUN crontab -u root /opt/app/schedulefile
容器启动脚本如下:
service cron start && nginx -g "daemon off;"