Skip to content

第17章:部署上线

17.2 部署方案

在上一节中,我们学习了如何配置Django生产环境。本节将介绍几种常见的Django部署方案,包括使用Nginx + Gunicorn的传统部署方式、云平台部署以及静态文件CDN加速。

Nginx + Gunicorn

Nginx + Gunicorn是Django应用最常见的部署组合。Nginx作为反向代理服务器处理静态文件和负载均衡,Gunicorn作为WSGI服务器运行Django应用。

Gunicorn配置

首先安装Gunicorn:

bash
pip install gunicorn

创建Gunicorn配置文件:

python
# gunicorn.conf.py
import multiprocessing

# 服务器套接字
bind = "127.0.0.1:8000"
backlog = 2048

# 工作进程
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2

# 重启策略
max_requests = 1000
max_requests_jitter = 100

# 日志
loglevel = "info"
accesslog = "/var/log/gunicorn/access.log"
errorlog = "/var/log/gunicorn/error.log"
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'

# 进程命名
proc_name = "myproject"

# 服务器力学
preload_app = True
daemon = False
pidfile = "/var/run/gunicorn.pid"
user = "www-data"
group = "www-data"

# SSL(如果直接使用Gunicorn处理HTTPS)
# keyfile = "/path/to/keyfile"
# certfile = "/path/to/certfile"

# 性能调优
worker_tmp_dir = "/dev/shm"

启动Gunicorn:

bash
# 使用配置文件启动
gunicorn --config gunicorn.conf.py myproject.wsgi:application

# 或者直接启动
gunicorn myproject.wsgi:application --bind 127.0.0.1:8000 --workers 3

Nginx配置

安装Nginx:

bash
# Ubuntu/Debian
sudo apt update
sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

创建Nginx站点配置:

nginx
# /etc/nginx/sites-available/myproject
upstream app_server {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen 80;
    server_name yourdomain.com;
    
    # 重定向到HTTPS(如果配置了SSL)
    # return 301 https://$server_name$request_uri;
    
    client_max_body_size 10M;
    
    # 静态文件处理
    location /static/ {
        alias /var/www/myproject/staticfiles/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    location /media/ {
        alias /var/www/myproject/media/;
        expires 30d;
        add_header Cache-Control "public";
    }
    
    # 动态请求转发给Gunicorn
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server;
    }
    
    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
}

# HTTPS配置(如果需要)
server {
    listen 443 ssl http2;
    server_name yourdomain.com;
    
    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;
    
    # SSL安全配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # 启用HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;
    
    # 其他配置与HTTP服务器相同
    client_max_body_size 10M;
    
    location /static/ {
        alias /var/www/myproject/staticfiles/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    
    location /media/ {
        alias /var/www/myproject/media/;
        expires 30d;
        add_header Cache-Control "public";
    }
    
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server;
    }
}

启用站点并重启Nginx:

bash
# 启用站点
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/

# 测试配置
sudo nginx -t

# 重启Nginx
sudo systemctl restart nginx

系统服务配置

为了确保Gunicorn在系统启动时自动运行,我们可以创建一个systemd服务:

ini
# /etc/systemd/system/myproject.service
[Unit]
Description=MyProject Django Application
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myproject
ExecStart=/var/www/myproject/venv/bin/gunicorn --config gunicorn.conf.py myproject.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always

# 环境变量
Environment=DJANGO_ENV=production
Environment=DJANGO_SECRET_KEY=your-secret-key
Environment=DB_PASSWORD=your-db-password

[Install]
WantedBy=multi-user.target

启动并启用服务:

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

# 启动服务
sudo systemctl start myproject

# 设置开机自启
sudo systemctl enable myproject

# 检查服务状态
sudo systemctl status myproject

云平台部署

现代Django应用也可以部署到各种云平台,包括Heroku、AWS、Google Cloud、Azure等。

Heroku部署

  1. 创建Procfile:
web: gunicorn myproject.wsgi:application --log-file -
  1. 创建runtime.txt指定Python版本:
python-3.11.5
  1. 安装并配置django-heroku:
bash
pip install django-heroku
python
# settings/production.py
import django_heroku

