Getting cron to work on docker

28,366

I installed rsyslog to see what errors I was getting I got the following

(*system*) NUMBER OF HARD LINKS > 1 (/etc/crontab). A bit of searching told me that cron has a security policy to not work if there are lots of hard-links to its files. Unfortunately Docker's layered file-system makes files have lots of hard-links.

To fix it, I added touch /etc/crontab /etc/cron.*/*, to the start up script, before running cron. This dis-attaches if from the other file-instances.

The new entrypoint is

#!/bin/sh

#fix link-count, as cron is being a pain, and docker is making hardlink count >0 (very high)
touch /etc/crontab /etc/cron.*/*

service cron start

# Hand off to the CMD
exec "$@"

I have tested and it works

Summary

To get cron to work you will have to.

  • Install cron — if not installed
  • Add cron job to /etc/cron.daily/ (or weekly). Ensure that your script-name, has only letters, numbers, hyphens, no dots. (Don't ask) see cron job not running from cron.daily
  • Get the hardlink count of crons config files down to one: do touch /etc/crontab /etc/cron.*/* — (if in docker). I put it in the start-up script.
  • Start cron: service cron start — (If on a basic OS, with no init. As in a lot of base images for use in docker). I put it in the starts-up script.

The entrypoint script from this answer, and everything else from the question, will do it. Current project can be fetched with hg clone ssh://[email protected]/davids_dad/a_website

Share:
28,366

Related videos on Youtube

ctrl-alt-delor
Author by

ctrl-alt-delor

A software engineer, programmer, project manager, Gnu+Linux user, Newly Qualified Teacher of computing. I am currently hanging out on A new site for computer science and IT educators. Visit the site here

Updated on September 18, 2022

Comments

  • ctrl-alt-delor
    ctrl-alt-delor over 1 year

    I am using nginx in docker. I have configured cron jobs to update SSL certificates and DNS registration. However the cron jobs are not running.

    What have I done. I have created a Dockerfile based on arm32v7/nginx this intern is based on debian:stretch-slim. At first I installed cron, and assumed that it would run, but then discovered that the service was not started (there is no init subsystem installed, debian:stretch-slim is very minimal). So I added code to start cron. Now if I ask the container if cron is running it says yes.

    #ctrl-alt-delor@raspberrypi:~/a_website/docker$
    #↳ docker exec -it $(docker container ls | sed -nr -e 's/.*(website-stack.*)/\1/p') service cron status
    [ ok ] cron is running.
    

    However I am not seeing any logs from the task that I have added to cron.

    If I run run-parts --report /etc/cron.daily, the my tasks get run, and produce log output. Therefore it still appears as if cron is not running.

    #ctrl-alt-delor@raspberrypi:~/a_website/docker$
    #↳ docker exec -it $(docker container ls | sed -nr -e 's/.*(website-stack.*)/\1/p') cat /proc/12/cmdline; echo
    /usr/sbin/cron
    

    So why is cron not running its jobs? What have I missed?

    Dockerfile

    FROM arm32v7/nginx
    
    ##add backports
    COPY stretch-backports-source.list /etc/apt/sources.list.d/
    
    ##install cron and curl — so we can register dns regularly
    RUN     apt-get update &&\
            apt-get install -y cron curl &&\
            apt-get clean
    
    ##setup cron to register dns
    COPY register-dns register-dns.auth register-dns-hostname /usr/local/bin/
    COPY register-dns.cron /etc/cron.daily/1-register-dns
    RUN chmod +x /usr/local/bin/register-dns /etc/cron.daily/1-register-dns
    
    ##add curtbot
    RUN apt-get update && \
        apt-get -t stretch-backports install -y python-certbot-nginx && \
        apt-get clean
    
    
    #add ssl port
    EXPOSE 443 80
    
    ##custom entry point — needed by cron
    COPY entrypoint /entrypoint
    RUN chmod +x /entrypoint
    ENTRYPOINT ["/entrypoint"]
    CMD ["nginx", "-g", "daemon off;"] #:tricky: we seem to need to re-specify this
    
    LABEL name="my-nginx" \
          description="nginx + cron + curl + certbot + dns-registering"
    

    entrypoint

    #!/bin/sh
    
    ## Do whatever you need with env vars here ...
    service cron start
    
    # Hand off to the CMD
    exec "$@"
    

    /etc/crontab

    SHELL=/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    
    # m h dom mon dow user  command
    17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
    25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
    47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
    52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
    

    /etc/cron.daily/1-register-dns

    #!/bin/sh
    date >> /var/log/register-dns
    /usr/local/bin/register-dns >>/var/log/register-dns
    
    • Rui F Ribeiro
      Rui F Ribeiro almost 6 years
      Have you created /var/spool/cron/crontabs inside the container?
    • ctrl-alt-delor
      ctrl-alt-delor almost 6 years
      @RuiFRibeiro no (however the directory exists). Tell me more.
  • Rui F Ribeiro
    Rui F Ribeiro almost 6 years
    Would you explain how touching it makes the difference? It got me curious.
  • ctrl-alt-delor
    ctrl-alt-delor almost 6 years
    @RuiFRibeiro I think it is because it makes it a different instance of the file, in the layered file-system, that docker uses.
  • Rui F Ribeiro
    Rui F Ribeiro almost 6 years
    Makes sense, will have to remember investigating it. thanks.