Cron task inside container from host - docker

I am trying a cron task inside a container from host but with no luck. From the host I am adding the following line on crontab -e
* * * * * docker exec -it sample_container bash -c 'touch /selected/directory/temp$(date +%H-%M)'
But this is not working. Interestingly, when I run the command independently outside crontab it is successfully executing. Can anyone explain what am I missing here?

Note: when debugging such problems with cron, you should look for errors in your local system mails or redirect those to your real mail by adding MAILTO=yourmail#yourdomain.com on top of your crontab file.
There are 2 problems with your crontab command
TLDR; the fixed cron expression
* * * * * docker exec sample_container bash -c 'touch /selected/directory/temp$(date +\%H-\%M)'
% has a special meaning in crontab
From man -s 5 crontab
Percent-signs (%) in the command, unless escaped with backslash (\),
will be changed into newline characters, and all data after the
first % will be sent to the command as standard input.
So you will need to escape those % signs in your date format string
Cron does not allocate a tty
Cron does not allocate a tty whereas your are trying to use one when executing your command (i.e. the -t option to docker exec). The command will therefore fail with the error the input device is not a TTY
You do not need to go interactive (-i) nor to allocate a tty for this command to do its job anyway, so you have to drop those options to launch it from cron.

Related

Docker container environment variable file during runtime

I have a docker image that basically schedules a cron job at a frequency defined when building the image using the below.
COPY myjobtime /etc/cron.d/myjobtime
RUN chmod 0644 /etc/cron.d/myjobtime &&\
crontab /etc/cron.d/myjobtime
CMD cron
I have the cron entry in the file myjobtime.
*/10 * * * * /usr/local/bin/sh /app/myscript.py
I would like to be able to pass the cron schedule during the runtime. Meaning, if someone wants to modify the cron schedule to a different frequency, they should be able to do that while running the container and passing an environment variable file with the new cron schedule in it. Can this be done?
The important detail is that you need to create and install the crontab file when the container starts up. I find an entrypoint wrapper script to be a useful pattern for this: set the image's ENTRYPOINT to be a shell script that does whatever first-time setup is required, then have it exec "$#" to run the image's CMD.
If your image is ultimately based on a Linux distribution based on the GNU toolset, then envsubst is a really helpful program here. It reads in a text file, expands environment variable references, and writes out the result. I'll assume you have this available; on Alpine-based images you can do similar tricks with sed(1) (though escaping around the cron schedule will become tricky).
This makes the entrypoint wrapper script something like:
#!/bin/sh
# entrypoint.sh
# Set a default schedule, if the user didn't provide one
if [ -z "$CRON_SCHEDULE" ]; then
export CRON_SCHEDULE='*/10 * * * *'
fi
# Run substitutions on the template file and inject the crontab
envsubst < /app/myjobtime.cron.tmpl | crontab
# Run the main container command
exec "$#"
Since the template isn't a "normal" crontab, it can't go in the "normal" crontab directory; putting it in the application directory is fine. That file has an environment variable reference where the schedule would go
# myjobtime.cron.tmpl
${CRON_SCHEDULE} /app/myscript.py
In your image, set the wrapper script to be the ENTRYPOINT, make sure the template file is in the right place, and leave the CMD unchanged.
# (assuming there's not a broad `COPY . .`)
COPY myjobtime.cron.tmpl .
COPY entrypoint.sh .
ENTRYPOINT ["/app/entrypoint.sh"] # must be JSON-array syntax
CMD cron # unchanged
This should allow you to override the cron schedule.
docker run -d --name hourly myappcron
docker run -d --name daily -e 'CRON_SCHEDULE=0 0 * * *' myappcron
Since the entrypoint wrapper script runs whatever command was provided, and you can override the command pretty easily, this also lets you double-check that the right schedule got set.
docker run --rm -e 'CRON_SCHEDULE=0 0 * * *' myappcron \
crontab -l # runs instead of the cron daemon

How to run cron job manually and check the logs in ubuntu

I need to check the printed logs inside my cron file in ubuntu/cent os server. I am explaining my code below.
backup-mongodb.sh
#!/bin/bash
name = "uBot_sandbox"
export DATABASE_NAME="planets"
export BACKUP_LOCATION="/home/UBOT"
for container_name in $(docker ps --filter="name=$name" -q);do
echo "container name : $container_name"
done
I set this file using crontab -e like below.
* * * * * /bin/bash /home/subhrajp/UBOT/git/uBot/python3.7-alpine3.8/app/mean-stack/node-js/utils/backup-mongodb.sh
Here I need to check the echo output of that .sh file once the cronjob started. Also I need to know what is the command to run the cron file manually without starting the cronjob so that I can use it while developing. Please help me to resolve my problem.