# 在文件末尾激活Heroku配置
django_heroku.settings(locals())
  1. 部署到Heroku:
bash
# 安装Heroku CLI并登录
heroku login

# 创建应用
heroku create myproject

# 设置环境变量
heroku config:set DJANGO_ENV=production
heroku config:set DJANGO_SECRET_KEY=your-secret-key

# 部署代码
git push heroku main

Docker部署

创建Dockerfile:

dockerfile
# Dockerfile
FROM python:3.11-slim

# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# 设置工作目录
WORKDIR /app

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

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

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

# 复制项目文件
COPY . /app/

# 创建非root用户
RUN adduser --disabled-password --gecos '' appuser && \
    chown -R appuser:appuser /app
USER appuser

# 暴露端口
EXPOSE 8000

# 运行应用
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

创建docker-compose.yml:

yaml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DJANGO_ENV=production
      - DJANGO_SECRET_KEY=your-secret-key
    volumes:
      - static_volume:/var/www/myproject/staticfiles
      - media_volume:/var/www/myproject/media
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=myproject
      - POSTGRES_USER=myproject
      - POSTGRES_PASSWORD=your-db-password
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - static_volume:/var/www/myproject/staticfiles
      - media_volume:/var/www/myproject/media
    depends_on:
      - web

volumes:
  postgres_data:
  static_volume:
  media_volume:

静态文件CDN

为了提高静态文件的加载速度,可以将静态文件部署到CDN上。

使用AWS S3和CloudFront

  1. 安装依赖:
bash
pip install django-storages boto3
  1. 配置settings:
python
# settings/production.py
import os

# AWS配置
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME', 'us-east-1')
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'

# 静态文件存储
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/static/'

# 媒体文件存储
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/media/'

# S3设置
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
AWS_S3_VERIFY = True
  1. 收集静态文件:
bash
python manage.py collectstatic --noinput

使用阿里云OSS

  1. 安装依赖:
bash
pip install django-oss-storage
  1. 配置settings:
python
# settings/production.py
import os

# 阿里云OSS配置
OSS_ACCESS_KEY_ID = os.environ.get('OSS_ACCESS_KEY_ID')
OSS_ACCESS_KEY_SECRET = os.environ.get('OSS_ACCESS_KEY_SECRET')
OSS_BUCKET_NAME = os.environ.get('OSS_BUCKET_NAME')
OSS_ENDPOINT = os.environ.get('OSS_ENDPOINT')

# 静态文件存储
STATICFILES_STORAGE = 'django_oss_storage.backends.OssStaticStorage'
STATIC_URL = f'https://{OSS_BUCKET_NAME}.{OSS_ENDPOINT}/static/'

# 媒体文件存储
DEFAULT_FILE_STORAGE = 'django_oss_storage.backends.OssMediaStorage'
MEDIA_URL = f'https://{OSS_BUCKET_NAME}.{OSS_ENDPOINT}/media/'

使用腾讯云COS

  1. 安装依赖:
bash
pip install qcloud_cos django-cos-storage
  1. 配置settings:
python
# settings/production.py
import os

# 腾讯云COS配置
COS_SECRET_ID = os.environ.get('COS_SECRET_ID')
COS_SECRET_KEY = os.environ.get('COS_SECRET_KEY')
COS_REGION = os.environ.get('COS_REGION')
COS_BUCKET = os.environ.get('COS_BUCKET')

# 静态文件存储
STATICFILES_STORAGE = 'django_cos_storage.backends.CosStaticStorage'
STATIC_URL = f'https://{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com/static/'

# 媒体文件存储
DEFAULT_FILE_STORAGE = 'django_cos_storage.backends.CosMediaStorage'
MEDIA_URL = f'https://{COS_BUCKET}.cos.{COS_REGION}.myqcloud.com/media/'

监控和维护

部署完成后,还需要考虑应用的监控和维护。

健康检查端点

创建健康检查视图:

python
# views.py
from django.http import JsonResponse
from django.db import connections
from django.db.utils import OperationalError
import redis
import os

