如何在 Docker 容器内运行 cron 定时任务?

容器内跑 cron:Dockerfile 装 cron、COPY crontab 文件、入口脚本用 cron -f 前台运行;cron 环境继承取决于实现,应显式传递允许的任务变量。K8s 场景推荐改用 CronJob。本文给出完整 Dockerfile 示例。

最佳实践
如何在 Docker 容器内运行 cron 定时任务?封面

基本步骤:镜像里装 cron → COPY crontab 文件到 /etc/cron.d/ → 专用调度容器里用 cron -f 前台运行;环境继承行为取决于 cron 实现,应显式传递允许的任务变量。不过容器里跑 cron 是妥协方案,K8s 环境优先用 CronJob,单机也可用宿主机 cron 调 docker exec。

完整 Dockerfile 示例

FROM python:3.12-slim

RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

# 拷贝定时任务定义
COPY crontab /etc/cron.d/app-cron
RUN chown root:root /etc/cron.d/app-cron && chmod 0644 /etc/cron.d/app-cron

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]

crontab 文件:

*/10 * * * * root /usr/local/bin/python /app/jobs/run_cleanup.py >> /proc/1/fd/1 2>&1

entrypoint.sh:

#!/bin/bash
set -e
umask 077
/usr/local/bin/python - <<'PYENV'
import json, os
with open('/run/job-env.json', 'w') as f:
    json.dump({k: os.environ[k] for k in ('APP_ENV', 'API_URL') if k in os.environ}, f)
PYENV
exec cron -f                  # 专用调度容器,前台运行

任务包装脚本 /app/jobs/run_cleanup.py:

import json, os, sys
with open('/run/job-env.json') as f:
    allowed = json.load(f)
env = {**os.environ, **allowed}
os.execve(sys.executable, [sys.executable, '/app/jobs/cleanup.py'], env)

/etc/cron.d 文件使用系统格式,必须有用户字段且末尾换行,不能再用 crontab 命令当用户表重复安装。

三个必踩的坑

  1. 环境变量:按实现核对环境;示例只将允许的变量存成权限受控 JSON,避免 printenv 内容被当 shell 代码执行
  2. 任务输出:cron 默认可能通过邮件投递输出,但容器未必配置了可用的邮件服务,重定向到 /proc/1/fd/1(主进程 stdout),这样 docker logs 和日志采集能拿到
  3. 双进程:若必须同时运行 cron 和应用,需要明确的监督与信号转发;上例专用调度容器不再启动 app.py

任务输出应带上任务名、执行时间和最终结果,并确认在容器日志中可见。用 DataKit接入观测云后,可按实际调度周期配置日志检测及无数据通知,窗口中留出执行与采集延迟。收到无成功记录的通知时,再区分任务未启动、执行失败和采集链路中断。

更推荐的替代方案

方案 适用
K8s CronJob K8s 环境首选,任务独立 Pod,可显式配置环境变量;调度不保证恰好一次执行,任务须幂等并处理重叠
宿主机 cron + docker exec 单机少量任务,容器保持单进程
应用内调度器 APScheduler / node-cron,与应用同进程

常见问题(FAQ)

Q:cron 容器时区不对?
A:镜像默认 UTC,挂载 -v /etc/localtime:/etc/localtime:ro 或镜像里设置 TZ 环境变量并装 tzdata。

Q:任务没执行怎么查?
A:进容器 grep CRON /var/log/syslog(需 rsyslog)或直接看重定向到 stdout 的输出;先手动跑一遍命令确认命令本身没问题。

Q:Alpine 镜像怎么装 cron?
A:Alpine 自带 crond(busybox),crond -f 前台启动即可,crontab 文件放 /etc/crontabs/root。

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台