Docker容器:如何收集主进程(PID1)以外进程的日志?
Docker默认仅收集容器PID1主进程及其子进程的STDOUT/STDERR到docker logs,而docker exec启动的进程属于独立的进程分支,不在PID1的进程树中,所以输出不会被自动捕获。以下是几种可行的解决办法:
1. 直接重定向到PID1的标准流
在执行docker exec时,将命令的输出重定向到容器内PID1的标准输出/错误对应的文件描述符。容器中PID1的标准输出路径是/proc/1/fd/1,错误输出是/proc/1/fd/2,示例命令:
docker exec my-container your-command >> /proc/1/fd/1 2>> /proc/1/fd/2
这样命令的所有输出会被追加到PID1的输出流中,自然会被docker logs my-container捕获。
2. 统一日志文件路径
在容器启动时,配置主进程将日志输出到一个共享文件,同时确保docker exec的命令也输出到该文件,再通过主进程将文件内容转发到标准流:
- 启动容器时,主进程执行(以bash为例):
tail -f /var/log/container-shared.log & exec your-main-command - 后续执行
docker exec时,将输出定向到该日志文件:docker exec my-container your-command >> /var/log/container-shared.log 2>&1
注意:如果主进程是前台运行,需要确保tail不会成为PID1(否则会影响信号处理),建议使用tini或supervisord作为容器的PID1来管理多个进程。
3. 使用Sidecar容器收集日志
对于多日志源的场景,可以部署一个Sidecar容器与主容器共享存储卷,Sidecar专门负责收集该卷下的日志文件并输出到自身的标准流,这样通过docker logs sidecar-container就能查看所有日志。这种方式适合长期、复杂的日志收集需求,但需要额外的容器配置。
4. 共享主机PID命名空间(不推荐)
启动容器时添加--pid=host参数,让容器共享主机的PID命名空间,此时docker exec的进程会被纳入主机的PID管理,但这会严重破坏容器的隔离性,带来安全风险,仅适合测试或特殊场景。
内容的提问来源于stack exchange,提问作者Reza Alizade

