
最近在部署容器化的 MX ,其中要用到 OpenDKIM 这个 milter (负责给出站邮件附上 dkim 签名,并检查入站邮件的 dkim 签名),opendkim 有一个问题就是我不知道怎么配才能让它把日志写到 stdout ,它只会往 syslog 写日志,这就是我说的 syslog-only 应用程序。
容器化的实例最好还是把日志写到 stdout ,方便 container supervisor 统一收集和管理,也具有通用性。我可以把宿主机的 /dev/log socket 以 bind mount 的方式挂载到容器的 mount ns ,然而这种做法破坏了容器的自包含性,会让容器部署依赖于宿主机的 syslog socket 的具体位置。并且在公有云 PaaS 或者权限受限的环境下,访问宿主机的 syslog 服务(或修改其配置让它将来着容器的日志转发到特定端点)并不总是可能的。
什么是 syslog ? syslog 它既是一个动态链接库提供的一个函数,也是一种日志分发的方式,依赖于 syslog 打印日志的应用程序称为 syslog client ,一般通过 socket 向本机的 syslog server 通信,syslog server 决定对各个应用发来的日志作何处理。
A. 挂载 (bind mount) 宿主机的 syslog socket 到容器内部,一般位于 /dev/log ,实际上在我的机器上这是一个 symbol link ,指向一个 systemd-journald 负责监听的 socket ,这样就可以让宿主机的 syslog server (systemd-journald) 扮演容器看来缺失了的 syslog server 的角色。前面说了为什么这种做法不行。
B. 我们说了 syslog 函数一般是通过动态链接的方式实现的,也就是说 app 自己的二进制可能没有 syslog client 的实现逻辑,这个逻辑是复用动态链接库里实现好了的 syslog client 的代码,系统通过解析 syslog 函数到真正的实现(一个 PIE shared object 文件)来使得 app 能以符合 syslog client 规范的行为向 syslog socket 发送日志。理论上,可以通过 LD_PRELOAD 的方式,劫持 app 调用的 syslog 函数。我们自己实现一个仿 syslog 函数,和 app 调用的 syslog 函数的签名一样,然后把收到的日志打到 stdout 。这种方案比较复杂,需要在容器构建时,编译这个 PIE shared object 文件,对于 multi-arch 镜像,也需要为每一种 arch 编译一份 shared object 文件。还需要在容器构建过程中安装额外的 toolchain 。
C. 在容器里启动一个轻量级的 syslog server 。这是最简单的、最合理的。既然 app 需要 syslog 才能工作,那就给他一个真的。
--no-caps 参数启动 syslog-ng ,让 shell 读取具名管道,把内容导给一个后台运行的 cat 进程。Dockerfile:
FROM debian:trixie RUN \ apt-get -y update && \ DEBIAN_FROnTEND=noninteractive apt-get -y --no-install-recommends install opendkim opendkim-tools syslog-ng && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* COPY <<EOF /etc/syslog-ng/syslog-ng.conf destination d_pipe { pipe("/var/log/any.log.pipe"); }; source src { system(); }; log { source(src); destination(d_pipe); }; EOF COPY <<EOF /entrypoint.sh #!/bin/bash mkfifo /var/log/any.log.pipe syslog-ng --no-caps cat </var/log/any.log.pipe & exec /usr/sbin/opendkim -f -x /etc/opendkim/opendkim.conf EOF RUN chmod +x /entrypoint.sh CMD [ "/entrypoint.sh" ] 1 defunct9 4 小时 28 分钟前 容器里的 opendkim 掉了,syslog-ng 没掉,怎么办 |
2 beyondstars OP @defunct9 或许会考虑用 tini 作为一个轻量的 supervisor ,或者 docker run 加 --init 参数。 |
3 beyondstars OP 还有一种方法是在 Dockerfile 编写自定义的 healthcheck ,docker 应该会自动重启 unhealthy 的容器 |
4 defunct9 3 小时 12 分钟前 -f Normally opendkim forks and exits immediately, leaving the service running in the background. This flag suppresses that behaviour so that it runs in the foreground. So, 一定是你某个地方配的不对。 |