我想在Docker容器中运行一些cron作业,并将输出发送到stdout。我读了这篇文章:如何在docker容器内运行cron作业?
为了用一个简单的例子来验证这一点,我创建了一个演示crontab:my-crontab:
* * * * * date > /dev/stdout 2> /dev/stderr
# empty line
然后我在Docker容器中运行一个交互式shell,基于我的脚本将需要的映像:
docker run -it --entrypoint bash python:3.10.3-bullseye
/# apt update
/# apt install cron
/# crontab < my-crontab
/# cron -f
如果我等待60秒,我希望每分钟看到一次连接到容器的控制台的输出。但是没有输出
最后,我在/var/spool/mail/mail中找到了输出。这里有一条信息:
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
那么看起来/bin/sh完全忽略了crontab中的shell重定向。
@DavidMaze在他的评论中回答了这个问题(上面-找不到链接)。重定向到/proc/1/fd/1和/proc/1/fd/2(对于stderr)完全有效。谢谢你,大卫。
然而,这是违反直觉的。文件系统节点/dev/stdout和/dev/stderr已经作为符号链接存在,分别指向/proc/1/fd/1和/proc/1/fd/2,独立于cron。为什么cmd > /dev/stdout
和cmd > /proc/1/fd/1
不能在crontab中互换?
cron
是很久以前写的。意料之中的是,它不是,比如说,docker
友好型的。它期望任务不产生任何输出。如果他们这样做了,那就被认为是一个错误,cron
就会试图给负责人发电子邮件。有一些技巧可以使cron
任务的输出在docker logs
中看到,但是为什么不选择一个docker
友好的cron
实现呢?
其中一个是supercronic
:
docker-compose.yml
:
services:
supercronic:
build: .
command: supercronic crontab
Dockerfile
:
FROM alpine:3.17
RUN set -x
&& apk add --no-cache supercronic shadow
&& useradd -m app
USER app
COPY crontab .
crontab
:
* * * * * date
一个要点与更多的信息。
另一个很好的是yacron
,但它使用YAML。
ofelia
可以使用,但它们似乎专注于在单独的容器中运行任务。这可能不是一个缺点,但我不确定为什么我想这样做。
但如果你坚持传统的,你可以在我的另一个答案中找到一些。