python定时任务执行shell脚本切割Nginx日志-慎用

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 执行这段脚本就大功告成了,但是,遇到的第一个问题是我在容器里执行脚本的时候报错:

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;"

你可能感兴趣的:(python,JAVA,linux,python,nginx,docker)