Recently, I needed to get cron working inside a Docker container running Debian Slim. It’s not difficult once you figure it out, but it did take a bit of research and learning to get everything to work.
First off, Debian Slim is real slim. There’s no
cron nor is there a
syslog when you want to debug things. Add
rsyslog in your Dockerfile before you start anything else. With
syslog installed, you can tail
/var/log/syslog while you’re debugging your cron files, which is incredibly helpful.
In my case, I wanted to run a few Python scripts on a schedule. Cron natively uses
sh. I’m sure there’s a way to get it to work that way, but I didn’t want to play around with that. I added my scripts directory in Docker to
PATH in my cronfile and set
bash as my
SHELL. My container runs in Docker Swarm, so it was also important that the output for my script landed in the same STDOUT that eventually ends up in
/proc/1/rd/1 is the trick for getting output in the right place.
The below example is where my cron file ended up, once I got everything working. It sets up
PATH to point to my scripts, changes the shell to
bash and gets my script ready to run each hour piping its output to STDOUT and errors to STDERR.
PATH=/your-working-directory/cron-scripts:/usr/local/bin:rest-of-path-goes-here SHELL=/bin/bash 0 * * * * scheduled_script.py > /proc/1/fd/1 2>&1
Having a valid cron file is just half the battle in getting cron to run successfully in Docker. In your Docker file you’ll need to make sure your script is executable and copy your cron file to
/etc/cron.d. Make sure your new cron file is executable with a little
chmod and then apply your changes. By default the cron and syslog service will not start on their own. Make sure you start those two service before you run any of your own commands.
# Make sure your script is executable RUN chmod +x cron-scripts/scheduled_script.py # Add crontab file in the cron directory RUN cp local/path/crontab /etc/cron.d/my-new-cron # Give execution rights on the cron job RUN chmod 0644 /etc/cron.d/my-new-cron # Apply cron job RUN crontab /etc/cron.d/my-new-cron # Start cron and rsyslog, etc CMD ["sh", "-c", "service rsyslog start ; service cron start ; more-stuff-you-doing"]
The above is really all you need to get things going. But… your Docker container is going to default to UTC. That’s fine and all, but when I’m setting up specific schedules in cron, I like to think in local time. The below command is one of many ways to change your time zone. Is it the best? I don’t know. It worked for me.
RUN echo "tzdata tzdata/Areas select US" | debconf-set-selections" RUN echo "tzdata tzdata/Zones/US select Central" | debconf-set-selections RUN rm -f /etc/localtime /etc/timezone RUN dpkg-reconfigure -f noninteractive tzdata