Filebeat无法收集Jupyter日志解决记录

载荷系统的 Jupyter 镜像,在本地启动的容器无法将日志正确采集到 ES,本文记录一下解决过程

检查分析

  1. 使用 root 用户启动容器,尝试执行 supervisord -c /usr/local/etc/supervisord.conf,进程正常,filebeat 与 jupyter 正常启动,supervisor 无报错,但是日志无法收集到 ES

  2. 使用 jovyan 用户启动容器,尝试执行 supervisord -c /usr/local/etc/supervisord.conf,进程正常,filebeat 与 jupyter 正常启动,supervisor 无报错,日志依旧无法收集到 ES

  3. 使用 root 用户启动容器,尝试修改 /usr/local/etc/supervisord.conf 文件,关闭前台显示,执行 su - jovyan 执行 supervisord -c /usr/local/etc/supervisord.conf,报错,提示 supervisor 命令未找到,切换回 root,使用 which 查找 supervisor 命令,发现位于 /opt/conda/bin/supervisord,切换回 jovyan 用户,使用绝对路径尝试启动 supervisor,依旧无效,引发思考:

    1. 是否容器的环境变量无法继承?无论是 root 还是 jovyan 进入容器时都可以正确执行 supervisord 命令,使用 /bin/su 命令后却无法查找到命令,猜测可能环境变量不继承,无法传递 PATH
    2. 如果上述情况确认,那么 supervisor 中为 filebeat 配置的启动命令就是错误的,但是 supervisor 却没有任何报错?是否是用户权限问题导致的日志无法采集?
  4. 使用 jovyan 用户启动容器,切换到 filebeat 目录,直接执行 ./filebeat -e -v,进程正常启动,新开一个 console,写入测试信息到 /tmp/start-notebook.log 中,等待一阵后发现 ES 成功采集到日志。

  5. 使用 root 用户启动容器,直接执行 /bin/su -c "cd /home/jovyan/filebeat5/ && ./filebeat -e -v" jovyan,进程正常启动,新开一个 console,写入测试信息到 /tmp/start-notebook.log 中,ES 无法采集日志,仔细排查后发现问题:

    1. 使用 ps -ef 命令查看进程时发现,filebeat 进程的属主为 root,并非 jovyan
    2. 查看 /tmp/start-notebook.log 文件,发现属主为 jovyan,并非 root

猜想尝试

猜想

是否 filebeat 内置权限隔离?需要进程与文件的属主一致才可以正常采集日志?

验证

登录线上 5119 环境检查,发现 supervisor 容器启动后的 CloudWatch 日志中,并没有以 root 启动 supervisor 而特有的警告信息

1
2021-03-29 08:08:46,817 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  If you intend to run as root, you can set user=root in the config file to avoid this message.
CloudWatch日志截图

此现象证明,容器中 supervisor 是以 jovyan 用户启动的,并非 root 用户,因此需要修改启动命令,替换掉原来的 /bin/su 的方式

结果

修改后使用 jovyan 用户启动容器,服务正常启动,日志也正确收集。

总结

使用 supervisor 创建 filebeat 的守护进程时,由于 supervisor 是以普通用户身份启动,因此在编写 Supervisord 的时候,command 命令中不应该使用 /bin/su -c,该命令会引发 supervisor 的提权行为,导致启动的 filebeat 进程的属主为 root,filebeat 不允许用户与日志文件属主不对等。

√ 正确案例

1
2
3
4
5
6
7
8
[program:filebeat]
command=/bin/bash -c "/home/jovyan/filebeat/filebeat -e -v -c /home/jovyan/filebeat/filebeat.yml"

[program:filebeat5]
command=/bin/bash -c "/home/jovyan/filebeat5/filebeat -e -v -c /home/jovyan/filebeat5/filebeat.yml"

[program:notebook]
command=/bin/bash -c "start-notebook.sh --NotebookApp.default_url=%(ENV_DEFAULT_URL)s &>> /tmp/start-notebook.log"

× 错误案例

1
2
3
4
5
6
7
8
[program:filebeat]
command=/usr/bin/su -c "cd /home/jovyan/filebeat/ && ./filebeat -e -v" jovyan

[program:filebeat5]
command=/usr/bin/su -c "cd /home/jovyan/filebeat5/ && ./filebeat -e -v" jovyan

[program:notebook]
command=/bin/bash -c "start-notebook.sh --NotebookApp.default_url=%(ENV_DEFAULT_URL)s &>> /tmp/start-notebook.log"

新 ES 采集容器的 userlog 正常,但是采集 container_log 异常,老 ES 可以正常采集 container_log

排查过程

  1. 本地启动容器,尝试执行 supervisord -c /usr/local/etc/supervisord.conf,进程正常,filebeat 与 jupyter 正常启动,supervisor 无报错,日志正常收集到新 ES,引发思考:

思考:检查 Dockerfile 发现,CMD 写的是 ["supervisord", "-c", " /usr/local/etc/supervisord.conf"],猜测是否引用了 py2 版本的 supervisor 或者旧版?

尝试

登录容器,执行 which supervisord 发现文件位于 /opt/conda/bin/supervisord,尝试修改 Dockerfile,修改 CMD 命令为 ["/opt/conda/bin/supervisord", "-c", "/usr/local/etc/supervisord.conf"]

验证

重新发布 base 镜像和 test 镜像,启动容器测试

结果

日志正确收集

总结

编写 Dockerfile 时,应注意 CMD 命令是否使用了绝对路径或注意 PATH 变量的值,如果包含旧版本应用,不使用绝对路径可能会导致启动结果与预期不一致的问题。