How to run a cron job inside a docker container?
Solution 1
Unfortunately, none of the above answers worked for me, although all answers lead to the solution and eventually to my solution, here is the snippet if it helps someone. Thanks
This can be solved with the bash file, due to the layered architecture of the Docker, cron service doesn't get initiated with RUN/CMD/ENTRYPOINT commands.
Simply add a bash file which will initiate the cron and other services (if required)
DockerFile
FROM gradle:6.5.1-jdk11 AS build
# apt
RUN apt-get update
RUN apt-get -y install cron
# Setup cron to run every minute to print (you can add/update your cron here)
RUN touch /var/log/cron-1.log
RUN (crontab -l ; echo "* * * * * echo testing cron.... >> /var/log/cron-1.log 2>&1") | crontab
# entrypoint.sh
RUN chmod +x entrypoint.sh
CMD ["bash","entrypoint.sh"]
entrypoint.sh
#!/bin/sh
service cron start & tail -f /var/log/cron-2.log
If any other service is also required to run along with cron then add that service with &
in the same command, for example: /opt/wildfly/bin/standalone.sh & service cron start & tail -f /var/log/cron-2.log
Once you will get into the docker container there you can see that testing cron....
will be getting printed every minute in file: /var/log/cron-1.log
Solution 2
I decided to use busybox, as it is one of the smallest images.
crond is executed in foreground (-f), logging is send to stderr (-d), I didn't choose to change the loglevel. crontab file is copied to the default path: /var/spool/cron/crontabs
FROM busybox:1.33.1
# Usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]
#
# -f Foreground
# -b Background (default)
# -S Log to syslog (default)
# -l N Set log level. Most verbose 0, default 8
# -d N Set log level, log to stderr
# -L FILE Log to FILE
# -c DIR Cron dir. Default:/var/spool/cron/crontabs
COPY crontab /var/spool/cron/crontabs/root
CMD [ "crond", "-f", "-d" ]
Solution 3
This question have a lot of answers, but some are complicated and another has some drawbacks. I try to explain the problems and try to deliver a solution.
cron-entrypoint.sh
:
#!/bin/bash
# copy machine environment variables to cron environment
printenv | cat - /etc/crontab > temp && mv temp /etc/crontab
## validate cron file
crontab /etc/crontab
# cron service with SIGTERM support
service cron start
trap "service cron stop; exit" SIGINT SIGTERM
# just dump your logs to std output
tail -f \
/app/storage/logs/laravel.log \
/var/log/cron.log \
& wait $!
Problems solved
- environment variables are not available on cron environment (like env vars or kubernetes secrets)
- stop when crontab file is not valid
- stop gracefully cron jobs when machine receive an SIGTERM signal
For context, I use previous script on Kubernetes with Laravel app.
Solution 4
If you'd like to run other services than crontab you might want to call this script to activate yourscript in addition to your entry point:
addCronTabEntry.sh
(crontab -l 2>/dev/null; echo "*/1 * * * * <yourscript>") | crontab -
service cron start
C Heyer
Updated on July 08, 2022Comments
-
C Heyer almost 2 years
I am trying to run a cronjob inside a docker container that invokes a shell script.
Yesterday I have been searching all over the web and stack overflow, but I could not really find a solution that works.
How can I do this?EDIT:
I've created a (commented) github repository with a working docker cron container that invokes a shell script at given interval.
-
Peter almost 3 yearsShouldn't it be doing
tail -f /var/log/cron-1.log
instead of/var/log/cron-2.log
, sincecron-1.log
is where the STDOUT/STDERR is being directed? (Unless I'm missing something) -
Gaurav Tyagi almost 3 yearsYes, correct, that was a typo,
/var/log/cron-1.log
should be at every place -
Johnson_145 almost 2 yearsIf I run
docker stop
with this setup, nothing happens, i.e.service cron stop
doesn't get executed. If I run the latter manually from within the container, thecron
process stops immediately instead of waiting for the cronjobs. cronjobs will still complete their run, so that may be fine. When they are done, the container does not stop either though. What am I missing? -
Johnson_145 almost 2 yearsGot it working now. I think the trap handler wasn't triggered, because I defined my entryscript as
CMD "/bin/sh" ENTRYPOINT /entrypoint.sh
instead ofENTRYPOINT ["/entrypoint.sh"]
. That way, it got wrapped in another shell which didn't pass the signals through. I had to do some further steps to actually wait for running cronjobs to finish. Elaborating on your answer over here.