Running a Docker Compose Command with Cron
cd into the directory holding compose.yaml so Docker Compose finds it, then call the full docker path. For scheduled tasks, docker compose run --rm a service is cleaner than exec because it doesn't need the container already running.
The crontab line
0 2 * * * cd /opt/app && /usr/bin/docker compose run --rm worker python job.py >> /var/log/compose-cron.log 2>&1
The cd matters — Compose looks for compose.yaml/docker-compose.yml in the working directory.
run --rm vs exec
run --rm starts a fresh container for the task and removes it after — ideal for cron. exec runs inside an already-running container: docker compose exec -T worker python job.py (use -T since cron has no TTY).
Permissions
The cron user must be in the docker group, or run the job from root's crontab.
FAQ
How do I run docker compose from cron?
cd to the compose directory and use the full docker path: 0 2 * * * cd /opt/app && /usr/bin/docker compose run --rm worker python job.py.
Should I use run or exec in a cron compose job?
Use run --rm for one-off scheduled tasks — it doesn't need the container running. Use exec -T only to run inside an already-running container.
Why does docker compose fail with no TTY in cron?
Cron has no terminal. Add -T to docker compose exec to disable TTY allocation.