我的实用工具库(1) - 自动加载执行 crontab 定时任务的 docker 镜像

pycron 顾名思义,python + crontab,是一个包含 Python 3 运行时的 docker 镜像,用来执行 crontab 配置文件中的定时任务。

缘起

MetaTool 有两个小工具,分别是 微博舆情统计信息 和 QQ音乐专辑单链销量,后端数据都是通过爬虫定时爬取的。爬虫脚本使用 Python 3 编写,通过 crontab 定时执行。

因为可能部署到多个云服务器,或者有时会更换云服务器,任务也会随时增删,就需要一种便捷的部署方式,最好随意复制一键启动,很自然就用到了 docker 镜像。

使用

先看一下 docker 运行命令:

1
2
3
4
5
6
7
docker run \
--name pycron \
--restart=always \
--volume $PWD/script:/data/script \
--network net_cron \
--detach \
kaleofeng/pycron:1.0-SNAPSHOT

镜像定义了一个数据卷,crontabs 配置文件和所有用户脚本等都放在该目录下。

下面是一个使用中状态的数据目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
pycron/
└── script
├── conf
│ └── db.conf
├── crontabs
└── qmusic
├── data
│ ├── qmusic_singerstat_2020-05-20-23-59-00.xls
│ ├── qmusic_singerstat_2020-05-21-23-59-00.xls
│ └── qmusic_singerstat_2020-05-22-23-59-00.xls
├── log
│ └── singerstat.log
└── singerstat.py

看一下 crontabs 配置文件内容:

1
59 23 * * * flock -xn /tmp/singerstat.lock -c 'timeout 5m /usr/bin/python3 /data/script/qmusic/singerstat.py >> /data/script/qmusic/log/singerstat.log 2>&1'

示例里只有一个定时任务:每日23点59分调用 singerstat.py 爬取相关数据。

需要注意的是,该配置文件只能使用 unix 换行符 \n,不要使用 \r\n

配置好定时任务,保证相关脚本可以正确执行。启动镜像,镜像会自动读取数据目录下的配置文件,生成 crontab 任务,定时执行,就像普通 linux 系统中的 crontab 任务一样。

实现

看一下 docker 镜像的 Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FROM centos:8

LABEL maintainer="KaleoFeng" \
version="1.0-SNAPSHOT" \
description="Crontab with Python 3 on CentOS 8"

USER root

RUN \cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

RUN dnf -y module install python36; \
pip3 install pymysql; \
pip3 install xlwt; \
pip3 install requests; \
dnf -y install cronie crontabs

VOLUME [ "/data/script" ]

COPY ./entrypoint.sh .
ENTRYPOINT [ "sh", "./entrypoint.sh" ]

CMD [ "/usr/sbin/crond", "-n" ]

一目了然,该镜像基于 CentOS 8。因为爬虫脚本使用 Python 3,会将爬到的数据写入数据库,并生成 Excel 文件,所以添加了 Python 3 运行时,并安装了 MySQL 读写库 pymysql、Excel 读写库 xlwt 等依赖库。

定义了数据卷 /data/script,宿主机数据目录需要映射到该路径。

镜像入口脚本 entrypoint.sh

1
2
3
4
5
6
7
#!/bin/bash
set -eo pipefail
shopt -s nullglob

crontab /data/script/crontabs

exec "$@"

就是让 crontab 程序读取数据目录下的 crontabs 配置文件来加载定时任务。

镜像默认运行 crond 服务,使用 -n 选项让 crond 作为前台进程运行,这是重点。