See cron output via docker logs, without using an extra file

Viewed 27339

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" ?

6 Answers

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

enter image description here

@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.

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"]
Related