/
Container & Orchestration

Cron in Docker Guide

Docker containers are designed to run a single foreground process, and there's no built-in Docker equivalent to cron — "scheduling a Docker job" always means choosing one of several patterns: running cron inside the container alongside your app, a dedicated sidecar/cron container, or delegating to your orchestrator's native scheduler (like Kubernetes CronJob).

Syntax Notes

There's no Docker-specific cron syntax — whichever approach you choose ends up using either standard Linux cron syntax (if cron runs inside a container) or your orchestrator's own scheduling syntax (e.g. Kubernetes CronJob's standard 5-field YAML schedule field).

Examples

Running cron inside a container (Dockerfile)
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y cron
COPY crontab /etc/cron.d/app-cron
RUN chmod 0644 /etc/cron.d/app-cron && crontab /etc/cron.d/app-cron
CMD ["cron", "-f"]
Dedicated cron sidecar (docker-compose.yml)
services:
  app:
    image: my-app
  scheduler:
    image: my-app
    entrypoint: crond -f
    volumes:
      - ./crontab:/etc/crontabs/root

Gotchas

  • Running cron as PID 1 in a container (`CMD ["cron", "-f"]`) means cron itself must handle signal forwarding correctly, or the container won't shut down cleanly on `docker stop` — this trips up a lot of first attempts at containerized cron.
  • A cron job running inside a container only has access to that container's filesystem and environment — if it needs to interact with another service's container (a database, an app container), it needs proper networking/volume configuration, unlike host cron which has full host access.
  • If you scale a service to multiple container replicas and each replica also runs its own embedded cron, the scheduled job fires once per replica — the exact same multi-instance duplication problem as node-cron, just at the container level.

Best Practices

  • Prefer your orchestrator's native scheduling (Kubernetes CronJob, ECS Scheduled Tasks, etc.) over cron-inside-a-container whenever you're already running on an orchestrator — it avoids the PID 1 signal-handling and multi-replica duplication problems entirely.
  • If you must run cron inside a container, use a minimal init system (tini, dumb-init) alongside cron so signals are forwarded correctly and zombie processes don't accumulate.
  • Keep the scheduled job's logic in a separate script invoked by cron, and send its output to stdout/stderr (not a file inside the container) so `docker logs` captures it — otherwise job output disappears when the container is removed.

Frequently Asked Questions

Can I just add a cron job to my application's Dockerfile?
Yes, technically, but it means running two processes (cron and your app) in one container, which goes against the one-process-per-container convention and complicates signal handling and logging. It works for simple cases but doesn't scale well.
What's the best way to run scheduled jobs in a Docker Swarm or Kubernetes setup?
Use the orchestrator's native scheduling primitive — Kubernetes CronJob or Swarm's own patterns — rather than cron inside a container. It integrates properly with the platform's scaling, logging, and restart behavior.
How do I see the output of a cron job running inside a container?
Redirect the cron job's stdout/stderr to the container's own stdout/stderr (e.g. via `> /proc/1/fd/1 2>/proc/1/fd/2` in the crontab entry) so `docker logs` picks it up — cron's default behavior of emailing output doesn't work in a typical minimal container image.