Django 项目部署指南

Django 部署概述

将 Django 项目从开发环境部署到生产环境是一个关键步骤。本指南将详细介绍如何配置服务器、优化性能、确保安全,并维护生产环境的稳定性。

典型部署架构

客户端
Web 浏览器、移动应用
Web 服务器
Nginx 反向代理和静态文件服务
应用服务器
Gunicorn WSGI 服务器
数据库和缓存
PostgreSQL Redis
部署选项
  • 传统 VPS - 完全控制,需要手动配置
  • PaaS 平台 - Heroku, PythonAnywhere 等
  • 容器化 - Docker, Kubernetes
  • 云服务 - AWS, Google Cloud, Azure
  • 专用服务器 - 高性能需求
部署组件
组件 作用 常用选择
Web 服务器 处理静态文件,反向代理 Nginx, Apache
WSGI 服务器 运行 Python 应用 Gunicorn, uWSGI
数据库 数据存储 PostgreSQL, MySQL
缓存 性能优化 Redis, Memcached
任务队列 异步任务处理 Celery + Redis

部署前准备

在部署之前,需要确保项目已准备好生产环境。

部署检查清单
环境配置分离

开发、测试、生产环境配置分离

安全设置

DEBUG=False, 正确的 ALLOWED_HOSTS

⚠️
静态文件配置

STATIC_ROOT 和 collectstatic 配置

⚠️
数据库迁移

确保所有迁移文件已应用

⚠️
依赖管理

requirements.txt 或 Pipfile 更新

⚠️
环境变量

敏感信息使用环境变量

生产环境配置
# settings/production.py

from
.base
import
*

# 安全设置
DEBUG
=
False

ALLOWED_HOSTS
= [
'yourdomain.com'
,
'www.yourdomain.com'
]

# 数据库配置
DATABASES
= {
    
'default'
: {
        
'ENGINE'
:
'django.db.backends.postgresql'
,
        
'NAME'
:
os
.environ.get(
'DB_NAME'
),
        
'USER'
:
os
.environ.get(
'DB_USER'
),
        
'PASSWORD'
:
os
.environ.get(
'DB_PASSWORD'
),
        
'HOST'
:
os
.environ.get(
'DB_HOST'
),
        
'PORT'
:
'5432'
,
    }
}

# 静态文件配置
STATIC_ROOT
=
os
.path.join(
BASE_DIR
,
'staticfiles'
)
STATIC_URL
=
'/static/'


# 媒体文件配置
MEDIA_ROOT
=
os
.path.join(
BASE_DIR
,
'media'
)
MEDIA_URL
=
'/media/'
环境变量管理
# .env 文件 (不提交到版本控制)

# Django 设置
SECRET_KEY
=
your-production-secret-key

DEBUG
=
False

ALLOWED_HOSTS
=
yourdomain.com,www.yourdomain.com


# 数据库设置
DB_NAME
=
mydatabase

DB_USER
=
myuser

DB_PASSWORD
=
mypassword

DB_HOST
=
localhost


# 邮件设置
EMAIL_HOST
=
smtp.gmail.com

EMAIL_PORT
=
587

EMAIL_HOST_USER
=
your-email@gmail.com

EMAIL_HOST_PASSWORD
=
your-app-password


# 第三方 API 密钥
AWS_ACCESS_KEY_ID
=
your-aws-key

AWS_SECRET_ACCESS_KEY
=
your-aws-secret
提示: 使用 python-decoupledjango-environ 库来管理环境变量。

服务器配置

配置 Linux 服务器来运行 Django 应用程序。

1 服务器初始化

# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装必要的软件
sudo apt install -y python3-pip python3-venv nginx postgresql postgresql-contrib redis-server

# 创建系统用户
sudo adduser --system --group --home /opt/myapp myapp
# 配置防火墙
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable

# 配置 PostgreSQL
sudo -u postgres psql
CREATE DATABASE mydatabase;
CREATE USER myuser WITH PASSWORD 'mypassword';
GRANT ALL PRIVILEGES ON DATABASE mydatabase TO myuser;
\q

2 部署应用程序

# 切换到应用用户
sudo su - myapp

# 克隆代码
git clone https://github.com/yourusername/yourproject.git /opt/myapp

# 创建虚拟环境
cd /opt/myapp
python3 -m venv venv
source venv/bin/activate

# 安装依赖
pip install -r requirements.txt
# 应用数据库迁移
python manage.py migrate

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

# 创建超级用户
python manage.py createsuperuser

# 测试应用
python manage.py runserver 0.0.0.0:8000
注意: 不要在生产环境中使用 runserver,这里仅用于测试。

Gunicorn 配置

Gunicorn 是一个 Python WSGI HTTP 服务器,用于在生产环境中运行 Django 应用。

安装和配置 Gunicorn
# 安装 Gunicorn
pip install gunicorn
# gunicorn.conf.py

# 绑定地址和端口
bind
=
"127.0.0.1:8000"


# 工作进程数
workers
=
3


# 工作进程类型
worker_class
=
"sync"


# 最大并发请求数
worker_connections
=
1000


# 超时设置
timeout
=
30

keepalive
=
2


# 日志配置
accesslog
=
"-"

errorlog
=
"-"

loglevel
=
"info"


# 进程名称
proc_name
=
"myapp_gunicorn"
Systemd 服务配置
# /etc/systemd/system/myapp.service

[Unit]

Description
=
gunicorn daemon for myapp

After
=
network.target


[Service]

User
=
myapp

Group
=
myapp

WorkingDirectory
=
/opt/myapp

Environment
=
"PATH=/opt/myapp/venv/bin"

ExecStart
=
/opt/myapp/venv/bin/gunicorn --config gunicorn.conf.py myproject.wsgi:application


[Install]

WantedBy
=
multi-user.target
# 启动 Gunicorn 服务
sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl enable myapp

# 检查服务状态
sudo systemctl status myapp
● myapp.service - gunicorn daemon for myapp
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2023-01-01 10:00:00 UTC; 1min ago

Nginx 配置

Nginx 作为反向代理服务器,处理静态文件并将动态请求转发给 Gunicorn。

Nginx 站点配置
# /etc/nginx/sites-available/myapp

server
{
    
listen
80
;
    
server_name
yourdomain.com www.yourdomain.com;

    
# 静态文件配置

    
location
/static/
{
        
alias
/opt/myapp/staticfiles/
;
        
expires
30d
;
        
add_header
Cache-Control
"public, immutable"
;
    }

    
# 媒体文件配置

    
location
/media/
{
        
alias
/opt/myapp/media/
;
        
expires
30d
;
    }

    
# Django 应用代理

    
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
;
    }
}
启用站点和 SSL
# 启用站点
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# 测试 Nginx 配置
sudo nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful

# 重启 Nginx
sudo systemctl restart nginx

# 安装 Certbot 获取 SSL 证书
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
SSL 配置示例
# SSL 配置自动由 Certbot 添加
server
{
    
listen
443
ssl http2;
    
ssl_certificate
/etc/letsencrypt/live/yourdomain.com/fullchain.pem
;
    
ssl_certificate_key
/etc/letsencrypt/live/yourdomain.com/privkey.pem
;
    
# ... 其他配置

}

server
{
    
listen
80
;
    
server_name
yourdomain.com www.yourdomain.com;
    
return
301
https://
$server_name$request_uri
;
}

数据库和缓存优化

优化数据库和缓存配置以提高应用性能。

PostgreSQL 优化
# /etc/postgresql/13/main/postgresql.conf

# 内存设置
shared_buffers
=
256MB

work_mem
=
4MB

maintenance_work_mem
=
64MB


# 检查点设置
checkpoint_completion_target
=
0.7

wal_buffers
=
-1


# 日志设置
logging_collector
=
on

log_directory
=
'pg_log'

log_filename
=
'postgresql-%Y-%m-%d_%H%M%S.log'
# 重启 PostgreSQL
sudo systemctl restart postgresql
Redis 缓存配置
# settings/production.py

# 缓存配置
CACHES
= {
    
'default'
: {
        
'BACKEND'
:
'django_redis.cache.RedisCache'
,
        
'LOCATION'
:
'redis://127.0.0.1:6379/1'
,
        
'OPTIONS'
: {
            
'CLIENT_CLASS'
:
'django_redis.client.DefaultClient'
,
        },
    }
}

# 会话引擎
SESSION_ENGINE
=
"django.contrib.sessions.backends.cache"

SESSION_CACHE_ALIAS
=
"default"
# /etc/redis/redis.conf

maxmemory
256mb

maxmemory-policy
allkeys-lru
save
900
1

save
300
10

save
60
10000

性能优化设置

# settings/production.py

# 数据库连接池
DATABASES
[
'default'
][
'CONN_MAX_AGE'
] =
600


# 静态文件存储优化
STATICFILES_STORAGE
=
'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'


# 模板缓存
TEMPLATES
= [{
    
'BACKEND'
:
'django.template.backends.django.DjangoTemplates'
,
    
'DIRS'
: [
BASE_DIR
/
'templates'
],
    
'APP_DIRS'
:
True
,
    
'OPTIONS'
: {
        
'context_processors'
: [
            
# ... 上下文处理器

        ],
        
'loaders'
: [
            (
'django.template.loaders.cached.Loader'
, [
                
'django.template.loaders.filesystem.Loader'
,
                
'django.template.loaders.app_directories.Loader'
,
            ]),
        ],
    },
}]
性能优化建议
  • 使用数据库连接池减少连接开销
  • 启用模板缓存提高渲染速度
  • 使用 CDN 加速静态文件
  • 优化数据库查询和索引
  • 启用 Gzip 压缩
  • 使用缓存中间件
