Skip to content

Running Cron Jobs in Docker Containers

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Running Cron Jobs in Docker Containers. We cover key concepts, practical examples, and best practices to help you master this topic.

Run cron jobs inside Docker containers: install cron, create crontabs, handle logging, manage environment variables, and use supervisord or entrypoint patterns for scheduling.

What You Learn

You will learn how to run cron inside Docker containers, handle the single-Process-per-container paradigm, use supervisord for multi-process containers, configure logging in Docker, and manage environment variables for cron in containers.

Why It Matters

Docker containers typically run a single process. Cron introduces a second process (the cron daemon) that must be managed alongside your application. Understanding how to combine them is essential for containerized backend systems.

Real-World Use

DodaTech runs scheduled tasks in Docker containers: hourly database health checks, daily log rotation, and weekly report generation. Each container runs both the application server and cron, with supervisord managing both processes.

Basic Cron in Docker

# Dockerfile
FROM ubuntu:22.04

# Install cron
RUN apt-get update && apt-get install -y cron

# Create crontab file
RUN echo "0 3 * * * /usr/local/bin/backup.sh >> /var/log/cron/backup.log 2>&1" > /etc/cron.d/my-cron \
    && echo "*/30 * * * * /usr/local/bin/health.sh >> /var/log/cron/health.log 2>&1" >> /etc/cron.d/my-cron

# Set permissions and apply crontab
RUN chmod 0644 /etc/cron.d/my-cron && crontab /etc/cron.d/my-cron

# Copy scripts
COPY backup.sh /usr/local/bin/backup.sh
COPY health.sh /usr/local/bin/health.sh
RUN chmod +x /usr/local/bin/backup.sh /usr/local/bin/health.sh

# Start cron and keep container running
CMD cron -f
# Build and run
docker build -t cron-app .
docker run -d --name cron-container cron-app

# Check logs
docker exec cron-container tail -f /var/log/cron/backup.log

# Verify cron is running
docker exec cron-container ps aux | grep cron

Using Supervisord

# Dockerfile with supervisord
FROM python:3.11-slim

# Install cron and supervisor
RUN apt-get update && apt-get install -y cron supervisor

# Create supervisor config
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Create crontab
COPY crontab /etc/cron.d/app-cron
RUN chmod 0644 /etc/cron.d/app-cron && crontab /etc/cron.d/app-cron

# Copy application
COPY app/ /app/
WORKDIR /app

# Start supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
; supervisord.conf
[supervisord]
nodaemon=true
logfile=/var/log/supervisor/supervisord.log
pidfile=/tmp/supervisord.pid

[program:cron]
command=/usr/sbin/cron -f
autostart=true
autorestart=true
stdout_logfile=/var/log/cron/crond.log
stderr_logfile=/var/log/cron/crond.err

[program:app]
command=/usr/local/bin/python app.py
autostart=true
autorestart=true
stdout_logfile=/var/log/app/app.log
stderr_logfile=/var/log/app/app.err

Entrypoint Pattern

#!/bin/bash
# entrypoint.sh
# Start cron and the main application

# Run startup tasks
echo "Running startup checks..."
/usr/local/bin/startup.sh

# Setup cron jobs
echo "Setting up cron..."
printenv | grep -v "no_proxy\|HOME\|PWD\|SHLVL" > /etc/environment
cron

# Start main application
echo "Starting main application..."
exec "$@"
# Dockerfile using entrypoint pattern
FROM python:3.11-slim

RUN apt-get update && apt-get install -y cron

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

COPY crontab /etc/cron.d/app-cron
RUN chmod 0644 /etc/cron.d/app-cron

COPY app/ /app/
WORKDIR /app

ENTRYPOINT ["/entrypoint.sh"]
CMD ["python3", "main.py"]

Handling Environment Variables

#!/bin/bash
# /usr/local/bin/cron-env.sh
# Cron in Docker has minimal environment.
# This script loads environment variables for cron jobs.

# Load environment from file
if [ -f /etc/environment ]; then
    export $(cat /etc/environment | xargs)
fi

# Load additional config
if [ -f /app/.env ]; then
    export $(cat /app/.env | xargs)
fi

# Now run the actual command
exec "$@"
# Dockerfile with environment handling
FROM python:3.11-slim

RUN apt-get update && apt-get install -y cron

# Copy environment loader
COPY cron-env.sh /usr/local/bin/cron-env.sh
RUN chmod +x /usr/local/bin/cron-env.sh

# Use environment loader in crontab
RUN echo "0 3 * * * /usr/local/bin/cron-env.sh /usr/local/bin/backup.sh >> /var/log/cron/backup.log 2>&1" > /etc/cron.d/app-cron

# Set environment in Docker
ENV DB_HOST=localhost
ENV DB_USER=app
ENV APP_ENV=production

