1. 部署准备

1.1 生产环境配置

# config.py
import os

class ProductionConfig:
    DEBUG = False
    TESTING = False
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'your-production-secret-key'
    
    # 数据库配置
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    
    # 安全配置
    SESSION_COOKIE_SECURE = True
    REMEMBER_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    REMEMBER_COOKIE_HTTPONLY = True
    
    # 邮件配置
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = int(os.environ.get('MAIL_PORT', 587))
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')

1.2 环境变量设置

# 创建 .env 文件(不要提交到版本控制)
echo "SECRET_KEY=your-super-secret-key-here" > .env
echo "DATABASE_URL=postgresql://username:password@localhost/dbname" >> .env
echo "MAIL_SERVER=smtp.gmail.com" >> .env
echo "MAIL_USERNAME=your-email@gmail.com" >> .env
echo "MAIL_PASSWORD=your-app-password" >> .env

# 加载环境变量
export $(grep -v '^#' .env | xargs)

2. 使用 Gunicorn 部署

2.1 安装 Gunicorn

pip install gunicorn

# 将依赖保存到 requirements.txt
pip freeze > requirements.txt

2.2 创建 WSGI 入口文件

# wsgi.py
from app import create_app
from app.config import ProductionConfig

app = create_app(ProductionConfig)

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

2.3 使用 Gunicorn 启动应用

# 基本启动
gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app

# 带更多配置的启动
gunicorn -w 4 -b 0.0.0.0:8000 \
  --access-logfile - \
  --error-logfile - \
  --preload \
  --timeout 120 \
  wsgi:app

2.4 Gunicorn 配置文件

# gunicorn.conf.py
import multiprocessing

# 服务器绑定
bind = "0.0.0.0:8000"

# 工作进程数
workers = multiprocessing.cpu_count() * 2 + 1

# 工作模式
worker_class = "sync"

# 最大客户端连接数
worker_connections = 1000

# 超时时间
timeout = 120

# 守护进程
daemon = False

# 访问日志
accesslog = "-"

# 错误日志
errorlog = "-"

# 日志级别
loglevel = "info"

# 预加载应用
preload_app = True

# 最大请求数(防止内存泄漏)
max_requests = 1000
max_requests_jitter = 100

启动命令:

gunicorn -c gunicorn.conf.py wsgi:app

3. 使用 Nginx 作为反向代理

3.1 安装 Nginx

# Ubuntu/Debian
sudo apt update
sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

3.2 Nginx 配置文件

# /etc/nginx/sites-available/yourdomain.com
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    # 静态文件处理
    location /static {
        alias /path/to/your/app/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    location /media {
        alias /path/to/your/app/media;
        expires 30d;
    }

    # 反向代理到 Gunicorn
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # WebSocket 支持(如果需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}

# HTTP 重定向到 HTTPS(如果使用 SSL)
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

启用站点:

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t  # 测试配置
sudo systemctl restart nginx

4. 使用 Systemd 管理服务

4.1 创建 Systemd 服务文件

# /etc/systemd/system/yourapp.service
[Unit]
Description=Gunicorn instance to serve your Flask app
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/your/venv/bin"
Environment="SECRET_KEY=your-secret-key"
Environment="DATABASE_URL=your-database-url"
ExecStart=/path/to/your/venv/bin/gunicorn -c gunicorn.conf.py wsgi:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

4.2 管理服务

# 重新加载 systemd 配置
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start yourapp

# 启用开机自启
sudo systemctl enable yourapp

# 查看服务状态
sudo systemctl status yourapp

# 查看日志
sudo journalctl -u yourapp -f

5. 使用 Docker 部署

5.1 创建 Dockerfile

# Dockerfile
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非 root 用户
RUN useradd --create-home --shell /bin/bash app
USER app

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["gunicorn", "-c", "gunicorn.conf.py", "wsgi:app"]

5.2 创建 docker-compose.yml

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - SECRET_KEY=your-secret-key
      - DATABASE_URL=postgresql://user:password@db:5432/yourapp
    depends_on:
      - db
    volumes:
      - ./logs:/app/logs
    restart: unless-stopped

  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=yourapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - web
    restart: unless-stopped

volumes:
  postgres_data:

5.3 构建和运行

# 构建镜像
docker-compose build

# 启动服务
docker-compose up -d

# 查看日志
docker-compose logs -f

6. 使用云平台部署

6.1 Heroku 部署

# 创建 Procfile
echo "web: gunicorn -w 4 -b 0.0.0.0:\$PORT wsgi:app" > Procfile

# 创建 runtime.txt
echo "python-3.9.7" > runtime.txt

# 部署到 Heroku
heroku create yourapp-name
heroku config:set SECRET_KEY=your-secret-key
heroku addons:create heroku-postgresql:hobby-dev
git push heroku main

6.2 PythonAnywhere 部署

# 在 PythonAnywhere 的 WSGI 配置文件
import sys
path = '/home/yourusername/yourapp'
if path not in sys.path:
    sys.path.append(path)

from wsgi import app as application

7. 数据库迁移和初始化

7.1 使用 Flask-Migrate

# 在应用初始化中添加
from flask_migrate import Migrate

migrate = Migrate()

def create_app(config_class=ProductionConfig):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # 初始化扩展
    db.init_app(app)
    migrate.init_app(app, db)
    
    return app

7.2 部署时的数据库操作

# 进入应用目录
cd /path/to/your/app

# 激活虚拟环境
source venv/bin/activate

# 初始化迁移(首次部署)
flask db init

# 生成迁移脚本
flask db migrate -m "Initial migration"

# 应用迁移
flask db upgrade

# 或者在代码中处理
@app.before_first_request
def create_tables():
    db.create_all()

8. SSL/TLS 配置(HTTPS)

8.1 使用 Let’s Encrypt

# 安装 Certbot
sudo apt install certbot python3-certbot-nginx

# 获取证书
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# 自动续期测试
sudo certbot renew --dry-run

8.2 Nginx SSL 配置

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    
    # 其他配置同上...
}

