From scratch or from a base image of your choice.
Prerequisite: if you start from a base image, is it based on alpine or debian?
The syntax is not the same because debian uses cron 1 while alpine uses crond 2.
Check with:
$ docker run --rm ghcr.io/borgmatic-collective/borgmatic:latest cat /etc/os-release
Output:
NAME="Alpine Linux"
1. From a fresh Debian/Ubuntu base (crontab)
Dockerfile
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
#!/bin/sh
set -e
(printenv | grep -v "^_="; echo "0 2 * * * /my/script.sh >> /var/log/cron.log 2>&1") | crontab -
exec cron -f
Unlike with alpine, the environment variables are not available to the script if you miss the printenv part 3
2. From an existing image, based on Alpine: example of borgmatic (crond)
compose.yaml
services:
borgmatic:
build: ./borgmatic
borgmatic/Dockerfile
FROM ghcr.io/borgmatic-collective/borgmatic:latest
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD []
borgmatic/entrypoint.sh
#!/bin/sh
set -e
borgmatic init ... # Because we override the entrypoint, we need to insert the commands that it would have ran
# 2 AM
echo "0 2 * * * borgmatic 2>&1 | tee -a /var/log/cron.log" > /etc/crontabs/root
exec crond -f
Unlike with Debian, environment variables are inherited. No tricks needed 4
Troubleshooting
Does the script work inside the container?
- Trigger the script manually:
docker exec <container> /my/script.sh
Does the cron trigger?
- Check if the cron is firing: run it every minute using
* * * * *and add a log:echo "$(date) cron fired" >> /var/log/cron.log; /my/script.sh
Note: output goes to /var/log/cron.log only, and will not show up in
docker logs <container>.
Instead use docker exec <container> tail -n 500 -f /var/log/cron.log