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

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



Solution 1:[1]

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

Solution 2:[2]

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

Solution 3:[3]

@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

Solution 4:[4]

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.

Solution 5:[5]

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

Solution 6:[6]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tarun Lalwani
Solution 2 MaxBlax360
Solution 3 kirkmadera
Solution 4
Solution 5 Matthias Simonis
Solution 6 mstrap