def health_check(request):
    """健康检查端点"""
    health_status = {
        'status': 'healthy',
        'database': check_database(),
        'redis': check_redis(),
        'disk_space': check_disk_space(),
    }
    
    # 如果有任何组件不健康,返回错误状态
    if not all(health_status.values()):
        health_status['status'] = 'unhealthy'
        return JsonResponse(health_status, status=503)
    
    return JsonResponse(health_status)

def check_database():
    """检查数据库连接"""
    db_conn = connections['default']
    try:
        c = db_conn.cursor()
        return True
    except OperationalError:
        return False

def check_redis():
    """检查Redis连接"""
    try:
        redis_client = redis.Redis(
            host=os.environ.get('REDIS_HOST', 'localhost'),
            port=os.environ.get('REDIS_PORT', 6379),
            db=0
        )
        redis_client.ping()
        return True
    except:
        return False

def check_disk_space():
    """检查磁盘空间"""
    try:
        stat = os.statvfs('/')
        free_bytes = stat.f_bavail * stat.f_frsize
        # 如果剩余空间小于1GB,认为不健康
        return free_bytes > 1024 * 1024 * 1024
    except:
        return False

配置URL:

python
# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('health/', views.health_check, name='health_check'),
    # 其他URL...
]

自动化部署脚本

创建部署脚本:

bash
#!/bin/bash
# deploy.sh

set -e  # 遇到错误时退出

echo "开始部署..."

# 拉取最新代码
git pull origin main

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

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

# 运行迁移
python manage.py migrate --noinput

# 收集静态文件
python manage.py collectstatic --noinput

# 重启服务
sudo systemctl restart myproject
sudo systemctl restart nginx

echo "部署完成!"

备份策略

创建数据库备份脚本:

bash
#!/bin/bash
# backup.sh

# 数据库备份
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/var/backups/myproject"
mkdir -p $BACKUP_DIR

# PostgreSQL备份
pg_dump myproject > $BACKUP_DIR/db_backup_$DATE.sql

# 压缩备份
gzip $BACKUP_DIR/db_backup_$DATE.sql

# 删除7天前的备份
find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +7 -delete

# 媒体文件备份(如果存储在本地)
tar -czf $BACKUP_DIR/media_backup_$DATE.tar.gz /var/www/myproject/media/

# 删除7天前的媒体文件备份
find $BACKUP_DIR -name "media_backup_*.tar.gz" -mtime +7 -delete

小结

Django部署方案的核心要点:

  1. ✅ Nginx + Gunicorn是传统部署的经典组合
  2. ✅ 云平台部署提供了更便捷的部署方式
  3. ✅ 使用CDN加速静态文件访问
  4. ✅ 实施监控和健康检查确保应用稳定
  5. ✅ 建立自动化部署和备份策略

选择合适的部署方案取决于项目需求、团队技能和预算考虑。无论选择哪种方案,都需要确保应用的安全性、稳定性和可扩展性。

通过本章的学习,您已经掌握了Django生产环境配置和部署的完整流程。在实际项目中,建议根据具体情况调整配置,并持续优化部署流程。


🎉Django 深入浅出系列课程

恭喜您完成了整个Django 深入浅出系列课程!通过本课程的学习,您已经掌握了:

核心技能掌握

  • ✅ Django MTV架构和项目结构
  • ✅ 模型设计和数据库操作
  • ✅ 视图开发和URL路由
  • ✅ 模板系统和表单处理
  • ✅ 用户认证和权限管理

高级特性应用

  • ✅ Admin后台定制
  • ✅ RESTful API开发
  • ✅ 测试驱动开发
  • ✅ 性能优化技巧
  • ✅ 生产环境部署

实战项目经验

  • ✅ 完整的博客系统开发
  • ✅ 前后端分离架构
  • ✅ 持续集成和自动化部署
  • ✅ 监控和维护策略

下一步建议

  1. 实践项目:尝试开发一个完整的个人项目
  2. 深入学习:探索Django Channels、Celery等高级特性
  3. 社区参与:加入Django社区,参与开源项目
  4. 持续学习:关注Django最新版本和最佳实践

感谢您学习本课程!祝您在Django开发之路上越走越远!

目录

返回课程目录

Released under the Apache 2.0 License.