Logging in Docker Cron

#!/bin/bash
# /usr/local/bin/cron-logger.sh
# Wrapper that logs to stdout for Docker's log system

JOB_NAME="$1"
shift

echo "[$(date '+%Y-%m-%d %H:%M:%S')] START: ${JOB_NAME}"

# Execute the actual command
"$@" 2>&1
EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] END: ${JOB_NAME} (success)"
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] FAIL: ${JOB_NAME} (exit: ${EXIT_CODE})"
fi

exit $EXIT_CODE
# Using the logger wrapper
COPY cron-logger.sh /usr/local/bin/cron-logger.sh
RUN chmod +x /usr/local/bin/cron-logger.sh

# Crontab entry using logger wrapper
RUN echo "0 3 * * * /usr/local/bin/cron-logger.sh backup /usr/local/bin/backup.sh" > /etc/cron.d/app-cron

Docker Compose with Cron

# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    container_name: app-with-cron
    environment:
      - DB_HOST=postgres
      - DB_USER=app
      - APP_ENV=production
      - TZ=UTC
    volumes:
      - cron-logs:/var/log/cron
      - backups:/backups
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret

volumes:
  cron-logs:
  backups:

Common Mistakes

1. Container Exits Immediately

Cron runs in the background by default. Without cron -f (foreground), the container exits immediately after starting cron.

2. Missing Environment Variables

Docker cron lacks environment variables set in the Dockerfile. Write them to /etc/environment or source them in cron wrappers.

3. Using @reboot in Container Cron

@reboot runs when cron starts, but container restarts are common. Use @reboot with caution in Docker. Some minimal images do not support it.

4. No Logging to stdout

Container logs come from stdout/stderr. Cron logs to files by default. Send cron output to stdout for visibility in docker logs.

5. Timezone Mismatch

Containers default to UTC. If your cron jobs expect a different timezone, set TZ environment variable or configure timezone in the Dockerfile.

Practice Questions

1. Why does a cron Docker container exit immediately?

Cron forks to the background by default. Without cron -f to run in the foreground, the container sees the main process exit and stops.

2. How do you run multiple processes in a Docker container?

Use supervisord or a similar process manager to run cron and your application as separate managed processes within one container.

3. How do cron jobs access Docker environment variables?

Write environment variables to /etc/environment in the entrypoint, then source them in cron wrappers. Or pass them explicitly in the crontab.

4. How do you view cron logs in Docker?

Redirect cron output to stdout: cron-job.sh >> /proc/1/fd/1 2>&1 or use a wrapper that logs to stdout for docker logs.

Challenge

Build a Docker image that runs: a web application server, cron daemon for scheduled tasks, daily backup at 3 AM to /backups, health check every 5 minutes logging to stdout, log rotation daily via cron, and uses supervisord for process management.

FAQ

Should I run cron in the same container as my app?

For simple cases, yes. For complex deployments, use a dedicated scheduler container (separate from the web container) to avoid resource contention.

Does cron work in minimal Docker images like Alpine?

Yes. Alpine includes busybox cron. Install with: apk add --no-cache dcron. Note: Alpine cron does not support @reboot.

How do I prevent cron in Docker from running multiple times?

Use distributed locking with Redis. Only one container in a Docker Compose or Swarm setup should execute each cron job.

Can I use Docker HEALTHCHECK with cron?

Yes. HEALTHCHECK can verify that the cron daemon is running: HEALTHCHECK CMD pgrep cron || exit 1.

What is the best way to manage cron in Kubernetes vs Docker?

In Docker, use supervisord or entrypoint scripts. In Kubernetes, use CronJob resources which are purpose-built for scheduling.

Mini Project: Docker Cron Container

# Dockerfile
FROM alpine:3.18

# Install cron and bash
RUN apk add --no-cache dcron bash

# Create log directory
RUN mkdir -p /var/log/cron /scripts

# Copy scripts
COPY scripts/ /scripts/
RUN chmod +x /scripts/*.sh

# Setup crontab (using BusyBox crond format)
RUN echo "*/5 * * * * /scripts/health.sh >> /var/log/cron/health.log 2>&1" > /var/spool/cron/crontabs/root \
    && echo "0 3 * * * /scripts/backup.sh >> /var/log/cron/backup.log 2>&1" >> /var/spool/cron/crontabs/root

# Write env for cron
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
CMD ["crond", "-f", "-l", "2"]
#!/bin/sh
# entrypoint.sh
echo "Setting up environment for cron..."
printenv > /etc/environment

echo "Starting cron..."
exec "$@"

What's Next

Now that you understand cron in Docker, explore cron in Kubernetes for cluster-level scheduling, then learn about cron alternatives like systemd timers.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro