记一次 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

posted @ 2023-08-02 15:50  流失的痕迹  阅读(19)  评论(0编辑  收藏  举报