I'm fairly new to Docker so please bear with me:
I have a collection of 5 java applications that I'm trying to run inside a docker container (via cronjobs inside the container).
I've created my Dockerfile and a docker-compose file as well. I'm able to launch my docker container and I'm able to manually run my applications inside the container. The problem is, it doesn't seem to be running my stuff via the cron. To test, I added a cron entry to echo hello world to a file every minute. It doesn't seem to run. Here are my files:
Dockerfile
FROM ubuntu:latest
ENV LANG C.UTF-8
ENV TZ=EST
ENV DEBIAN_FRONTEND=noninteractive
RUN mkdir -p /wrds/ingesters/logs
WORKDIR /wrds/ingesters
RUN apt-get update && apt-get install -y \
tzdata \
apt-utils \
cron \
default-jdk \
bash \
postgresql \
bsd-mailx \
postfix \
vim
COPY *.jar /wrds/ingesters/
COPY run* /wrds/ingesters/
COPY *.properties /wrds/ingesters/
ADD ingester_cron /etc/cron.d/root
RUN chmod 0644 /etc/cron.d/root
RUN touch /var/log/cron.log
RUN crontab /etc/cron.d/root
RUN mkfifo /var/spool/postfix/public/pickup
RUN echo 'alias ll="ls -la"' >> ~/.bashrc
RUN echo 'stty erase ^H' >> ~/.bashrc
CMD cron -L15 && tail -f /var/log/cron.log
docker-compose.yml (anything in all caps is edited out by me for security issues)
version: '3.5'
services:
wrds_hylo_db_ingesters:
image: HOSTNAME/wrds/CONTAINERNAME
container_name: CONTAINERNAME
restart: always
env_file: env.dev-v2
volumes:
- /ingester_logs:/wrds/ingesters/logs
pid: host
ingester_cron
0 17 * * 1 root /wrds/ingesters/run_script1
0 20 * * 1 root /wrds/ingesters/run_script2
0 23 * * 1 root /wrds/ingesters/run_script3
0 2 * * 2 root /wrds/ingesters/run_script4
* * * * * root echo "Hello World" >> /var/log/cron.log 2>&1
When I run my docker container and ssh in, I get the following:
root#1b0d719feada:/var/log# service cron status
* cron is running
crontab -l
0 17 * * 1 root /wrds/ingesters/run_script1
0 20 * * 1 root /wrds/ingesters/run_script2
0 23 * * 1 root /wrds/ingesters/run_script3
0 2 * * 2 root /wrds/ingesters/run_script4
* * * * * root echo "Hello World" >> /var/log/cron.log 2>&1
Any help would be appreciated!
Maybe you take a look at the logs. Maybe you can see more of what your crons are doing.
Cron: */3 * * * * YOUR-CRON_BLABLA > /dev/stdout logs to the container output
ex.: docker-compose logs -f
I load my cron jobs like this:
COPY ./MY-CRON-FILE.cron /
RUN crontab /tmp/MY-CRON-FILE.cron
...
Depending on the application also sometimes with a certain user:
RUN crontab -u MY-USER /MY-CRON-FILE.cron
Related
I'm trying to have a cron job that calls for an endpoint of my flask application every minute. After building and running the image, I can see the job if I run crontab -l but my flask isn't reporting any call. Any idea why? any help is appreciated! Here's the setup
Dockerfile:
FROM python:3
WORKDIR /app
COPY . /app
RUN apt-get update && apt-get install -y cron curl
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 13800
RUN chmod -v +x start.sh
CMD ["./start.sh"]
here's what's inside start.sh:
#!/bin/sh
/usr/bin/crontab periodicGossipInvoker
# start cron
service cron start
# Flask
python main.py
here's what's inside periodicGossipInvoker:
* * * * * sleep 10; /usr/bin/curl http://0.0.0.0:13800/dict
here's the run:
$ docker run --name="node1" --net=kv_subnet \
> --ip=10.10.0.2 -p 13802:13800 \
> -e ADDRESS="${addr1}" \
> -e VIEW=${initial_full_view} \
> -e REPL_FACTOR=2 \
> kv-store:4.0
Starting periodic command scheduler: cron.
* Serving Flask app "main" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://0.0.0.0:13800/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 104-728-720
The problem is, the flask app never gets any call from the cron job, even though I see the cron job when I do
docker exec -ti 556 crontab -l
* * * * * sleep 10; /usr/bin/curl http://0.0.0.0:13800/dict
I am trying to create docker image that will execute cronjobs from root and custom made user. So far only root user is working:
FROM amazonlinux:2017.09
RUN yum -y install ca-certificates shadow-utils cronie && yum -y clean all
# root cronjob
RUN echo '* * * * * echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2' > ~/cronjob
RUN chmod 0644 ~/cronjob
RUN crontab ~/cronjob
RUN useradd -ms /bin/bash ansible
# Ansible cronjob
USER ansible
RUN echo '* * * * * echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2' > ~/cronjob
RUN chmod 0644 ~/cronjob
RUN crontab ~/cronjob
USER root
CMD ["/usr/sbin/crond", "-n"]
I build this docker using this command docker build -t demotest -f Dockerfile .
I execute the created image using this command docker run -t -i demotest:latest
Result of execution:
> docker run -t -i demotest:latest
root - Working in a coal mine...
root - Working in a coal mine...
root - Working in a coal mine...
root - Working in a coal mine...
Few details:
docker run -t -i demotest:latest bash -c 'ls -l /home/ansible/cronjob'
-rw-r--r-- 1 ansible ansible 81 Jul 11 16:06 /home/ansible/cronjob
docker run -t -i demotest:latest bash -c 'ls -l /root/cronjob'
-rw-r--r-- 1 root root 81 Jul 11 16:06 /root/cronjob
docker run -t -i demotest:latest bash -c 'crontab -u root -l'
* * * * * echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2
docker run -t -i demotest:latest bash -c 'crontab -u ansible -l'
* * * * * echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2
What am I doing wrong?
Updated information
I changed CMD to look like this: CMD ["/usr/sbin/crond", "-n", "-x", "sch"]
This generated the output:
docker run -t -i demotest:latest
debug flags enabled: sch
[1] cron started
log_it: (CRON 1) INFO (RANDOM_DELAY will be scaled with factor 85% if used.)
log_it: (CRON 1) INFO (running with inotify support)
[1] GMToff=0
[1] Target time=1562865060, sec-to-wait=12
user [root:0:0:...] cmd="run-parts /etc/cron.hourly"
user [root:0:0:...] cmd="[ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.monthly"
user [root:0:0:...] cmd="[ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.weekly"
user [root:0:0:...] cmd="[ ! -f /etc/cron.hourly/0anacron ] && run-parts /etc/cron.daily"
user [ansible:500:500:...] cmd="echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2"
user [root:0:0:...] cmd="echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2"
Minute-ly job. Recording time 1562865061
[1] Target time=1562865120, sec-to-wait=60
Minute-ly job. Recording time 1562865061
log_it: (root 8) CMD (echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2)
log_it: (ansible 9) CMD (echo "$USER - Working in a coal mine..." > /proc/1/fd/1 2>/proc/1/fd/2)
root - Working in a coal mine...
This shows that the custom user cronjob is executed but output is not redirected.
So the questions changes to - How to properly redirect stdout to host console?
Change last line of your Dockerfile:
from
CMD ["/usr/sbin/crond", "-n", "-x", "sch"]
to
CMD ["cron", "-f"]
Note:
cron -f --> cron foreground
I am running "cron" in a docker container.
Every day a script is executed.
The output of this script I would like to see via "docker logs "
The process with PID 0 is the cron daemon in my container. Entrypoint starts cron in foreground:
/usr/sbin/crond -f
I understand, that I could redirect the script output to a file "path/to/logs"
07 2 * * * /data/docker/backup_webserver/backupscript.sh >> path/to/logs
and start the container as following to see the logs
"tail -f path/to/logs"
But then the file "path/to/logs" would grow during the runtime of the container.
Is there a possibility to log from crontab, directly to "docker logs" ?
Change your cron file to below
07 2 * * * /data/docker/backup_webserver/backupscript.sh > /dev/stdout
This will make sure the logs go to the container output
Alpine: No need for redirection
using the default cron utility (busybox)
Dockerfile
FROM alpine:3.7
# Setting up crontab
COPY crontab /tmp/crontab
RUN cat /tmp/crontab > /etc/crontabs/root
CMD ["crond", "-f", "-l", "2"]
crontab
* * * * * echo "Crontab is working - watchdog 1"
Centos:
Redirection to /proc/1/fd/1 inside the crontab declaration line
Dockerfile
FROM centos:7
RUN yum -y install crontabs
ADD crontab /etc/cron.d/crontab
RUN chmod 0644 /etc/cron.d/crontab
RUN crontab /etc/cron.d/crontab
CMD ["crond", "-n"]
crontab
* * * * * echo "Crontab is working - watchdog 1" > /proc/1/fd/1
#mcfedr is correct, but it took me a while to understand it with it being a one-liner with variables and some extra code related to setting up cron.
This may be a little bit easier to read. It helped me to write it out explicitly.
# Create custom stdout and stderr named pipes
mkfifo /tmp/stdout /tmp/stderr
chmod 0666 /tmp/stdout /tmp/stderr
# Have the main Docker process tail the files to produce stdout and stderr
# for the main process that Docker will actually show in docker logs.
tail -f /tmp/stdout &
tail -f /tmp/stderr >&2 &
# Run cron
cron -f
Then, write to those pipes in your cron:
* * * * * /run.sh > /tmp/stdout 2> /tmp/stderr
fifo is the way to go, it also useful because it allows cron tasks that are not running as root to write to the output.
I am using a CMD along these lines
ENV LOG_STREAM="/tmp/stdout"
CMD ["bash", "-o", "pipefail", "-c", "mkfifo $$LOG_STREAM && chmod 777 $$LOG_STREAM && echo -e \"$$(env | sed 's/=\\(.*\\)/=\"\\1\"/')\n$$(cat /etc/cron.d/tasks)\" > /etc/cron.d/tasks && cron -f | tail -f $$LOG_STREAM"]
With the tasks in /etc/cron.d/tasks
* * * * */10 www-data echo hello >$LOG_STREAM 2>$LOG_STREAM
I also prepend the env at launch to tasks so it's visible to the tasks, as cron doesnt pass it though by itself. The sed is needed because crontab format requires env vars to be quoted - at least it requires empty vars to be quoted and fails to run tasks if you have an empty var without quotes.
You could just use a FIFO.
mkfifo path/to/logs
When processes exchanging data via the FIFO, the kernel passes all
data without writing it to the filesystem. Thus, the FIFO special has
no contents on the filesystem; the filesystem entry merely serves a
reference point so that processes can access the pipe using a in the
filesystem.
man fifo
For Debian-based images, following Dockerfile works for me (note that /etc/crontab has a slightly different format, compared to user crontab files):
FROM debian:buster-slim
RUN apt-get update \
&& apt-get install -y cron
RUN echo "* * * * * root echo 'Crontab is working - watchdog 1' > /proc/1/fd/1 2>/proc/1/fd/2" > /etc/crontab
CMD ["cron", "-f"]
I have this simple Dockerfile for testing, but this is also same in my LEMP stack in a PHP image: cron jobs simply not being executed in Docker.
This is my testing Dockerfile:
FROM debian:latest
MAINTAINER XY <info#domain.com>
LABEL Description="Cron" Vendor="Istvan Lantos" Version="1.0"
RUN apt-get -y update && apt-get -y dist-upgrade \
&& apt-get -y install \
cron \
rsyslog \
vim
RUN rm -rf /var/lib/apt/lists/*
#cron fixes
RUN touch /etc/crontab /etc/cron.d/* /var/spool/cron/crontabs/*
#COPY etc/cron.d /etc/cron.d
COPY etc/crontab /etc/crontab
#COPY var/spool/cron/crontabs /var/spool/cron/crontabs
RUN chmod 600 /etc/crontab /etc/cron.d/* /var/spool/cron/crontabs/*
RUN touch /etc/crontab /etc/cron.d/* /var/spool/cron/crontabs/*
RUN rm -rf /var/lib/apt/lists/*
COPY docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
CMD ["/docker-entrypoint.sh"]
docker-entrypoint.sh:
#!/bin/bash
set -e
echo PID1 > /dev/null
/etc/init.d/rsyslog start
#Stay in foreground mode, don’t daemonize.
/usr/sbin/cron -f
And this is the Crontab file. I also placed one liners in /etc/cron.d or /var/spool/cron/crontabs with the name of the user, but the effect was the same just like if I modified this base crontab file: cron jobs not will be executed:
MAILTO=""
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/php7/bin:/usr/local/php7/sbin
# 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 )
#
*/1 * * * * root date >> /var/log/cron-test.log 2>&1
This is the output of the /var/log/syslog file:
Jan 23 09:38:39 1ab854e8d9a7 rsyslogd: [origin software="rsyslogd" swVersion="8.4.2" x-pid="14" x-info="http://www.rsyslog.com"] start
Jan 23 09:38:39 1ab854e8d9a7 rsyslogd: imklog: cannot open kernel log(/proc/kmsg): Operation not permitted.
Jan 23 09:38:39 1ab854e8d9a7 rsyslogd-2145: activation of module imklog failed [try http://www.rsyslog.com/e/2145 ]
Jan 23 09:38:39 1ab854e8d9a7 cron[19]: (CRON) INFO (pidfile fd = 3)
Jan 23 09:38:39 1ab854e8d9a7 cron[19]: (*system*) NUMBER OF HARD LINKS > 1 (/etc/crontab)
Jan 23 09:38:39 1ab854e8d9a7 cron[19]: (*) ORPHAN (no passwd entry)
Jan 23 09:38:39 1ab854e8d9a7 cron[19]: (CRON) INFO (Running #reboot jobs)
/var/log/cron-test.log won't be created by the cron job.
I have a question for those who flagged this as "off topic" and SuperUser material, plus this is about general computing HARDWARE AND SOFTWARE: really? Docker questions when become sysadmin stuff? This way every Docker related question here have at least one flag. I'm not against promoting more users to the less known child sites, but we have more change to get the answer here than their.
UPDATE:
This is what I come up with until cron jobs not working:
End of Dockerfile:
COPY cron-jobs.sh /
RUN chmod +x /cron-jobs.sh
COPY docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
CMD ["/docker-entrypoint.sh"]
docker-entrypoint.sh:
#!/bin/bash
set -e
echo PID1 > /dev/null
# Run script in the background (this is not daemonized)
/cron-jobs.sh &
/usr/local/php7/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php7/etc/php-fpm.conf
cron-jobs.sh:
#!/bin/bash
while true; do
date >> /var/log/cron-test.log 2>&1
sleep 60
done
Cron (at least in Debian) does not execute crontabs with more than 1 hardlink, see bug 647193. As Docker uses overlays, it results with more than one link to the file, so you have to touch it in your startup script, so the link is severed:
touch /etc/crontab /etc/cron.*/*
I have an Ubuntu 14.04 docker image that I want to schedule a python script within to execute every minute. My DockerFile contains CMD ["cron","-f"] in order to start the cron daemon. The crontab entry looks like this:
0,1 * * * * root python /opt/com.org.project/main.py >> /opt/com.org.project/var/log/cron.log
/opt/com.org.project/main.py is completely accessible and owned by root and has 744 privileges set; so can be executed.
Nothing is showing up in my /opt/com.org.project/var/log/cron.log file, nor /var/log/cron.log. Yet ps aux | grep cron shows cron -f running at PID 1.
What am I missing? Why is my cron job not running within the container?
Here are my DockerFile contents as requested:
FROM ubuntu
# Update the os and install the dependencies needed for the container
RUN apt-get update \
&& apt-get install -y \
nano \
python \
python-setuptools \
python-dev \
xvfb \
firefox
# Install PIP for python package management
RUN easy_install pip
CMD ["cron", "-f"]
Why use cron? Just write a shell script like this:
#!/bin/bash
while true; do
python /opt/com.org.project/main.py >> /opt/com.org.project/var/log/cron.log
sleep 60
done
Then just set it as entrypoint.
ENTRYPOINT ["/bin/bash", "/loop_main.sh" ]
Where did you use crontab -e? On the host running docker or in the container itself?
I can't see that you are adding an crontab entry in the dockerfile you provided. I recommend you to add an external crontab file like this:
ADD crontabfile /app/crontab
RUN crontab /app/crontab
CMD ["cron", "-f"]
The file crontabfile has to be located next to Dockerfile.
image_folder
|
|- Dockerfile
|- crontabfile
Example content of crontabfile:
# m h dom mon dow command
30 4 * * * /app/myscript.py