如何在 Docker 中安全运行 cron 任务(带监控)

发布: (2025年12月10日 GMT+8 04:33)
5 min read
原文: Dev.to

Source: Dev.to

封面图片:安全在 Docker 中运行 cron 任务(带监控)

系统 cron 的问题

cron 守护进程是为传统 Linux 服务器设计的,而不是容器:

# ❌ Don't do this
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y cron
COPY mycron /etc/cron.d/mycron
RUN crontab /etc/cron.d/mycron
CMD cron -f

出现的问题

  • 没有日志 – cron 将日志写入 syslog,而不是 stdout
  • 信号处理不佳SIGTERM 不能优雅地停止任务。
  • 环境变量地狱 – cron 不会继承 Docker 的 ENV 变量。
  • PID 1 问题 – 如果 cron 是 PID 1,信号处理会失效。

解决方案:Supercronic

Supercronic 是为容器重新构想的 cron:

# ✅ Do this instead
FROM php:8.2-cli

ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 \
    SUPERCRONIC=supercronic-linux-amd64 \
    SUPERCRONIC_SHA1SUM=cd48d45c4b10f3f0bfdd3a57d054cd05ac96812b

RUN 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

COPY crontab /app/crontab
CMD ["supercronic", "/app/crontab"]

Supercronic 的 crontab 语法

# /app/crontab
*/15 * * * * php /app/bin/console app:import-data
0 2 * * * /app/scripts/backup.sh
0 */4 * * * php /app/bin/console cache:clear

优势

  • ✅ 日志输出到 stdoutdocker logs 可用)。
  • ✅ 在收到 SIGTERM 时优雅关闭。
  • ✅ 自动继承 Docker ENV
  • ✅ 单进程,无守护进程的复杂性。

在容器中运行的 Symfony 示例应用

Dockerfile

FROM php:8.2-cli

# Install Supercronic
ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64
RUN curl -fsSLO "$SUPERCRONIC_URL" \
 && chmod +x supercronic-linux-amd64 \
 && mv supercronic-linux-amd64 /usr/local/bin/supercronic \
 && apt-get update && apt-get install -y git curl unzip

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Application
COPY . /app
WORKDIR /app
RUN composer install --no-dev --optimize-autoloader

COPY docker/crontab /app/crontab
CMD ["supercronic", "/app/crontab"]

docker/crontab

# Process message queue
* * * * * php /app/bin/console messenger:consume async --time-limit=3600

# Send scheduled emails
*/5 * * * * php /app/bin/console app:send-emails

# Generate daily reports
0 6 * * * php /app/bin/console app:generate-reports

# Cleanup old data
0 3 * * * php /app/bin/console cache:clear

docker-compose.yml

version: '3.8'

services:
  app:
    build: .
    # ... your app service

  cron:
    build: .
    container_name: app-cron
    restart: unless-stopped
    env_file: .env
    depends_on:
      - db
      - redis
    networks:
      - app-network

缺失的环节:监控

Cron 任务可能会悄悄失败。没有监控,你根本不知道任务是否运行,可能导致数据丢失或停机。

解决方案:HTTP ping

使用类似 CronMonitor.app 的服务,在每条命令后发送 ping:

*/15 * * * * php /app/your-command.php && curl -fsS https://cronmonitor.app/ping/{token}

CronMonitor dashboard

你将获得的功能

  • 当任务未正确完成时,通过 Slack/Discord/邮件发送警报。
  • 仪表盘展示所有任务。
  • 持续时间和错误跟踪。
  • 无需代理,无额外复杂性。

完整的多容器解决方案示例

docker-compose.yml

version: '3.8'

services:
  # Main application
  app:
    image: myapp:latest
    # ...

  # Cron worker for background jobs
  cron-worker:
    build:
      context: .
      dockerfile: docker/Dockerfile.cron
    container_name: myapp-cron
    restart: unless-stopped
    env_file: .env
    depends_on:
      - db
      - redis
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

docker/Dockerfile.cron

FROM php:8.2-cli

# Supercronic
RUN curl -L https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 \
    -o /usr/local/bin/supercronic && chmod +x /usr/local/bin/supercronic

# App dependencies
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get install -y git curl unzip libzip-dev \
    && docker-php-ext-install pdo_mysql zip

# Application
COPY composer.* /app/
WORKDIR /app
RUN composer install --no-dev --no-scripts --optimize-autoloader

COPY . /app
RUN composer dump-autoload --optimize

COPY docker/crontab /app/crontab
CMD ["supercronic", "-debug", "/app/crontab"]

docker/crontab(带监控)

# Queue processor - critical, monitor closely
* * * * * curl -fsS https://cronmonitor.app/ping/{token} && php bin/console messenger:consume --time-limit=3600

# Hourly data sync
0 * * * * curl -fsS https://cronmonitor.app/ping/{token} && php bin/console app:sync-data || curl -fsS https://cronmonitor.io/fail/sync-def456

# Daily backup - MUST succeed
0 2 * * * curl -fsS https://cronmonitor.app/ping/{token} && /app/scripts/backup.sh

# Weekly cleanup
0 3 * * 0 curl -fsS https://cronmonitor.app/ping/{token} && php bin/console app:cleanup

调试技巧

# 实时查看日志
docker logs -f myapp-cron

# 测试单个命令
docker exec myapp-cron php bin/console app:your-command

# 检查环境变量
docker exec myapp-cron env | grep DATABASE

# 手动 crontab 测试
docker exec myapp-cron supercronic -test /app/crontab

迁移清单

  • 用 Supercronic 替换系统 cron 守护进程。
  • 将 crontab 文件移入容器,并在 CMD 中引用。
  • 确保所有必需的环境变量已在 Dockerfile 或 docker‑compose 文件中设置。
  • 为每个任务添加 HTTP ping 调用(或其他监控钩子)。
  • 验证日志能通过 docker logs 查看。
  • 测试优雅关闭(docker stop),确认任务收到 SIGTERM
  • 在 CronMonitor(或你偏好的监控服务)中设置警报。
Back to Blog

相关文章

阅读更多 »