Crontab task doesn't work when I edit crontab by vim instead of "crontab -e" on docker container ubuntu18.04

Crontab task doesn't work when I edit crontab by vim instead of "crontab -e" on docker container ubuntu18.04
step 1:
Use docker run a container, the image is ubuntu18.04 os.
step 2:
vim /var/spool/cron/crontabs/root
and Write content to root file as following:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
*/1 * * * * . /etc/profile; /bin/sh /test_cron/xx.sh 2>&1
step 3:
cd /
mkdir test_cron
cd test_cron
step 4:
Edit xx.sh in /test_cron/xx.sh, the content as following:
echo "cron job has start" >> /test_cron/run.log
step 5:
service cron restart
step 6:
There is no run.log in /test_cron/, that’s to say, the crontab task doesn't work. But if I using "crontab -e" to open the /var/spool/cron/crontabs/root file and don't make anything modify. Just open and close the /var/spool/cron/crontabs/root, I can see the run.log file in /test_cron/, amazing, the crontab task worked. Could you tell me the reason?
Few points,
The corntab -e makes sure certain formatting and error tracking to an extent.
crontab file should contain one empty line at the end.
There are certain permission to set to the crontab chmod 600
After completing these I could see the manual entry was working. However it is not recommended to directly edit the crontab file and the best practice is to use crontab -e
EDIT: Actually emptyline should be corrected as newline character or % as per the man page
The "sixth" field (the rest of the line) specifies the command to be
run. The entire command portion of the line, up to a newline or %
character, will be executed by /bin/sh or by the shell specified in
the SHELL variable of the cronfile. Percent-signs (%) in the command,
unless escaped with backslash (), will be changed into newline
characters, and all data after the first % will be sent to the command
as standard input.

Custom shell script in crontab

I've a simple shell script that executes a docker-exec command inside a container.
The script is located in /var/www/mysite-nginx/nginx-reload.sh and permissions of this file are -rwxrwxr-x
#!/bin/sh
docker exec -it mysite_nginx nginx -s reload
If I execute this script directly from shell, it works. But if I add the script to my crontab with the following line, it doesn't work.
15 4 * * * /var/www/mysite-nginx/nginx-reload.sh
I suppose that cron doesn't execute the command, or what is wrong?
On /var/log/syslog I have:
Jul 23 15:30:01 arrubiu CRON[29511]: (sergej) CMD (/var/www/mysite-nginx/nginx-reload.sh)
[EDIT] Solved in this way: docker exec is not working in cron
The issue seems to be that docker is not found. There are two ways around:
You enter the full paths of all application in your crontab script, you can find that out using e.g. locate docker, so that it looks something like
#!/bin/sh
/usr/bin/docker exec -it mysite_nginx
/usr/bin/nginx -s reload
Alternatively, you can set the $PATH and other environment variables in the same way how they are set for a usual sh-script. To achieve that, first backup what is saved in /etc/environment, and then flush it with the currently available variables by executing:
cp /etc/environment > ~/my_etc_environment_backup
env >> /etc/environment
Related questions on SO
Where can I set environment variables that crontab will use?

How te restart the sidekiq when it crushes down?

I started the sidekiq by
bundle exec sidekiq -d -L log/sidekiq.log -C config/sidekiq.yml -e production
Sometime, Sidekiq was crushed, busy=0 and enqueue > 0.
How can I setup the sidekiq to restart after crushed/stopped?
You can use some automated packages, or write your own bash script to do that.
I personally prefer writing my own scripts so let me explain that:
Write a script that executes sidekiq if not running already
Write a cronjob to execute that script every minute
Note that this method is not instant, meaning that you might have a downtime up to 1 minute, since the cronjob works every minute. So if your project is sensitive on that, you might want to use one of the process management tools such as monit or god.
Your bash script should contain your command,
bundle exec sidekiq -d -L log/sidekiq.log -C config/sidekiq.yml -e production
But make sure you are using absolute paths if you are going to store your script outside your project directory.
Here is a helpful topic about writing the shell script to check whether the process already exists.
To run the script every minute, do the following:
Go to your terminal
Type crontab -e
Append * * * * * /bin/bash -l -c 'cd /PATH/TO/YOUR/DIR && sh SCRIPTNAME.sh'
Save and exit editor
By doing this, you are telling your computer to execute your script every minute.
Usually people prefer writing only * * * * * /path/to/script.sh to their crontab but this fails in some circumstances.
Hope this helps.

Resources