Run a bash script as cron job in Docker container - bash

I would like to run a bash script periodically inside a Docker container (my work is based on this answer: https://stackoverflow.com/a/37458519/6240756)
Here is my script hello.sh:
#!/bin/sh
echo "Hello world" >> /var/log/cron.log 2>&1
Here is the cron file hello-cron:
# m h dom mon dow command
* * * * * /app/hello.sh
# Empty line
And here is my Dockerfile:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y cron
# Add backup script
COPY hello.sh /app/
RUN chmod +x /app/hello.sh
# Configure the cron
# Copy file to the cron.d directory
COPY hello-cron /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
# Start the cron
CMD cron && tail -f /var/log/cron.log
I build and run the container but nothing happens. I should see "Hello world" displayed every minutes.
If I replace the call to the script in the cron file by directly echo "Hello world" >> /var/log/cron.log 2>&1 it works, I see "Hello world" every minutes
What am I doing wrong?
EDIT
And the Docker commands:
docker build -t hello-cron .
docker run -t -i hello-cron

About your concrete question
The problem is that you're launching your docker with -t -i, and what you want is a background execution and check it interactively.
Try with:
docker run -d --name mycontainer hello-cron
docker logs -f mycontainer
Best practices
If you are going to execute something periodically, consider if it should be in healthcheck definition, where you can set period and other variables.
Second, note that your cron.log is not mounted, so, you'd lose this info if docker restart.

Related

How to run two docker containers from cron?

I am trying to set up crontab to run two docker containers on system startup/reboot. The line I use to do this after entering the command crontab -e is:
#reboot sh folder_b/run_docker_containers.bash
The script run_docker_containers.bash has the following contents:
#!/bin/bash
# Run containers based on setup_image and main_image
sudo bash /home/user/folder_a/run_setup_docker_container.bash
sudo bash /home/user/folder_b/run_main_docker_container.bash
The scripts run_setup_docker_container.bash and run_main_docker_container.bash both have the following contents (where docker_image is setup_image and main_image, respectively):
#!/bin/bash
/snap/bin/docker run \
--rm \
--detach \
--privileged \
--net=host \
--device /dev/bus/usb \
docker_image:latest \
/bin/bash -c\
"
*SOME COMMANDS*
"
export containerId=$(/snap/bin/docker ps -l -q)
However, the containers are not run when the script is executed on reboot. I prove it finds the script folder_b/run_docker_containers.bash by adding the following code to it and seeing that the new file has been created after reboot.
touch proof_that_crontab_has_done_something.txt
It seems that crontab cannot find the scripts run_setup_docker_container.bash and run_main_docker_container.bash. Any ideas where I'm going wrong?
If you want to execute a shellscript with sudo rights I would recommend using the sudo crontab.
sudo crontab -e
Your personal cronjob should not be able to start a shell with sudo rights. Unless you do some weird modifications.
Use the absolute path
#reboot /...../folder_b/run_docker_containers.bash

How to start cron plus a shelll script in an Ubuntu Docker container

I am attempting to start cron automatically in an Ubuntu 20.10 (Groovy Gorilla) Docker container, thus far without success.
From previous searches (example), I've found a method to start cron using Dockerfile as follows:
# Install and enable cron
RUN apt-get install systemd -y
RUN apt-get install cron -y
RUN systemctl enable cron
# Copy cron file to the cron.d directory
COPY cronfile /etc/cron.d/cronfile
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/cronfile
# Apply cron job
RUN crontab /etc/cron.d/cronfile
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
CMD cron && tail -f /var/log/cron.log
However, I can't make this work with my server setup. I have another, later, CMD in my Dockerfile (similar to this):
CMD ["/usr/sbin/run-lamp.sh"]
and of course only the second CMD will be run. I have tried combining multiple commands:
CMD cron && tail -f /var/log/cron.log && /usr/sbin/run-lamp.sh
but this does not run run-lamp.sh. I also tried putting the commands inside run-lamp.sh, but nothing has resulted in cron starting. Having said that, it is very easy to start cron manually, by opening up a shell in the container and entering the following:
# cron
# crontab /etc/cron.d/cronfile
I am open to suggestions.
All the files I'm working with are available here:
https://github.com/Downes/gRSShopper
In particular:
Dockerfile:
https://github.com/Downes/gRSShopper/blob/master/Dockerfile
run-lamp.sh:
https://github.com/Downes/gRSShopper/blob/master/run-lamp.sh
cronfile:
https://github.com/Downes/gRSShopper/blob/master/cronfile
Thanks in advance.
First off, you don't need that tail -f /var/log/cron.log, it's useless in a container.
Secondly, tail -f is designed to only stop on a signal, and you never signal it, so it will not stop, and therefore the next command, run-lamp.sh, will not run.
Here's a minimal reproducer:
entrypoint.sh:
#!/bin/bash
touch /tmp/x
sleep 120
cronfile:
* * * * * touch /tmp/y
# An empty line is required at the end of this file for a valid cron file.
Dockerfile:
FROM ubuntu:20.10
RUN apt-get update
RUN apt-get install systemd -y
RUN apt-get install cron -y
RUN systemctl enable cron
# Copy cron file to the cron.d directory
COPY cronfile /etc/cron.d/cronfile
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/cronfile
# Apply cron job
RUN crontab /etc/cron.d/cronfile
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
CMD cron && tail -f /var/log/cron.log
COPY entrypoint.sh /entrypoint.sh
CMD /entrypoint.sh
Test command:
docker build -t lamp . \
&& docker rm -f lamp \
&& docker run -d --name lamp lamp \
&& echo waiting for cron... \
&& sleep 61 \
&& docker exec lamp ls /tmp \
&& docker exec lamp sh -c "ps -e | grep cron || echo no cron"
Result:
Sending build context to Docker daemon 71.17kB
Step 1/12 : FROM ubuntu:20.10
...
Successfully tagged lamp:latest
lamp
0fbe19e0583b178543ccf1d1108f72b7f3f6dffb664122621bc67d5939b66672
waiting for cron...
x
no cron
However, with this Dockerfile:
FROM ubuntu:20.10
RUN apt-get update
RUN apt-get install systemd -y
RUN apt-get install cron -y
RUN systemctl enable cron
# Copy cron file to the cron.d directory
COPY cronfile /etc/cron.d/cronfile
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/cronfile
# Apply cron job
RUN crontab /etc/cron.d/cronfile
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
COPY entrypoint.sh /entrypoint.sh
# Run everything in parallel with '&', even the useless tail command
CMD /entrypoint.sh & cron & tail -f /var/log/cron.log
Result:
Sending build context to Docker daemon 87.55kB
Step 1/11 : FROM ubuntu:20.10
...
Successfully tagged lamp:latest
lamp
99dca45fe135326ca96ea90fe21ff7ae23689a56fab5cf0c2ccd8252bc4be84a
waiting for cron...
x
y
10 ? 00:00:00 cron

Docker run to execute script in mount without exiting container automatically?

I have a simple bash script 'test.sh' in the root of mounted folder :
#!/bin/bash
Rscript -e "source('/home/rstudio/mount-folder/src/controller.R')";
However, when i try to mount folder and start the container with docker run as follows:
docker run -d -p 8000:8787 -e ROOT=true -e DISABLE_AUTH=true --name container -v mount-folder/:/home/rstudio/ image_name /home/rstudio/test.sh
above run command starts the container but exits automatically.
I am looking for a docker run command that starts the container , mounts the folder and then executes the bash script which is in the mount-folder without exiting the container.
(** dont want to go with docker exec command as it is not suitable for my use case for other reasons)
Dockerfile:
FROM rocker/rstudio:4.0.2
//some RUN commands to install necessary r packages
EXPOSE 8787
CMD tail -f /dev/null
Other details :
Image that i am using is rstudio server from rocker and container runs on AWS ubuntu machine.
Edit :
have also tried adding CMD tail -f /dev/null at the end of dockerfile as suggested in http://bigdatums.net/2017/11/07/how-to-keep-docker-containers-running/ even then the container exits.
Docker containers shutdown automatically when run in detached mode. I think this article proposes a nice solution:
http://bigdatums.net/2017/11/07/how-to-keep-docker-containers-running/
You could add tail -f /dev/null as the last command in your bash script instead so that the script will never halt unless it is told to do so.
When you do docker run [options] image_name [cmd] the command you specify becomes the command for the container and replaces any the command specified in the dockerfile (that's why adding CMD tail -f /dev/null doesn't do anything). If you ran your container without the /home/rstudio/test.sh at the end, it should stay running.
The solution would be to update your script to add the tail command at the end.
#!/bin/bash
Rscript -e "source('/home/rstudio/mount-folder/src/controller.R')";
exec tail -f /dev/null
If you can't update that script, you could instead add it to the command being passed to the container, with something like:
docker run [options] image_name bash -c '/home/rstudio/test.sh && exec tail -f /dev/null'

Bash shell script not executing command docker entrypoint

I have a shell script, it is not executing the "crontab" command when it is run from docker CMD. But works when I execute the file inside the docker container. What am I missing?
File entry.sh:
#!/bin/sh
echo "Starting cron"
/usr/sbin/cron -f -L 15
crontab /etc/cron.d/cron-python
Docker file:
FROM python:3
RUN apt-get update && apt-get -y install cron
COPY ./cron/entry.sh /entry.sh
COPY ./cron/crontab.txt /etc/cron.d/cron-python
RUN chmod +x /entry.sh
RUN chmod 0644 /etc/cron.d/cron-python
CMD ["./entry.sh"]
cron-python:
# crontab -e
*/1 * * * * python /app/myscript.py >> /var/log/script.log 2>&1
Following should work :
#!/bin/sh
# start cron
echo "Starting cron"
crontab /etc/cron.d/cron-python
/usr/sbin/cron -f -L 15
In your version, /etc/cron.d/cron-python does not get installed as you asked /usr/sbin/cron to run on foreground.
Also you need to copy /app/myscript.py.

Dockerfile CMD not running at container start

So i've written a Dockerfile for a project, i've defined a CMD to run on starting the container to bootstrap the application.
The Dockerfile looks like
# create our mount folders and volumes
ENV MOUNTED_VOLUME_DIR=sites
RUN mkdir /$MOUNTED_VOLUME_DIR
ENV PATH=$MOUNTED_VOLUME_DIR/sbin:$MOUNTED_VOLUME_DIR/common/bin:$PATH
RUN chown -Rf www-data:www-data /$MOUNTED_VOLUME_DIR
# Mount folders
VOLUME ["/$MOUNTED_VOLUME_DIR/"]
# Expose Ports
EXPOSE 443
# add our environment variables to the server
ADD ./env /env
# Add entry point script
ADD ./start.sh /usr/bin/startContainer
RUN chmod 755 /usr/bin/startContainer
# define entrypoint command
CMD ["/bin/bash", "/usr/bin/startContainer"]
The start.sh script, does some git stuff like cloning the right repo, setting environment vars, as well as starting supervisor.
The start script begins with this
#!/bin/bash
now=$(date +"%T")
echo "Container Start Time : $now" >> /tmp/start.txt
/usr/bin/supervisord -n -c /etc/supervisord.conf
I start my new container like this
docker run -d -p expoPort:contPort -t -i -v /$MOUNTED_VOLUME_DIR/$PROJECT:/$MOUNTED_VOLUME_DIR $CONTAINER_ID /bin/bash
when i login to the container i see that supervisor hasn't been started, and neither has nginx or php5-fpm. the /tmp/start.txt file with a timestamp set from the startContainer script doesn't exist, showing its never ran the CMD in the Dockerfile.
Any hints on to get this fixed would be great
This:
docker run -d -p expoPort:contPort -t -i -v /$MOUNTED_VOLUME_DIR/$PROJECT:/$MOUNTED_VOLUME_DIR $CONTAINER_ID /bin/bash
Says 'run /bin/bash' after instantiating the container. E.g. skip CMD.
Try this:
docker run -d -p expoPort:contPort -t -i -v /$MOUNTED_VOLUME_DIR/$PROJECT:/$MOUNTED_VOLUME_DIR $CONTAINER_ID

Resources