9. 监控和日志

9.1 日志配置

# logging_config.py
import logging
from logging.handlers import RotatingFileHandler
import os

def setup_logging(app):
    if not app.debug:
        if not os.path.exists('logs'):
            os.mkdir('logs')
        
        file_handler = RotatingFileHandler(
            'logs/yourapp.log', 
            maxBytes=10240, 
            backupCount=10
        )
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        file_handler.setLevel(logging.INFO)
        app.logger.addHandler(file_handler)
        app.logger.setLevel(logging.INFO)
        app.logger.info('Application startup')

9.2 健康检查端点

@app.route('/health')
def health_check():
    return jsonify({'status': 'healthy', 'timestamp': datetime.utcnow().isoformat()})

@app.route('/metrics')
@login_required  # 如果需要认证
def metrics():
    # 返回应用指标
    return jsonify({
        'active_users': get_active_users_count(),
        'memory_usage': get_memory_usage(),
        'database_connections': get_db_connections()
    })

10. 部署脚本示例

10.1 自动化部署脚本

#!/bin/bash
# deploy.sh

echo "开始部署 Flask 应用..."

# 拉取最新代码
git pull origin main

# 激活虚拟环境
source venv/bin/activate

# 安装依赖
pip install -r requirements.txt

# 运行数据库迁移
flask db upgrade

# 收集静态文件(如果需要)
# flask collectstatic

# 重启应用
sudo systemctl restart yourapp

# 重启 Nginx
sudo systemctl reload nginx

echo "部署完成!"

10.2 使用 Makefile

# Makefile
.PHONY: deploy test migrate

deploy:
	git pull origin main
	pip install -r requirements.txt
	flask db upgrade
	sudo systemctl restart yourapp
	sudo systemctl reload nginx

test:
	pytest

migrate:
	flask db migrate -m "Auto migration"
	flask db upgrade

logs:
	sudo journalctl -u yourapp -f

11. 安全最佳实践

11.1 安全配置

class ProductionConfig:
    # 安全相关配置
    SESSION_COOKIE_SECURE = True
    REMEMBER_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    REMEMBER_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SAMESITE = 'Lax'
    
    # 防止点击劫持
    @app.after_request
    def set_security_headers(response):
        response.headers['X-Frame-Options'] = 'SAMEORIGIN'
        response.headers['X-Content-Type-Options'] = 'nosniff'
        response.headers['X-XSS-Protection'] = '1; mode=block'
        return response

11.2 防火墙配置

# 配置 UFW 防火墙
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

12. 性能优化

12.1 Gunicorn 优化配置

# gunicorn_optimized.conf.py
import multiprocessing

bind = "unix:/tmp/yourapp.sock"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "gthread"
threads = 4
worker_connections = 1000
max_requests = 1000
max_requests_jitter = 100
preload_app = True
timeout = 120

12.2 使用缓存

from flask_caching import Cache

cache = Cache(config={'CACHE_TYPE': 'RedisCache', 'CACHE_REDIS_URL': 'redis://localhost:6379/0'})

@app.route('/expensive-operation')
@cache.cached(timeout=300)  # 缓存5分钟
def expensive_operation():
    # 耗时操作
    return expensive_result

部署检查清单

  • 配置文件已设置为生产环境
  • 环境变量已正确设置
  • 数据库已迁移到最新版本
  • 静态文件已正确配置
  • SSL证书已安装和配置
  • 防火墙规则已设置
  • 监控和日志已配置
  • 备份策略已制定
  • 域名解析已设置
  • 测试所有功能是否正常

选择适合你项目规模的部署方式。小型项目可以从简单的 Gunicorn + Nginx 开始,大型项目可以考虑 Docker 和云平台部署。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