记一次 gunicorn+python+flask+venv 部署过程
记一次 gunicorn+python+flask+venv 部署过程
flask直接部署到服务器会有警告,本身也是不稳定的,它只是一个应用。需要一个独立的Server来承担WSGI角色和责任。
venv是pytohn的虚拟环境,用来隔离不同项目的包版本不一致的问题。python3.6+以上都自带有,在部署之前先创建虚拟环境。
1、创建python虚拟环境
cd ~
python3 -m venv xxx
这样就在root下创建了xxx这个虚拟环境(也是个文件目录),该目录下也自动创建了几个文件夹。
2、安装gunicorn
cd xxx
bin/pip install gunicorn -i https://pypi.tuna.tsinghua.edu.cn/simple
3、配置命令
可以直接使用命令方式配置启动参数,也可以使用配置文件的方式启动。这里为了后续维护方便,使用的配置文件:
import multiprocessing
import gevent.monkey
gevent.monkey.patch_all()
bind = '127.0.0.1:8777' # 绑定的ip端口号
chdir = '/root/xxx' # gunicorn要切换到的目的工作目录
logdir = '/var/opt/logs/xxx'
timeout = 60 # 超时
worker_class = 'gevent' # 使用gevent模式,还可以使用sync 模式,默认的是sync模式
workers = multiprocessing.cpu_count() * 2 + 1 # 启动的进程数
loglevel = "info" # 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' # 设置gunicorn访问日志格式,错误日志无法设置
pidfile = f"{logdir}/gunicorn.pid"
accesslog = f"{logdir}/access.log"
errorlog = f"{logdir}/error.log"
daemon = True # 是否后台运行
4、自动发布脚本
设计一个自动发布脚本可以放到其他发布工具上去,只需要git合并代码就会触发,爽歪歪。
#!/bin/bash
# 修改APP_NAME为云效上的应用名
SERVE=gunicorn
APP_NAME=xxx
PROG_NAME=$0
ACTION=$1
ENV=$2
APP_START_TIMEOUT=20 # 等待应用启动的时间
APP_PORT=0000 # 应用端口
HEALTH_CHECK_URL=http://127.0.0.1:${APP_PORT}/ping # 应用健康检查URL
HEALTH_CHECK_FILE_DIR=/home/admin/status # 脚本会在这个目录下生成nginx-status文件
APP_HOME=/root/${APP_NAME} # 从package.tgz中解压出来的项目文件放到这个目录下
START_LOG=${APP_HOME}/logs/start.log # 应用的启动日志
GUNICORN_CONFIG=${APP_HOME}/gun_${ENV}.py # gunicorn的配置文件
# 创建出相关目录
mkdir -p ${HEALTH_CHECK_FILE_DIR}
mkdir -p ${APP_HOME}
mkdir -p ${APP_HOME}/logs
usage() {
echo "Usage: $PROG_NAME {start|stop|restart}"
exit 2
}
health_check() {
exptime=0
echo "checking ${HEALTH_CHECK_URL}"
while true
do
status_code=`/usr/bin/curl -L -o /dev/null --connect-timeout 5 -s -w %{http_code} ${HEALTH_CHECK_URL}`
if [ "$?" != "0" ]; then
echo -n -e "\rapplication not started"
else
echo "code is $status_code"
if [ "$status_code" == "200" ];then
break
fi
fi
sleep 1
((exptime++))
echo -e "\rWait app to pass health check: $exptime..."
if [ $exptime -gt ${APP_START_TIMEOUT} ]; then
echo 'app start failed'
exit 1
fi
done
echo "check ${HEALTH_CHECK_URL} success"
}
start_application() {
echo "starting flask process"
gunicorn -c ${GUNICORN_CONFIG} app:${APP_NAME} > ${START_LOG} 2>&1 &
echo "started flask process"
}
stop_application() {
checkpid=`ps -ef | grep ${SERVE} | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
if [[ ! $checkpid ]];then
echo -e "\rno ${SERVE} process"
return
fi
echo "stop ${SERVE} process"
times=60
for e in $(seq 60)
do
sleep 1
COSTTIME=$(($times - $e ))
checkpid=`ps -ef | grep ${SERVE} | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
if [[ $checkpid ]];then
kill -9 $checkpid
echo -e "\r -- stopping ${SERVE} lasts `expr $COSTTIME` seconds."
else
echo -e "\r${SERVE} process has exited"
break;
fi
done
echo ""
}
start() {
start_application
health_check
}
stop() {
stop_application
}
case "$ACTION" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
usage
;;
esac