CentOS 7 云服务器部署踩坑记(五):Supervisor 进程管理与应用启动

背景#

Python 环境和依赖都准备好了,用 Supervisor 管理应用进程,实现开机自启和崩溃自动重启。这一步的问题集中在:Supervisor 配置本身没问题,但应用就是起不来。


问题一:can’t find command#

报错信息:

flask      FATAL     can't find command '/var/www/flask-app/venv/bin/gunicorn'
streamlit  FATAL     can't find command '/var/www/streamlit-app/venv/bin/streamlit'

虚拟环境里没装对应的包,或路径写错了。

# 先检查文件是否存在
ls -la /var/www/flask-app/venv/bin/gunicorn
ls -la /var/www/streamlit-app/venv/bin/streamlit

# 不存在的话重新安装
cd /var/www/flask-app
source venv/bin/activate
pip install gunicorn
deactivate

cd /var/www/streamlit-app
source venv/bin/activate
pip install streamlit
deactivate

sudo supervisorctl restart all

问题二:No module named ‘_ssl’#

报错信息:

ModuleNotFoundError: No module named '_ssl'

Python 编译时没有 SSL 支持,需要先编译 OpenSSL 1.1.1,再重新编译 Python,然后重建虚拟环境。具体步骤见系列第二篇。

重建虚拟环境:

cd /var/www/streamlit-app
rm -rf venv
python3.11 -m venv venv
source venv/bin/activate
pip install streamlit
deactivate

问题三:Exited too quickly#

报错信息:

flask      FATAL     Exited too quickly (process log may have details)

先查日志:

cat /var/log/flask.err.log | tail -30
cat /var/log/streamlit.err.log | tail -30

日志里会有具体的报错信息,根据提示排查。


问题四:App failed to load#

报错信息:

gunicorn.errors.HaltServer: <HaltServer 'App failed to load.' 4>

Flask 应用本身有问题,无法导入。手动测试:

cd /var/www/flask-app
source venv/bin/activate
python -c "from app import app; print('OK')"

根据报错信息修复。


问题五:Failed to find attribute ‘app’ in ‘app’(最坑的一个)#

报错信息:

Failed to find attribute 'app' in 'app'.

项目里同时存在 app.py 文件和 app/ 文件夹,Python 导入时优先导入了文件夹,找不到 app 属性:

flask-app/
├── app.py       ← 入口文件
├── app/         ← 应用包(与 app.py 同名,冲突!)
│   ├── __init__.py
│   └── ...

把入口文件改名解决:

cd /var/www/flask-app
mv app.py wsgi.py

wsgi.py 内容:

import os
from app import create_app

env = os.getenv('APP_ENV', 'development')
config_name = 'production' if env == 'prod' else 'development'
app = create_app(config_name)

if __name__ == '__main__':
    app.run()

修改 Supervisor 配置(app:app 改为 wsgi:app):

[program:flask]
command=/var/www/flask-app/venv/bin/gunicorn -w 2 -b 127.0.0.1:5000 wsgi:app

重启:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart flask

问题六:No module named ‘config’#

报错信息:

ModuleNotFoundError: No module named 'config'

配置文件不存在,手动创建:

cat > /var/www/flask-app/config.py << 'EOF'
import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'your-secret-key-here'
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'data', 'app.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}
EOF

mkdir -p /var/www/flask-app/data

完整的 Supervisor 配置#

# /etc/supervisord.d/apps.ini

[program:streamlit]
command=/var/www/streamlit-app/venv/bin/streamlit run app.py --server.port 8501 --server.address 127.0.0.1
directory=/var/www/streamlit-app
environment=APP_ENV="prod"
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/streamlit.err.log
stdout_logfile=/var/log/streamlit.out.log

[program:flask]
command=/var/www/flask-app/venv/bin/gunicorn -w 2 -b 127.0.0.1:5000 wsgi:app
directory=/var/www/flask-app
environment=APP_ENV="prod"
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/flask.err.log
stdout_logfile=/var/log/flask.out.log

Supervisor 常用命令#

# 重新加载配置
sudo supervisorctl reread
sudo supervisorctl update

# 查看状态
sudo supervisorctl status

# 启动/停止/重启
sudo supervisorctl start flask
sudo supervisorctl stop flask
sudo supervisorctl restart flask
sudo supervisorctl restart all

# 实时查看日志
tail -f /var/log/flask.err.log
tail -f /var/log/streamlit.out.log

标准排查流程#

# 1. 看状态
sudo supervisorctl status

# 2. FATAL 就看日志
cat /var/log/flask.err.log | tail -30

# 3. 手动测试能否导入
cd /var/www/flask-app
source venv/bin/activate
python -c "from wsgi import app; print('OK')"

# 4. 手动启动测试
gunicorn -w 1 -b 127.0.0.1:5000 wsgi:app

# 5. 修复后重启
sudo supervisorctl restart flask

Streamlit 配置文件#

mkdir -p /root/.streamlit
cat > /root/.streamlit/config.toml << 'EOF'
[server]
headless = true
port = 8501
enableCORS = false
enableXsrfProtection = false

[browser]
gatherUsageStats = false
EOF

问题汇总#

问题 根因 解决方案
can’t find command 包未安装 重新 pip install
No module ‘_ssl’ Python 缺 SSL 支持 重编 Python
Exited too quickly 应用启动失败 查看错误日志
App failed to load 应用代码问题 手动测试导入
attribute not found 文件/文件夹名冲突 重命名入口文件为 wsgi.py
config 缺失 配置文件不存在 手动创建

系列小结#

到这里,整个部署流程走完了。最终架构:

Nginx(80/443)
    ├── misaku.site       → Hugo 静态文件
    ├── app1.misaku.site  → Streamlit(8501)
    └── app2.misaku.site  → Flask(5000)
                             Supervisor 守护

CentOS 7 真的太老了,各种兼容性问题耗费了大量时间。新项目建议直接用 Rocky Linux 9Ubuntu 22.04,能省掉本系列大部分麻烦。


上一篇:Python 包安装与 GCC 版本问题