6

I am trying to build a docker image which would have a cron. A cron which will delete files from particular location of docker file system. Below is my Dockerfile

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

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

# Copy testfiles folder to docker container.
COPY ./testfiles /opt/

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

RUN (crontab -l -u root; echo "* * * * * root rm -rf /opt/*") | crontab

# Run the command on container startup
CMD cron

ENTRYPOINT ["/bin/sh", "-c", "/bin/bash"]

Everything is successful. my cron is also set in the container

roadrunner:test shailesh$ docker run -it crontest /bin/bash
root@ac31f5acc49f:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@ac31f5acc49f:/# crontab -l
* * * * * root rm -rf /opt/*
root@ac31f5acc49f:/# cd /opt/
root@ac31f5acc49f:/opt# ls  
file1  file10  file11  file12  file13  file14  file15  file16  file17  file18  file19  file2  file20  file21  file22  file23  file24  file25  file3  file4  file5  file6  file7  file8  file9

However it is not running and deleting the files which are in /opt/ folder. Can someone tell me what is wrong in the configuration.

Shailesh Sutar
  • 1,517
  • 5
  • 23
  • 41

4 Answers4

18

Try some thing like this,

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

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

# Add crontab file in the cron directory
ADD crontab /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

create file crontab and add an entry like this

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

Hope this will help you!!!

Gerald Schneider
  • 23,274
  • 8
  • 57
  • 89
Prabhin
  • 314
  • 2
  • 2
  • 2
    Thank you for the answer but this isn't helping. It's not making a log entry in that location `/var/log/cron.log 2>&1` – Shailesh Sutar Aug 03 '18 at 12:12
  • Works great, but environment variables have not the same values than in interactive bash command line with same user – Damien C Jun 09 '20 at 16:25
  • `failed running [/bin/sh -c "crontab /etc/cron.d/hello-cron"]: exit code: 127` – Nicolae Jun 07 '21 at 19:15
  • I think this answer used a wrong syntax for the job definition. When we use `crontab filename` to install cron jobs, the user field (`root` here) should not be put after `* * * * *`. See [Jenny's answer below](https://serverfault.com/a/976645/940850). The user field is needed only for `/etc/crontab` or files inside `/etc/cron.d/`. However, I don't know how to install jobs defined in these files. In ubuntu, `man cron` says `cron` also look for jobs in these files. However, in docker, they do not work. Don't know why – doraemon Jan 12 '22 at 07:46
  • This answer was incredibly helpful. I needed to make 2 small adjustments: 1. Remove `root` from the line in the crontab file, and 2. Add an [empty line](https://serverfault.com/a/230407/474272) under that single line in the crontab to keep cron happy. – stevec Jan 12 '23 at 13:30
3

Your crontab syntax is wrong.

There are two places where you can place cron files:

  • in the user's own crontab file, usually under /var/spool/cron/USERNAME. This is where things get placed automatically if you use the command crontab.
  • in /etc/cron.d

If you place it in /etc/cron.d, the file must contain the name of the user you're running it under, since there's otherwise no connection between the file and the user. But if you use the crontab command, the cron specification will be placed in the crontab belonging to your user (or to the user you specify when invoking crontab), so you don't need to include the username.

So to fix this you can do either one of two things:

  • You can remove the username from the string you're passing to the crontab command, so that it looks like this:

    RUN (crontab -l -u root; echo "* * * * * rm -rf /opt/*") | crontab
  • You can place the crontab entry in a file under /etc/cron.d instead, like this:

    RUN (echo "* * * * * root rm -rf /opt/*" > /etc/cron.d/clearopt)
Jenny D
  • 27,780
  • 21
  • 75
  • 114
  • I found that your approach works. After executing `crontab`, `/var/spool/cron/crontabs/root` is generated, which contains job definitions (no `root` in job definition). However, I cannot get the second one work if I later run `cron -f` to start. I feel that in my ubuntu docker image, `cron -f` does not manage the files in `/etc/cron.d`. Did miss something to let `cron` read the files in `/etc/cron.d`? – doraemon Jan 12 '22 at 07:28
  • EDIT for the previous comment: I should have typed "your **first approach** works". – doraemon Jan 12 '22 at 07:40
0

I had the same issue too. After lots of searching and testing I came up with this solution: Be sure to install 'cron' from your Dockerfile. Then add these lines to your Dockerfile:

ADD cron_start.sh /docker-entrypoint.d
ADD healthcheck.sh /docker-entrypoint.d

The file cron_start.sh simply contains these lines:

#!/bin/bash
echo "Starting cron"
service cron start

Then add this line to add your Dockerfile to create the crontab entry:

RUN (echo "* * * * * /docker-entrypoint.d/healthcheck.sh" | crontab -u root -)

Note, there is no need for an interim file if you tell crontab to get the data from stdin with the "-" flag.

0

I've got the same issue in the same context. My tip is to create a bash script to do whatever you want at the container's startup.
and then set the CMD in the Dockerfile to run it using JSON array syntax.

I have a file start.sh to do some stuff and I use & to run it in the background and then I run cron && apache2-foregroung to start the cron and the apache server.

This is the final command at the end of my Dockerfile:

CMD ./start.sh > web/startup.log & cron && apache2-foreground
Micael Mota
  • 101
  • 1