Docker에서 cron 작업을 안전하게 실행하는 방법 (monitoring 포함)

발행: (2025년 12월 10일 오전 05:33 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

Docker에서 cron 작업을 안전하게 실행하기 (모니터링 포함) 커버 이미지

시스템 cron 문제

cron 데몬은 전통적인 Linux 서버용으로 설계되었으며, 컨테이너 환경에 맞지 않습니다:

# ❌ 이렇게 하면 안 됩니다
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은 stdout이 아니라 syslog에 기록합니다.
  • 시그널 처리 불량SIGTERM이 작업을 정상적으로 종료시키지 못합니다.
  • ENV 지옥 – cron은 Docker ENV 변수를 상속하지 않습니다.
  • PID 1 문제 – cron이 PID 1이면 시그널 처리가 깨집니다.

해결책: Supercronic

Supercronic은 컨테이너용으로 재구성된 cron입니다:

# ✅ 대신 이렇게 사용하세요
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

장점

  • ✅ 로그가 stdout으로 출력돼 docker logs 로 확인 가능.
  • SIGTERM 시 정상 종료.
  • ✅ Docker ENV 를 자동으로 상속.
  • ✅ 단일 프로세스, 데몬 복잡성 없음.

컨테이너에서 실행되는 Symfony 샘플 애플리케이션

Dockerfile

FROM php:8.2-cli

# 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

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

# 애플리케이션 복사
COPY . /app
WORKDIR /app
RUN composer install --no-dev --optimize-autoloader

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

docker/crontab

# 메시지 큐 처리
* * * * * php /app/bin/console messenger:consume async --time-limit=3600

# 예약된 이메일 전송
*/5 * * * * php /app/bin/console app:send-emails

# 일일 보고서 생성
0 6 * * * php /app/bin/console app:generate-reports

# 오래된 데이터 정리
0 3 * * * php /app/bin/console cache:clear

docker-compose.yml

version: '3.8'

services:
  app:
    build: .
    # ... 애플리케이션 서비스 설정

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

누락된 요소: 모니터링

Cron 작업은 실패해도 눈에 띄지 않을 수 있습니다. 모니터링이 없으면 작업이 실행되지 않았는지 알 수 없어 데이터 손실이나 다운타임이 발생합니다.

해결책: HTTP 핑

각 명령 실행 후에 CronMonitor.app 같은 서비스를 이용해 핑을 전송합니다:

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

CronMonitor 대시보드

얻을 수 있는 것

  • 작업이 정상적으로 완료되지 않을 경우 Slack/Discord/이메일 알림.
  • 모든 작업을 한눈에 볼 수 있는 대시보드.
  • 실행 시간 및 오류 추적.
  • 별도 에이전트 없이 간단하게 구현.

전체 멀티 컨테이너 솔루션 예시

docker-compose.yml

version: '3.8'

services:
  # 메인 애플리케이션
  app:
    image: myapp:latest
    # ...

  # 백그라운드 작업용 Cron 워커
  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

# 애플리케이션 의존성
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

# 애플리케이션 복사
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 (모니터링 포함)

# 큐 프로세서 - 중요, 반드시 모니터링
* * * * * curl -fsS https://cronmonitor.app/ping/{token} && php bin/console messenger:consume --time-limit=3600

# 매시간 데이터 동기화
0 * * * * curl -fsS https://cronmonitor.app/ping/{token} && php bin/console app:sync-data || curl -fsS https://cronmonitor.io/fail/sync-def456

# 일일 백업 - 반드시 성공해야 함
0 2 * * * curl -fsS https://cronmonitor.app/ping/{token} && /app/scripts/backup.sh

# 주간 정리
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

마이그레이션 체크리스트

  • 시스템 cron 데몬을 Supercronic 으로 교체.
  • crontab 파일을 컨테이너 안으로 옮기고 CMD 에서 참조.
  • 모든 필수 환경 변수가 Dockerfile 또는 docker‑compose 파일에 설정돼 있는지 확인.
  • 각 작업에 HTTP 핑 호출(또는 다른 모니터링 훅) 추가.
  • 로그가 docker logs 로 출력되는지 검증.
  • 정상적인 종료(docker stop) 를 테스트하고 작업이 SIGTERM 을 받는지 확인.
  • CronMonitor(또는 선호하는 모니터링 서비스) 에 알림을 설정.
Back to Blog

관련 글

더 보기 »