Docker容器中的定时任务:使用Supercronic运行Python脚本
告别Docker内Cron的环境变量烦恼,Supercronic成为更优选择
在上一篇文章中,我介绍了 eudic-maimemo-sync 项目——利用 Python 脚本调用欧路词典和墨墨背单词的开放API将生词本自动同步到墨墨背单词,并演示了如何用 Docker 将其部署到树莓派上,每天自动执行同步。
这篇文章,我想分享我在配置 Docker 容器实现定时任务时遇到的一个问题,以及我是如何解决它的:我最初在容器内使用标准的 Cron 服务来调度 Python 脚本。但我发现,即使把环境变量传入了容器,Cron 触发脚本时依然读不到这部分配置,导致 Python 读取不到 API 密钥。原因是 Cron 不会继承容器的环境变量,它运行在相对隔离的环境中。
为了解决这个问题,我开始在网上搜索并向大语言模型求助,最后得到几个可能的方案:
- 将
.env
文件直接挂载进容器,让脚本从指定路径读取 - 在
entrypoint.sh
文件中,读取环境变量,然后显式地将它们写入 crontab 文件或注入到 Cron 进程环境中 - 使用 Supercronic 或其他替代 Cron 方案
虽然前两种方法可行,但需要额外的配置和脚本处理。经过测试,我最终选择了 Supercronic。它是一个与 Cron 语法兼容、专为容器设计的任务调度工具,用法和原生 Cron 几乎一致,且能够直接继承容器内的环境变量,大大简化了配置过程。将 Cron 替换为 Supercronic 后,问题就迎刃而解了。
如果你有同样的需求,想要通过容器定时运行 Python 脚本或其他程序,我推荐试试 Supercronic。我精简了eudic-maimemo-sync 项目,编写一个基础示例 docker-python-supercronic-example。示例中展示了如何在 Docker 容器里配置 Supercronic,并定时执行 Python 脚本,供大家参考。
接下来我讲讲如何使用这个示例:
.
├── Dockerfile # 用于构建包含 Supercronic 的 Python 镜像
├── docker-compose.yml # 容器部署的配置
├── entrypoint.sh # 生成 crontab 并启动 Supercronic 的脚本
├── test.py # 按计划运行的示例 Python 脚本
└── requirements.txt # Python 依赖项
开始使用
克隆此仓库
git clone https://github.com/emuqi/docker-python-supercronic-example.gitcd docker-python-supercronic-example为你的架构选择 Supercronic
Dockerfile 默认配置为 ARM64 架构。对于其他架构(例如 x86_64),需要修改
Dockerfile
:访问 Supercronic Releases,找到适合你的 CPU 架构的 安装说明。安装说明内一般会包含要添加到 Dockerfile 的代码。
替换以下部分:
# 最新版本请访问 https://github.com/aptible/supercronic/releases# 根据你的CPU架构选择合适的 Supercronic 版本ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.33/supercronic-linux-arm64 \SUPERCRONIC_SHA1SUM=e0f0c06ebc5627e43b25475711e694450489ab00 \SUPERCRONIC=supercronic-linux-arm64RUN curl -fsSLO "$SUPERCRONIC_URL" \&& echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \&& chmod +x "$SUPERCRONIC" \&& mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \&& ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic创建
.env
文件用于设置环境变量CUSTOM_MESSAGE=来自计划任务的问候! CRON_SCHEDULE=*/5 * * * * # 每 5 分钟运行一次
构建并启动容器
docker compose up -d --build检查日志以验证程序是否按预期运行
docker logs my_python_cron_job你应该能看到类似下面的日志输出:
my_python_cron_job | time="2025-04-23T18:53:00+08:00" level=info msg="Python script start" channel=stdout iteration=0 job.command="/usr/local/bin/python /app/test.py" job.position=0 job.schedule="* * * * *" my_python_cron_job | time="2025-04-23T18:53:00+08:00" level=info msg="Message: Hello World!" channel=stdout iteration=0 job.command="/usr/local/bin/python /app/test.py" job.position=0 job.schedule="* * * * *" my_python_cron_job | time="2025-04-23T18:53:00+08:00" level=info msg="job succeeded" iteration=0 job.command="/usr/local/bin/python /app/test.py" job.position=0 job.schedule="* * * * *"
配置
环境变量
变量 | 描述 |
---|---|
TZ |
容器时区 |
CRON_SCHEDULE |
用于调度的 Cron 表达式 |
CUSTOM_MESSAGE |
传递给 Python 脚本的示例变量 |
Cron 计划表达式示例
* * * * *
- 每分钟*/5 * * * *
- 每 5 分钟0 * * * *
- 每小时(0分时)0 0 * * *
- 每天午夜0 18 * * *
- 每天下午 6:00
自定义
- 用你自己的 Python 脚本替换或修改
test.py
- 通过编辑
.env
文件或docker-compose.yml
中的environment:
部分来扩展或覆盖变量。添加的任何新变量(例如NEW_VAR=value
)都将被加载到容器中。 - 将所需的任何依赖项添加到
requirements.txt
- 重新构建并运行容器:
docker-compose up -d --build