How to run a cron job inside a docker container?
You can copy your crontab into an image, in order for the container launched from said image to run the job.
See "Run a cron job with Docker" from Julien Boulay in his Ekito/docker-cron
:
Let’s create a new file called "
hello-cron
" to describe our job.
* * * * * echo "Hello world" >> /var/log/cron.log 2>&1# An empty line is required at the end of this file for a valid cron file.
If you are wondering what is 2>&1, Ayman Hourieh explains.
The following Dockerfile describes all the steps to build your image
FROM ubuntu:latestMAINTAINER docker@ekito.frRUN apt-get update && apt-get -y install cron# Copy hello-cron file to the cron.d directoryCOPY hello-cron /etc/cron.d/hello-cron # Give execution rights on the cron jobRUN chmod 0644 /etc/cron.d/hello-cron# Apply cron jobRUN crontab /etc/cron.d/hello-cron # Create the log file to be able to run tailRUN touch /var/log/cron.log # Run the command on container startupCMD cron && tail -f /var/log/cron.log
(see Gaafar's comment and How do I make apt-get
install less noisy?:apt-get -y install -qq --force-yes cron
can work too)
As noted by Nathan Lloyd in the comments:
Quick note about a gotcha:
If you're adding a script file and telling cron to run it, remember toRUN chmod 0744 /the_script
Cron fails silently if you forget.
OR, make sure your job itself redirect directly to stdout/stderr instead of a log file, as described in hugoShaka's answer:
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
Replace the last Dockerfile line with
CMD ["cron", "-f"]
See also (about cron -f
, which is to say cron "foreground") "docker ubuntu cron -f
is not working"
Build and run it:
sudo docker build --rm -t ekito/cron-example .sudo docker run -t -i ekito/cron-example
Be patient, wait for 2 minutes and your commandline should display:
Hello worldHello world
Eric adds in the comments:
Do note that
tail
may not display the correct file if it is created during image build.
If that is the case, you need to create or touch the file during container runtime in order for tail to pick up the correct file.
See "Output of tail -f
at the end of a docker CMD
is not showing".
See more in "Running Cron in Docker" (Apr. 2021) from Jason Kulatunga, as he commented below
See Jason's image AnalogJ/docker-cron
based on:
Dockerfile installing
cronie
/crond
, depending on distribution.an entrypoint initializing
/etc/environment
and then callingcron -f -l 2
The accepted answer may be dangerous in a production environment.
In docker you should only execute one process per container because if you don't, the process that forked and went background is not monitored and may stop without you knowing it.
When you use CMD cron && tail -f /var/log/cron.log
the cron process basically fork in order to execute cron
in background, the main process exits and let you execute tailf
in foreground. The background cron process could stop or fail you won't notice, your container will still run silently and your orchestration tool will not restart it.
You can avoid such a thing by redirecting directly the cron's commands output into your docker
stdout
andstderr
which are located respectively in/proc/1/fd/1
and/proc/1/fd/2
.
Using basic shell redirects you may want to do something like this :
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
And your CMD will be : CMD ["cron", "-f"]
For those who wants to use a simple and lightweight image:
FROM alpine:3.6# copy crontabs for root userCOPY config/cronjobs /etc/crontabs/root# start crond with log level 8 in foreground, output to stderrCMD ["crond", "-f", "-d", "8"]
Where cronjobs is the file that contains your cronjobs, in this form:
* * * * * echo "hello stackoverflow" >> /test_file 2>&1# remember to end this file with an empty new line