部分较小的项目例如flask,对内部使用,可无需使用web server,直接用flask自带服务即可完成需求,但考虑到直接使用python app.py
启动flask后,运行过程进程可能会退出,因此有必要对其进行监控并自动重启,supervisor可满足需求,加上其用python写成,可以独自进行二次开发(supervisor的代码值得学习)。本文是对以往部分项目进行一个整理,作为参考资料归档。
1、离线安装supervisor
supervisor下载地址:https://files.pythonhosted.org/packages/ca/1f/07713b0e1e34c312450878801d496bce8b9eff5ea9e70d41ff4e299b2df5/supervisor-4.1.0-py2.py3-none-any.whl
setuptools的下载地址:
https://files.pythonhosted.org/packages/d9/de/554b6310ac87c5b921bc45634b07b11394fe63bc4cb5176f5240addf18ab/setuptools-41.6.0-py2.py3-none-any.whl
先安装setuptools
unzip setuptools-41.6.0.zip && cd setuptools-41.6.0
python setup.py install
再安装supervisor
unzip supervisor-4.1.0.tar.gz && cd supervisor-4.1.0
python setup.py install
# 测试是否安装成功
[root@~d]# python
>>> import supervisor
>>>
2、配置supervisor环境变量
很多网上教程在安装完supervisor后,都会给出如下提示:
在/etc/supervisor目录下生成配置文件
echo_supervisord_conf>/etc/supervisord.conf
但如果echo_supervisord_conf或者supervisord 二进制程序所在目录没有配到PATH环境变量的话,那么提示未找到对应的命令
[root@wap ~]# echo_supervisord_conf>/etc/supervisord.conf
-bash: echo_supervisord_conf: command not found
查找echo_supervisord_conf 在哪个目录下
2.1 PATH的问题
一般会在python的安装目录下,例如/usr/local/python27/bin 或者在编译安装python所设定的路径
[root@wap~]# which python3.5 /usr/local/bin/python3.5
但会有例外:
很多人安装python后,并没有把python的bin路径设到PATH里,而是直接把新安装的python 路径通过软链接的方式覆盖旧python,例如下面所示:
ln -s /usr/bin/python3.5 /usr/bin/python
虽然这种方式在可以启动python3.5,但一旦安装新的库后,这些库所在路径不是位于python3.5目录下,而是位于系统默认的bin目录下,如下面所示:
[root@wap ~]# ls /usr/bin/
flask python3.5 pyvenv-3.5 pip3 supervisorctl supervisord echo_supervisord_conf
这里flask库和supervisor库都在/usrl/bin/
目录下
而此时查看系统系统的path变量,centos最初始的path配置如下
# .bash_profile
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin
export PATH
显然没有加入python的环境变量,修改后如下:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
PATH=$PATH:$HOME/bin:/usr/bin/
export PATH
到此,supervisor的相关命令可在shell直接使用
[root@wap ~]# echo_supervisord_conf
; Sample supervisor config file.
;
; For more information on the config file, please see:
......
3、 将supervisor配置成service,并加入开机自启
3.1 加入service
离线安装supervisor后,还需配置开机启动service,这里要注意:
需要将 daemon "supervisord -c /etc/supervisord.conf "
改为daemon "/usr/bin/supervisord -c /etc/supervisord.conf "
完整的service配置如下:
[root@wap ~]# vi /etc/rc.d/init.d/supervisord
#!/bin/bash
# source function library
. /etc/rc.d/init.d/functions
RETVAL=0
start() {
echo -n $"Starting supervisord: "
daemon "/usr/bin/supervisord -c /etc/supervisord.conf "
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/supervisord
}
stop() {
echo -n $"Stopping supervisord: "
killproc supervisord
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/supervisord
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|force-reload|reload)
restart
;;
condrestart)
[ -f /var/lock/subsys/supervisord ] && restart
;;
status)
status supervisord
RETVAL=$?
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
exit 1
esac
exit $RETVAL
修改文件权限为755,并设置开机启动
chmod 755 /etc/rc.d/init.d/supervisord
chkconfig supervisor on
3.2 修改默认的/etc/supervisord.conf
[unix_http_server]
file=/var/run/supervisor.sock
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; 修改为 /var/log 目录,避免被系统删除
pidfile=/var/run/supervisord.pid
...
[supervisorctl]
; 和'unix_http_server'里面的设定匹配
serverurl=unix:///var/run/supervisor.sock
注意:/var/log/supervisor/supervisord.log
需要手动创建
3.4、配置supervisord的web界面
[inet_http_server]
port=*:36700
username=***
password=***
3.5、配置管理进程
配置管理进程有两种方式,一种是直接在supervisord.conf文件写入相关进程配置,另外一种是在某个目录下,为每个进程单独创建一份配置文件,然后把这些配置文件include到supervisord.conf,已防止supervisord.conf的全局配置被错误修改。
# /etc/supervisor/config,用于存放全部进程管理的配置文件
[root@wap ~]# mkdir -p /etc/supervisor/config
# 在/etc/supervisord.conf全局配置文件中的include参数,
# 将/etc/supervisor/config目录添加到include中
[include]
files =/etc/supervisor/config/*.ini
这里以配置flask两个小项目作为示例
[root@wap ~]# vi /etc/supervisor/config/flask_app_1.init
[program:flask_app_1]
command=python /opt/flask_app_1/app.py
# 日志目录需要手动创建,文件名由supervisor创建
stdout_logfile=/etc/supervisor/logs/flask_app_1.log
# stdout日志文件大小,默认50MB,这里设为10M
stdout_logfile_maxbytes=10MB
# 限制保存最近10个日志
stdout_logfile_backups=10
# 在 supervisord 启动的时候也自动启动
autostart=true
# 把stderr重定向到stdout,默认false
redirect_stderr = true
# 程序异常退出后自动重启
autorestart=true
# 启动5秒后若没有异常退出,则认为该服务已经正常启动
startsecs=5
user=root ;默认使用root用户
priority=10 ;该进程的优先级
stopasgroup=true ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=true ;默认为false,向进程组发送kill信号,包括子进程
flask_app_2同上配置,注意实际使用中,应与相关需求或功能命名。
4、启动supervisor并测试
这里因为已经将supervisor配置成service,故不需要再使用
supervisord -c /etc/supervisord.conf
这样的命令启动supervisor
[root@wap ~]# service supervisor start
Starting supervisord: [ OK ]
[root@wap ~]# service supervisor status
supervisord (pid 18921) is running...
[root@wap ~]# service supervisor stop
Stopping supervisord: [ OK ]
[root@wap ~]# service supervisor restart
Stopping supervisord: [ OK ]
Starting supervisord: [ OK ]
以上说明supervisor的service配置是成功的。
# 查看已经被管理进程,这里有两种方式,一种在web 页面查看与操作,另外一种则用cli方式查看
# cli查看相关被管理进程服务
[root@portal py_apps]# supervisorctl
flask_app_1 RUNNING pid 191047, uptime 0:11:04
flask_app_2 RUNNING pid 191047, uptime 0:11:04
supervisor>
# 重启几次flask,查看其日志
[root@wap ~]# cat /etc/supervisor/logs/flask_app_1.log
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
通过web查看和管理进程
5、supervisor分布式管理服务
例如在serverA放了app1,serverB放了app2,serverC放了app3,而且每个server还有自行开发的其他采集模块等,因supervisor只能管理单机上的进程,对于不同服务器上的进程管理,则需要借助其他工具:例如cesi,地址:https://github.com/Gamegos/cesi
。它可以实现跨服务器管理进程。当然我们完全可以基于supervisor进行开发,利用它提供的rpc接口,也可以开发出集群管理工具。但不建议这么做,考虑到还需要主力攻项目,这些通用工具能用第三方可优先使用。本文不再对cesi进行测试。