阿猫的博客

阿猫的博客

Docker使用cron运行定时任务

1281
2022-02-19

概述

在有Docker之前,环境的部署实在是噩梦,尤其是像Python这一类环境管理非常恶心的。使用Docker完美地解决了部署的问题。最近在写一个需要定时爬取的爬虫,爬虫的代码已经编写好,现在需要每天中午12点自动运行一下这个爬虫更新新一天的数据。定时任务一事,很自然就想到使用cron来解决。由于对cron的不熟悉,中途还是踩了一点坑,记录一下中途遇到的一些坑点。

TL;DR

先创建一个crontab,就一个纯文本文件,写上需要的cron表达式。

# crontab
0 12 * * * EXEC_USER SOME_COMMAND >> /var/log/cron.log 2>&1

然后写Dockerfile

# 我这里需要用到python环境,用的python镜像,底层是Debian(bullseye)
FROM python:3.7
RUN apt-get update && apt-get -y install cron tzdata
# 安装tzdata,结合环境变量将容器时间调整为北京时间(默认为UTC时间)
ENV TZ Asia/Shanghai
# 创建log,防止后面因为文件不存在报错
RUN touch /var/log/cron.log
# 将cron复制到cron.d,名字随便取,这里叫app-cron
COPY crontab /etc/cron.d/app-cron
... # do whatever you need
# 将cron放在前台运行
CMD ["cron", "-f"]

cron不是镜像里的标配

Docker镜像为了精简大小,会保留相对最少的依赖,因此需要安装一下cron。

# 修改为国内源,加速下载
RUN sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list
RUN apt-get update && apt-get -y install cron

默认为UTC时间

Docker容器无法获取主机的时区,因此会以UTC时间运行(北京时间是东八区,UTC +8,因此会相差8个小时),一般而言不影响使用,但若对时间概念有需求则需要调整为对应的时区。

需要另外安装tzdata,这个加在上面就可以了。

# 指定一下默认时区
ENV TZ Asia/Shanghai

这时候如果需要设置容器为其他时区,只需要创建容器时-e TZ=Asia/Singapore设定即可。

cron表达式

cron表达式的参数要记得,分时日月周,用户名和命令。

需要注意,如果需要使用重定向(例如输出日志),>>为append模式,>为w模式(清除原有内容)。同时,所有的路径最好使用绝对路径,如/usr/local/bin/python/var/log/cron.log

* * * * * EXEC_USER SOME_COMMAND

最后的命令

一开始以为让容器运行cron就可以了,写成了

RUN cron

结果容器一启动就退出了,还是状态0(正常退出)。这里误解了CMDRUN,还有类似的ENTRYPOINT,他们的区别和用法如下。

  • RUN命令执行命令并创建新的镜像层,通常用于安装软件包,或进行一些文件操作
  • CMD命令设置容器启动后默认执行的命令及其参数,但CMD设置的命令能够被docker run命令后面的命令行参数替换
  • ENTRYPOINT配置容器启动时的执行命令(不会被忽略,一定会被执行,即使运行 docker run时指定了其他命令)

改成以下就可以达到预期的效果了。这行的意思是容器启动时让cron在前台运行。

CMD ["cron", "-f"]

其实还有另一种写法,也能达到同样的效果。但是相较上一种写法,这种写法在cron里面的任务运行出错时,让cron退出而容器还是正常运行的状态,不利于状态的监控(例如原本监控容器退出可以自动重启)。

CMD cron && tail -f /var/log/cron.log

具体的讨论可以见:https://stackoverflow.com/questions/37458287/how-to-run-a-cron-job-inside-a-docker-container

更多资料

How to run a cron job inside a docker container?

确切地解决了我的问题,也是本文主要的参考。

Running Cron in Docker https://github.com/AnalogJ/docker-cron

介绍在不同发行版镜像上运行cron的文章及其仓库。

如何查看crontab的日志记录

介绍查看cron执行日志的几种方法,方便debug。