# 中间件缓存示例
MIDDLEWARE = [
    # ...
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
    # ...
]

监控和维护

监控应用性能和设置自动化维护任务。

日志配置
# settings/production.py

LOGGING
= {
    
'version'
:
1
,
    
'disable_existing_loggers'
:
False
,
    
'formatters'
: {
        
'verbose'
: {
            
'format'
:
'{levelname} {asctime} {module} {process:d} {thread:d} {message}'
,
            
'style'
:
'{'
,
        },
    },
    
'handlers'
: {
        
'file'
: {
            
'level'
:
'INFO'
,
            
'class'
:
'logging.handlers.RotatingFileHandler'
,
            
'filename'
:
'/var/log/myapp/django.log'
,
            
'maxBytes'
:
1024
*
1024
*
5
,
# 5 MB

            
'backupCount'
:
5
,
            
'formatter'
:
'verbose'
,
        },
    },
    
'loggers'
: {
        
'django'
: {
            
'handlers'
: [
'file'
],
            
'level'
:
'INFO'
,
            
'propagate'
:
True
,
        },
    },
}
系统监控
# 安装和配置监控工具
sudo apt install htop iotop nethogs

# 监控系统资源
htop
iotop
nethogs

# 查看服务状态
sudo systemctl status nginx
sudo systemctl status myapp
sudo systemctl status postgresql
sudo systemctl status redis
定期维护任务
# /etc/crontab

# 每天备份数据库
0
2
* * * myapp /opt/myapp/venv/bin/python /opt/myapp/manage.py dbbackup

# 每周清理会话
0
3
* *
0
myapp /opt/myapp/venv/bin/python /opt/myapp/manage.py clearsessions

# 每月更新 SSL 证书
0
4
1
* * root certbot renew --quiet

故障排除

常见部署问题和解决方案。

常见问题诊断
# 检查服务状态
sudo systemctl status myapp
sudo systemctl status nginx

# 查看应用日志
sudo journalctl -u myapp -f
tail -f /var/log/myapp/django.log

# 查看 Nginx 日志
tail -f /var/log/nginx/error.log
tail -f /var/log/nginx/access.log

# 测试数据库连接
python manage.py dbshell
常见错误和解决
502 Bad Gateway

Gunicorn 没有运行或配置错误。检查 Gunicorn 服务状态和日志。

静态文件 404

Nginx 静态文件配置错误或没有运行 collectstatic。检查 Nginx 配置和静态文件目录。

数据库连接错误

数据库服务没有运行或连接参数错误。检查数据库服务和连接设置。

权限错误

应用用户没有文件或目录权限。检查文件和目录权限设置。

# 权限修复命令
sudo chown -R myapp:myapp /opt/myapp
sudo chmod -R 755 /opt/myapp
sudo chmod 644 /opt/myapp/*.py

自动化部署

使用自动化工具简化部署流程。

Fabric 部署脚本
# fabfile.py

from
fabric
import
Connection, task

def
deploy
(c):
    
"""部署应用到生产服务器"""

    c.run(
'cd /opt/myapp && git pull'
)
    c.run(
'cd /opt/myapp && source venv/bin/activate && pip install -r requirements.txt'
)
    c.run(
'cd /opt/myapp && source venv/bin/activate && python manage.py migrate'
)
    c.run(
'cd /opt/myapp && source venv/bin/activate && python manage.py collectstatic --noinput'
)
    c.run(
'sudo systemctl restart myapp'
)
    c.run(
'sudo systemctl reload nginx'
)

@task
def
deploy_prod
(c):
    c = Connection(
'user@yourdomain.com'
)
    deploy(c)
# 运行部署
fab deploy-prod
Docker 部署
# Dockerfile

FROM
python:3.9-slim

ENV
PYTHONUNBUFFERED=1
WORKDIR
/app

COPY
requirements.txt .
RUN
pip install --no-cache-dir -r requirements.txt

COPY
. .

RUN
python manage.py collectstatic --noinput

EXPOSE
8000

CMD
[
"gunicorn"
,
"--bind"
,
"0.0.0.0:8000"
,
"myproject.wsgi:application"
]
# docker-compose.yml

version
:
'3.8'


services
:
  
web
:
    
build
: .
    
ports
:
      -
"8000:8000"

    
environment
:
      -
DATABASE_URL=postgres://user:pass@db:5432/mydb

    
depends_on
:
      - db
  
db
:
    
image
: postgres:13
    
environment
:
      -
POSTGRES_DB=mydb

      -
POSTGRES_USER=user

      -
POSTGRES_PASSWORD=pass