I want to run some cron jobs in a Docker container and send the output to stdout. I read this post: How to run a cron job inside a docker container?
To try this out with a simple example, I created a demo crontab:
my-crontab:
* * * * * date > /dev/stdout 2> /dev/stderr
# empty line
Then I run an interactive shell inside a Docker container based on the image my scripts will need:
docker run -it --entrypoint bash python:3.10.3-bullseye
/# apt update
/# apt install cron
/# crontab < my-crontab
/# cron -f
If I wait 60 seconds, I expect to see some output to the console attached to the container once every minute. But there is no output.
Finally, I found the output in /var/spool/mail/mail. Here is one message:
From root@5e3c82cb3651 Tue May 10 20:04:02 2022
Return-path: <root@5e3c82cb3651>
Envelope-to: root@5e3c82cb3651
Delivery-date: Tue, 10 May 2022 20:04:02 +0000
Received: from root by 5e3c82cb3651 with local (Exim 4.94.2)
(envelope-from <root@5e3c82cb3651>)
id 1noW5S-0000SA-0T
for root@5e3c82cb3651; Tue, 10 May 2022 20:04:02 +0000
From: root@5e3c82cb3651 (Cron Daemon)
To: root@5e3c82cb3651
Subject: Cron <root@5e3c82cb3651> date > /dev/stdout 2> /dev/stderr
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
Message-Id: <E1noW5S-0000SA-0T@5e3c82cb3651>
Date: Tue, 10 May 2022 20:04:02 +0000
Tue May 10 20:04:01 UTC 2022
Then it looks like /bin/sh is completely ignoring the shell redirection in the crontab.
2
Answers
@DavidMaze answered this in his comment (above - can't find a link to it). Redirecting to /proc/1/fd/1 and /proc/1/fd/2 (for stderr) totally works. Thank you, David.
Nevertheless, that's counterintuitive. The filesystem nodes /dev/stdout and /dev/stderr already exist as symlinks that point to /proc/1/fd/1 and /proc/1/fd/2, respectively, independent of cron. Why wouldn't
cmd > /dev/stdout
andcmd > /proc/1/fd/1
be interchangeable in a crontab?cron
was written quite a while a ago. And expectedly, it’s not, say,docker
-friendly. It expects tasks to produce no output. And if they do, that is considered an error, andcron
tries to email the responsible person about it. There are some tricks to makecron
tasks’ output to be seen indocker logs
, but why not choose adocker
-friendlycron
implementation?One of which is
supercronic
:docker-compose.yml
:Dockerfile
:crontab
:A gist with a bit more info.
Another good one is
yacron
, but it uses YAML.ofelia
can be used, but they seem to focus on running tasks in separate containers. Which is probably not a downside, but I’m not sure why I’d want to do that.But if you insist on traditional ones, you can find a couple in my other answer.