通过 docker 日志查看 cron 输出,无需使用额外文件

Posted

技术标签:

【中文标题】通过 docker 日志查看 cron 输出,无需使用额外文件【英文标题】:See cron output via docker logs, without using an extra file 【发布时间】:2018-01-05 19:34:57 【问题描述】:

我在 docker 容器中运行“cron”。 每天都会执行一个脚本。 我想通过“docker logs”查看此脚本的输出

PID 为 0 的进程是我容器中的 cron 守护进程。入口点在前台启动 cron:

/usr/sbin/crond -f 

我了解,我可以将脚本输出重定向到文件“path/to/logs”

07 2 * * * /data/docker/backup_webserver/backupscript.sh >> path/to/logs

并按以下方式启动容器以查看日志

"tail -f path/to/logs" 

但是文件“path/to/logs”会在容器运行期间增长。 是否可以从 crontab 直接登录到“docker logs”?

【问题讨论】:

我创建了一个仓库来解决这个问题:github.com/tomsaleeba/alpine-cron-test。答案似乎是不添加任何额外的重定向,它会“正常工作”,至少对于我简单的echo 测试而言。 在我的情况下,This answer 是唯一有效的方法。 【参考方案1】:

将您的 cron 文件更改为以下

07 2 * * * /data/docker/backup_webserver/backupscript.sh > /dev/stdout

这将确保日志进入容器输出

【讨论】:

当使用crond -l 2 -f开始时,这适用于Alpine 为什么会这样?我以为/dev/stdout 实际上会转到/proc/self/fd/1,对于cron 启动的进程,这不会是docker 监控的/proc/1/fd/1 文件。 我认为这不会起作用,因为 /dev/stdout 是访问它的进程的 STDOUT 的链接。因此,通过执行 foo > /dev/stdout,您是在说“将我的 STDOUT 重定向到我的 STDOUT”。 Kinda 什么都不做 :-)。 添加到我自己的评论中,我认为 cron 正在收集作业的输出并将其传递给 its 标准输出,码头工人监控。 @TomSaleeba,是的,因为重定向是在 cron 的进程中运行的,这就是为什么 stdout 只是 cron 的原因【参考方案2】:

你可以只使用 FIFO。

mkfifo path/to/logs

当进程通过 FIFO 交换数据时,内核将所有 数据而不将其写入文件系统。因此,FIFO 特殊具有 文件系统上没有内容;文件系统条目仅用于 参考点,以便进程可以使用 a 访问管道 文件系统。

man fifo

【讨论】:

【参考方案3】:

fifo 是要走的路,它也很有用,因为它允许未以 root 身份运行的 cron 任务写入输出。

我正在按照这些思路使用 CMD

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

/etc/cron.d/tasks中的任务

* * * * */10 www-data echo hello >$LOG_STREAM 2>$LOG_STREAM

我还在启动时将 env 添加到 tasks,因此它对任务是可见的,因为 cron 不会自行传递它。 sed 是必需的,因为 crontab 格式需要引用环境变量 - 至少它需要引用空变量,并且如果您有一个没有引号的空变量,则无法运行任务。

【讨论】:

【参考方案4】:

Alpine:无需重定向

使用默认的 cron 实用程序 (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:

在 crontab 声明行中重定向到 /proc/1/fd/1

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

【讨论】:

我很好奇...为什么将 crontab 复制到 /tmp 然后再复制到 /etc/crontabs/root? Debian 应用补丁来取消标准输出,与 CentOS 类似:salsa.debian.org/debian/cron/-/blob/master/debian/patches/fixes/… 我猜 Alpine 是唯一不应用此补丁的人 我建议您在 CentOS 的答案中添加 2>/proc/1/fd/2 以捕获发送到 stderr 的错误 你能告诉我这是什么意思吗:using the default cron utility (busybox) 我的ubuntu 有一个busybox 二进制文件/usr/bin/busybox,其中包含一组小程序。我需要使用busybox appletname 来访问它们。你怎么能在busybox中引用你的crond而不在你的命令中提到busybox【参考方案5】:

@mcfedr 是正确的,但我花了一段时间才理解它,因为它是一个带有变量和一些与设置 cron 相关的额外代码的单行代码。

这可能更容易阅读。它帮助我明确地写出来。

# 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

然后,写入 cron 中的那些管道:

* * * * * /run.sh > /tmp/stdout 2> /tmp/stderr

【讨论】:

谢谢你 - 我能够理解逐行细分 - 它有效 ?

以上是关于通过 docker 日志查看 cron 输出,无需使用额外文件的主要内容,如果未能解决你的问题,请参考以下文章

如何查看docker日志 怎样查看docker日志

docker容器内部日志本地怎么查看

cron 如何根据日期输出到新的日志文件?

docker一次查看两个容器日志

解决crontab cron 无日志 开启日志 log

dockerdocker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志