unaheidi / unaheidi.github.io

Build a Jekyll blog in minutes, without touching the command line.
https://unaheidi.github.io/
MIT License
1 stars 0 forks source link

supervisor & gunicorn #18

Open unaheidi opened 3 years ago

unaheidi commented 3 years ago

背景

AI 团队有个应用,需要手工安装部分组件,其次,除了 python 运行环境还需要 Java 运行环境,因此,CI/CD 的时候,这个应用不能直接基于公司统一的 python 基础镜像来创建部署镜像,得自己团队手工把镜像 push 到 hub 来部署实例。
用我们公共发布系统部署实例的时候,实例总是点火失败,应用的 owner 向我们寻求帮助。

哪些因素影响排障效率

  1. 用户和支持人员是否熟悉部署环境
  2. 支持人员和用户关注点是否相同

用户和我对 Python 的部署环境,只知道皮毛。 我的关注点一直在:用户是自定义镜像,他自制的镜像是否遵守公司 python 部署规范呢? 用户一开始关注 Java 环境,这一点被我忽略掉了。事后发现后面引入的问题和用户准备这个 Java 环境有直接关系。

问题解决过程

  1. 用户先报 ”ModuleNotFound: no module name ...“ 的错误 这个应该是用户选择了没有安装组件的某个 python 版本导致的。当我搭建测试环境帮用户查找问题的时候,我发现并没有这个问题。估计用户自己搞定了。
  2. 有编码类型的报错 image 这个用户一看是编码的问题,把文件里面的中文改为英文后,不再报错。
  3. 用户看了 gunicorn.log 告诉我 ”进程一直在重启“,web 服务没有启动 image 我上网查了,告诉用户,可以加个 --preload ,会有 gunicorn 详细报错。
    /opt/app/.venv/bin/python3 /opt/app/.venv/bin/gunicorn -c /etc/gunicorn.conf.py --preload wsgi:application
    image
  4. 上述编码问题搞定后,用户的 web 服务是能正常运行的。
  5. 遗留一个问题:实例重启后,用户要的 web 服务进程根本没启动。
  6. 先检查了用户容器的部署文件是否符合公司部署要求。 用户的构建目录和文件、以及 wsgi.py 内 wsgi 接口实例以及按要求命名为 application。
  7. 知识点补漏。 在这个时候,逼着我把和 web 服务运行相关的一些东西搞搞清楚。
    • 用户的 web 服务是没启动,但是,supervisor 这个进程一直都在。 root 12 1 0 Jun07 ? 00:00:14 /usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
    • 正常的话,supervisor 这个进程会调用 python 的 web 进程。 为何总是没有 python 的进程呢?并且 gunicorn.log 没有内容。估计,实例启动后,gunicorn 就没在工作。
    • 是否该查一下 supervisor 的运行日志呢? 真实好主意,我感觉解决问题的思路越来越清晰了。 find / -name supervisor.log image
    • Root Cause 终于出来了 用户为了设置 Java 运行环境,修改了 /etc/profile 文件,并且在 /etc/supervisord.d/gunicorn.ini 文件中增加了下面的内容:
      command=source /etc/profile && /opt/app/.venv/bin/gunicorn -c /etc/gunicorn.conf.py wsgi:application
      这就是 supervisor.log 报错的原因了。
unaheidi commented 3 years ago

本案例的排查过程,为什么给人倒着走的感觉?如果一上来就看 supervisor.log , 问题不就很快就能定位了吗?
🤣 思考了一下,原因如下:

  1. 不知道 supervisor 确切的作用。 是在查问题的过程中,发现这个 supervisor 一直都在,标准 python 应用也有这个进程。才知道应该从这个 supervisor 开始查。
  2. 用户是自定义的镜像,让人很想查看一下他定义的镜像是否符合公司部署规范。
unaheidi commented 3 years ago

😆 这里还有一个很好的问题:为什么公司部署规范中,要求 ”wsgi.py 内 wsgi 接口实例以及按要求命名为 application“ 呢?
😃 其实这个就是公司 python 部署的约定,用相同的配置文件启动 web 服务罢了。看一下 /etc/supervisord.d/gunicorn.ini 文件就能发现这个小密码了。

unaheidi commented 3 years ago

supervisord 进程的日志究竟吐到哪里去了?
这个问题可以抽象为:linux 系统上某个进程,日志吐到哪里怎么查看呢?
lsof -p 进程id | grep .log

为啥返回是 /tensorflow-serving/supervisord.log 这么个怪的路径 ?

unaheidi commented 3 years ago

今天,在帮用户搞定多语言运行环境的过程中,我自己验证了 ~/.bashrc 和 ~/.bash_profile 的区别。
容器中把 java 执行路径等环境配置项分别写在 /home/user/.bashrc 和 /home/user/.bash_profile 这两个文件,然后创建镜像A镜像B
基于镜像A创建的容器,通过公司堡垒机用管理员账号登录后,切换到 user,发现 java 可用。
基于镜像B创建的容器,通过公司堡垒机用管理员账号登录后,切换到 user,发现 java 不可用。

看来,在公司这种环境下,适合把环境变量配置到 /home/user/.bashrc 这个文件中。