背景

换过几个云服务器,每次都要在 crontab 这折腾一会儿,这次索性把问题记录下来,力求详尽。

笔者的云服务器:腾讯云 2C4G;

Linux 系统: Ubuntu 20.04 LTS 64bit。

crontab 是 Linux 下周期性执行的指令,常常在后台运行,每一分钟检查是否有预定的作业需要执行。这类作业一般称为 cron jobs。(摘自百度百科)

必备知识

1、cron 的配置文件可在三个地方存放

  • /var/spool/cron/crontabs/root
  • /etc/crontab
  • /etc/cron.d/

​ 一般情况下,通过 crontab -e 命令编辑的是第一个路径下的配置文件,在这里的命令不需要指定用户为 root;后两个则需要,比如命令 0 3 * * 1 root python test.py,其中的 root 不可少。

需要注意的是,如果使用 crontab -e 编辑,修改后使用 Ctrl+X,提示:save modified buffer ...? ,选择 :yes,又提示:file name to write ,选择:Ctrl+T,在最后一个界面使用左右箭头切换至 crontab。

2、虽然说编辑完 crontab 文件后不需要重启 cron 服务,但是包括重启在内的一些命令最好还是了解下。

  • 重启,各种资料都说是 service crond restart,在笔者的环境上实测是 service cron restart;在 centos 上是 systemctl restart crond,笔者暂未考证。
  • 状态,笔者亲测为 service cron start;其他环境同上。

问题记录

使用命令定时执行 python 脚本,每个小时的第 15 分钟运行一次,无任何反应。命令如下:

15 * * * * /mypath/venv/bin/python3 /mypath/monitor.py >> /mypath/execute.log 2>&1

python 脚本输出的 execute.log 亦无输出。

问题解决

第一步想着查看 crontab 的日志,才知道默认是不打开的需要手动配置。命令如下:

1
2
3
4
5
sudo vim /etc/rsyslog.d/50-default.conf
cron.* /var/log/cron.log #将cron前面的注释符去掉
#重启rsyslog
sudo service rsyslog restart
sudo service cron restart

然后 vi /var/log/cron.log 查看日志,能够发现脚本确实运行了,除此之外没有任何有用信息,看其他博主(参考文末链接2)说是需要安装 postfix,正安装着不知道怎么配置邮件服务器的域名,又看到如果 python 脚本输出配置了重定向日志,不用配这个也行。遂作罢。

排除了 crontab 的问题,那只有是 python 脚本的问题了,偶然间发现(参考文末链接 3):python 脚本中涉及到读写文件的动作,一般定时任务都不会执行.;脚本在执行时,由于是通过 crontab 去执行的,它的执行目录会变成当前用户的根目录,如果是root,就会在/root/下执行。

但是我们读写的文件路径在 root 下吗,大概率不是,一种解决办法是将 python 脚本中的文件路径全部换成服务器绝对路径,但是这样可移植性差;更好的办法是使用 shell 脚本,shell 脚本第一行使用命令 cd 到我们的目的路径,然后第二行修改我们原来的命令(py 脚本的绝对路径也可以简化成相对路径),如下:

1
2
3
#!/usr/bin/bash
cd /mypath
/mypath/venv/bin/python3 /monitor.py

使用 chmod a+x test.sh 赋予执行权限,然后在 crontab 配置定时运行这个 shell 脚本,

1
15 * * * * /bin/sh /mypath/test.sh >> /mypath/execute.log 2>&1

最后可能还有一个坑,查看 execute.log,发现无法 cd 到 mypath,这是因为这个 test.sh 是通过 rz 上传的,不是在服务器上通过 touch 创建的,无法识别,解决办法就在原因中,touch 创建再复制命令就行。

参考

1、一个 crontab 的坑

2、迷之 crontab 异常:不运行、不报错、无日志

3、crontab运行python脚本不生效问题