19

To preface, I have been referencing these two articles for help:

My goal is to have a cron job automatically start when I start my docker container. Currently, it doesn't automatically start, but I can manually go into my container and run service cron start, which starts the job, and it works correctly.

So the problem is: How do I get my cron job to start automatically when my container starts up?

Dockerfile

FROM microsoft/dotnet:latest
RUN apt-get update && apt-get install -y cron

COPY . /app

WORKDIR /app

ADD crontab /etc/cron.d/crontab
RUN chmod 0600 /etc/cron.d/crontab
RUN crontab -u root /etc/cron.d/crontab
RUN touch /var/log/cron.log

RUN ["dotnet", "restore"]

RUN ["dotnet", "build"]

EXPOSE 5000/tcp

CMD cron && tail -f /var/log/cron.log
CMD service cron start

crontab

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# Empty space

Though I wasn't able to get cron working in that particular container, I was able to create a standalone docker container specifically for cron, and was successful in getting it to run automatically.

As far as setup for the cron container, I followed the linked article, Run a cron job with Docker - Julien Boulay, and was able to get it working.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Tory
  • 916
  • 1
  • 11
  • 19
  • Do you need cron to be running inside the container, or could you create a cron job on the host that will run this container at the desired time to do its work? – Roman Oct 22 '16 at 23:11
  • @R0MANARMY It needs to be running inside the container. – Tory Oct 22 '16 at 23:16
  • You've already seen [this question](http://stackoverflow.com/questions/37458287/how-to-run-a-cron-job-inside-a-docker-container) ? – Roman Oct 22 '16 at 23:19
  • @R0MANARMY Yes, that question basically just outlines my first reference. – Tory Oct 22 '16 at 23:20
  • This may seem like a stupid question, but is your container running? I see you have 2 `CMD` directives at the end of your Dockerfile, I think the second one will overwrite the first. Assuming it does, `service cron start` should finish successfully, once the command finishes running, your container should shut down. – Roman Oct 22 '16 at 23:25
  • @R0MANARMY My container is running. It stays running too, until I run `docker-compose kill`. – Tory Oct 22 '16 at 23:28
  • 1
    Per [Docker docs](https://docs.docker.com/engine/reference/builder/#/cmd), there can only be one CMD instruction in a Dockerfile. I would suggest taking out the second one. It also looks like there are only a couple of other differences between your Dockerfile and the one in the other answer. I would try changing those one at a time to see if you can get it to run. – Roman Oct 22 '16 at 23:34

4 Answers4

17

What I'm doing is have the CMD call cron directly like this:

CMD /usr/sbin/cron -f

Before that I'm adding the crontab to the container and assigning it as the root crontab with the command:

RUN crontab /root/mycrontab

You don't need to call the crontab command on files that are located in /etc/cron.d, but you do need those files to have the correct syntax. Using your example, instead of this:

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1

You should have this:

* * * * * root echo "Hello world" >> /var/log/cron.log 2>&1

On your crontab file. This only applies to crontab files located within /etc/cron.d, otherwise your crontab file syntax is correct and you use the crontab command to load it.

Starting from your example, I think you should modify your files like this:

Dockerfile

FROM microsoft/dotnet:latest
RUN apt-get update && apt-get install -y cron

COPY . /app

WORKDIR /app

ADD crontab /etc/cron.d/crontab
RUN chmod 0600 /etc/cron.d/crontab
RUN touch /var/log/cron.log

RUN ["dotnet", "restore"]

RUN ["dotnet", "build"]

EXPOSE 5000/tcp

CMD /usr/sbin/cron -f

crontab

* * * * * root echo "Hello world" >> /var/log/cron.log 2>&1

Another alternative would be:

Dockerfile

FROM microsoft/dotnet:latest
RUN apt-get update && apt-get install -y cron

COPY . /app

WORKDIR /app

ADD crontab /root/
RUN crontab /root/crontab
RUN touch /var/log/cron.log

RUN ["dotnet", "restore"]

RUN ["dotnet", "build"]

EXPOSE 5000/tcp

CMD /usr/sbin/cron -f

crontab

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
Alvaro Carvajal
  • 1,306
  • 1
  • 7
  • 6
  • Thanks for the response! I'm having trouble following you. Do you mind editing your answer to display what my *Dockerfile* and *crontab* files would look like? Thanks! – Tory Oct 21 '16 at 17:08
  • I tried both versions of your answer, and it's still not working. Is there any additional information I can provide to better help? – Tory Oct 21 '16 at 17:44
  • I just tested it using the second version (removing the dotnet restore & build commands from the dockerfile) and cron works. Can you get inside the container and see if cron is running? (ex: `ps auxw|grep cron`) – Alvaro Carvajal Oct 21 '16 at 19:14
  • So what I am doing is; `docker-compose build`, `docker-compose up -d`, then I am entering my container via `docker exec -it {container-id} bash`, then checking to see if cron is running by `service cron status`, which returns `cron is not running ... failed!` – Tory Oct 21 '16 at 19:22
  • I tried with the same commands, but for me `service cron status` returns `cron is running.`. I'm testing on an ubuntu box with 4.4.0.45-generic kernel. Are you testing on a Windows box? – Alvaro Carvajal Oct 21 '16 at 19:49
  • 1
    I am running `Linux 4280056316a8 3.13.0-96-generic #143-Ubuntu`. – Tory Oct 21 '16 at 19:52
  • I just tested the solution on an Ubuntu box with ` 3.16.0-0.bpo.4-amd64` kernel and it works there as well. What happens if you run `/usr/sbin/cron -f` from your container after you've launched it with `docker-compose up -d`? – Alvaro Carvajal Oct 21 '16 at 20:35
  • Sorry for the late response. It returns nothing. Cron is still not running, even after making my code reflect your recent answer change. – Tory Oct 27 '16 at 20:06
8

We had a problem with php-fpm and docker where our cronjob tasks were not be executed. There were two problems we solved:

  • We tried to copy a crontab file into the docker container by using COPY config/custom-cron /etc/cron.d/custom-cron. The problem is, that our line endings were in windows format. This did break our crontab file, because this line endings are not converted while copy that file into the container.
  • The second problem was, that we tried to start the cron via CMD ["cron", "-f"] which did block the main php-fpm process. This results in a 502 Bad gateway error when calling our web application.

Finaly we made it work by editing the crontab file manually while building the docker image instead of copy-pasting and using supervisord to have multiple tasks running inside docker. This should work on all supported operating systems.

dockerfile

FROM php:7.1.16-fpm

RUN apt-get update && apt-get install -y cron supervisor

# Configure cron
RUN crontab -l | { cat; echo "* * * * * echo 'Hello world' >> /var/log/cron-test.log 2>&1"; } | crontab -

# Configure supervisor
COPY config/supervisord.conf /etc/supervisor/supervisord.conf

supervisord.conf

[supervisord]
logfile = /dev/null
loglevel = info
pidfile = /var/run/supervisord.pid
nodaemon = true

[program:php-fpm]
command = php-fpm
autostart = true
autorestart = true
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0

[program:cron]
command = cron -f
autostart = true
autorestart = true
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0
lin
  • 17,956
  • 4
  • 59
  • 83
  • 1
    THANKS A TON for pointing this out! We noticed that our laravel scheduled jobs suddenly stopped working in a PROD application and has no clue why. Turns out, the issue started after we deployed a docker container built on Windows. Previously we had only deployed containers built on Linux. I just converted the crontab to UNIX format and was able to fix the issue, even when deployed from a Windows machine. Thanks again! – Siddhant Sadangi Nov 18 '21 at 12:34
4

There is a bug in Debian based distributions which will cause cronjobs to fail because docker uses layered filesystem and cron doesn't start and says NUMBER OF HARD LINKS > 1 (/etc/crontab).

The fix is simple, add touch /etc/crontab /etc/cron.*/* to the entrypoint of your container.

I have made a blog post explaining how to setup cron in a Docker container here : https://esc.sh/blog/cron-jobs-in-docker/

Root
  • 185
  • 4
  • 6
0

I know this is an old question but I found a fix to this on Debian and it solved my problem. Cron pam auth with uid was breaking my cron from being able to run.

RUN sed -i '/session    required     pam_loginuid.so/c\#session    required     pam_loginuid.so/' /etc/pam.d/cron