Djangodeployment

LearningDjango deployment相关 in 容, includingdeployment before 准备工作, deployment选项, 静态fileprocessing, security性configurationetc.

deploymentoverview

deploymentDjangoapplication is 将Developmentenvironmentincreation application转移 to produceenvironment, 使其able to被user访问 过程. deployment过程涉及 many 个方面, includingserverconfiguration, Webserver设置, datalibraryconfiguration, 静态fileprocessing, security性configurationetc..

Djangoapplication deploymentarchitecture通常including以 under component:

  • Webserver: such asNginx, Apache, 负责processing静态file and 反向proxyrequest.
  • applicationserver: such asGunicorn, uWSGI, 负责runDjangoapplication.
  • datalibraryserver: such asPostgreSQL, MySQL, storeapplicationdata.
  • cacheserver: such asRedis, Memcached, improvingapplicationperformance.
  • monitortool: such asPrometheus, Grafana, monitorapplicationrunstatus.

提示

Developmentenvironment and produceenvironment应该保持一致, includingPythonversion, 依赖libraryversion, datalibraryclass型etc.. 可以using虚拟environment and Docker来implementationenvironment consistency.

deployment before 准备工作

in deploymentDjangoapplication之 before , 需要completion以 under 准备工作:

1. 设置DEBUG for False

in produceenvironmentin, 必须将DEBUG设置 for False, 否则会暴露敏感information:

# settings.py
DEBUG = False

# 允许 主机list, using通配符*表示允许所 has 主机访问, 但不推荐 in produceenvironmentinusing
ALLOWED_HOSTS = ['example.com', 'www.example.com', '192.168.1.100']

2. configuration静态file

configuration静态file 收集Table of Contents:

# settings.py
# 静态fileURL
STATIC_URL = '/static/'
# 静态file收集Table of Contents, 用于produceenvironment
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

# 媒体fileURL
MEDIA_URL = '/media/'
# 媒体filestoreTable of Contents
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

3. configurationdatalibrary

in produceenvironmentin, 推荐usingPostgreSQL or MySQLetc.relationships型datalibrary, 而不 is SQLite:

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': 'localhost',
        'PORT': '5432',
    }
}

4. installation依赖library

usingpip freezecommands生成依赖librarylist, 然 after in produceenvironmentininstallation:

# 生成依赖librarylist
pip freeze > requirements.txt

#  in produceenvironmentininstallation依赖library
pip install -r requirements.txt

5. 收集静态file

usingcollectstaticcommands收集静态file to STATIC_ROOTTable of Contents:

python manage.py collectstatic

6. 执行datalibrarymigration

in produceenvironmentin执行datalibrarymigration:

python manage.py migrate

7. creation超级user

creation用于loginmanagement界面 超级user:

python manage.py createsuperuser

deployment选项

has many 种方式可以deploymentDjangoapplication, 以 under is 一些常用 deployment选项:

1. Nginx + Gunicorn

Nginx is a high performance Webserver, 负责processing静态file and 反向proxyrequest; Gunicorn is a Python WSGI HTTPserver, 负责runDjangoapplication.

installationGunicorn

pip install gunicorn

usingGunicornrunDjangoapplication

gunicorn mysite.wsgi:application --bind 0.0.0.0:8000

configurationNginx

creationNginxconfigurationfile:

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com www.example.com;
    
    # 静态fileconfiguration
    location /static/ {
        alias /path/to/your/project/staticfiles/;
    }
    
    # 媒体fileconfiguration
    location /media/ {
        alias /path/to/your/project/media/;
    }
    
    # 反向proxyconfiguration
    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;
    }
}

启用Nginxconfiguration:

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t  # testconfigurationfile
nginx -s reload  # 重 new 加载Nginxconfiguration

2. Nginx + uWSGI

uWSGI is 另一个常用 Python WSGI HTTPserver, and Nginx配合using效果良 good .

installationuWSGI

pip install uwsgi

configurationuWSGI

creationuWSGIconfigurationfile:

# uwsgi.ini
[uwsgi]
# projectTable of Contents
chdir = /path/to/your/project
# WSGImodulepath
module = mysite.wsgi:application
# Python虚拟environmentpath
home = /path/to/your/virtualenv
# process数
processes = 4
# thread数
threads = 2
# uWSGI监听 端口
socket = 127.0.0.1:8000
# 启用主process
master = true
# processIDfile
pidfile = /tmp/project-master.pid
# logfile
daemonize = /var/log/uwsgi/project.log
# 静态filemap
static-map = /static=/path/to/your/project/staticfiles

启动uWSGI

uwsgi --ini uwsgi.ini

configurationNginx

Nginxconfiguration and Gunicornclass似, 只需将proxy_pass改 for uwsgi_pass:

# /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com www.example.com;
    
    # 静态fileconfiguration
    location /static/ {
        alias /path/to/your/project/staticfiles/;
    }
    
    # 媒体fileconfiguration
    location /media/ {
        alias /path/to/your/project/media/;
    }
    
    # uWSGIconfiguration
    location / {
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
}

3. Dockerdeployment

usingDocker可以implementationapplication containerizationdeployment, improvingdeployment consistency and portability.

creationDockerfile

# Dockerfile
FROM python:3.10

# 设置工作Table of Contents
WORKDIR /app

# copyrequirements.txtfile
COPY requirements.txt .

# installation依赖library
RUN pip install --no-cache-dir -r requirements.txt

# copyprojectfile
COPY . .

# 收集静态file
RUN python manage.py collectstatic --noinput

# 执行datalibrarymigration
RUN python manage.py migrate

# 暴露端口
EXPOSE 8000

# 启动application
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000"]

creationdocker-compose.ymlfile

# docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DEBUG=False
      - SECRET_KEY=your-secret-key
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/mydatabase
    depends_on:
      - db
    volumes:
      - ./staticfiles:/app/staticfiles
      - ./media:/app/media
  
  db:
    image: postgres:14
    environment:
      - POSTGRES_DB=mydatabase
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data/

volumes:
  postgres_data:

构建 and runDockercontainers

# 构建Docker镜像
docker-compose build

# runDockercontainers
docker-compose up -d

4. 云平台deployment

可以using各种云平台来deploymentDjangoapplication, such as:

  • Heroku: providing了 simple deployment流程, supportautomationdeployment.
  • AWS: providing了 many 种deployment选项, such asElastic Beanstalk, EC2+RDSetc..
  • Google Cloud Platform: providing了App Engine, Compute Engineetc.deployment选项.
  • Microsoft Azure: providing了App Serviceetc.deployment选项.

静态fileprocessing

in produceenvironmentin, Django不会自动processing静态file, 需要usingWebserver来processing.

1. 收集静态file

usingcollectstaticcommands将所 has application 静态file收集 to 一个Table of Contents:

python manage.py collectstatic

2. configurationWebserver

configurationWebserver (such asNginx, Apache) 来processing静态filerequest:

Nginxconfiguration

location /static/ {
    alias /path/to/your/project/staticfiles/;
    expires 30d;  # 设置静态filecache时间
    access_log off;  # 关闭静态file访问log
}

Apacheconfiguration

Alias /static/ /path/to/your/project/staticfiles/
<Directory /path/to/your/project/staticfiles/>
    Require all granted
    Options -Indexes
</Directory>

3. usingCDN

for 于 big 型application, 可以usingCDN ( in 容分发network) 来加速静态file 访问:

# settings.py
# usingCDN 静态fileURL
STATIC_URL = 'https://cdn.example.com/static/'
# 本地静态file收集Table of Contents
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

datalibraryconfiguration

in produceenvironmentin, 推荐usingPostgreSQL or MySQLetc.relationships型datalibrary, 而不 is SQLite.

PostgreSQLconfiguration

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME', 'mydatabase'),
        'USER': os.environ.get('DB_USER', 'mydatabaseuser'),
        'PASSWORD': os.environ.get('DB_PASSWORD', 'mypassword'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
        'OPTIONS': {
            'sslmode': 'require',  # 启用SSL连接
        },
    }
}

MySQLconfiguration

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.environ.get('DB_NAME', 'mydatabase'),
        'USER': os.environ.get('DB_USER', 'mydatabaseuser'),
        'PASSWORD': os.environ.get('DB_PASSWORD', 'mypassword'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '3306'),
        'OPTIONS': {
            'charset': 'utf8mb4',  # supportemoji
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

datalibraryoptimization

  • using连接池: such aspgBouncer (PostgreSQL) , ProxySQL (MySQL) , improvingdatalibrary连接efficiency.
  • creationindex: for 频繁query 字段creationindex, improvingquery速度.
  • 定期backup: 设置定期backup策略, 防止dataloss.
  • monitordatalibrary: usingmonitortoolmonitordatalibraryperformance and status.

environmentvariableconfiguration

in produceenvironmentin, 应该usingenvironmentvariable来store敏感information, such asdatalibrarypassword, SECRET_KEYetc., 而不 is 硬编码 in configurationfilein.

usingpython-decouple

python-decouple is a 用于managementenvironmentvariable library, 可以将configuration and code分离:

installationpython-decouple

pip install python-decouple

creation.envfile

# .env
DEBUG=False
SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=example.com,www.example.com

DB_NAME=mydatabase
DB_USER=mydatabaseuser
DB_PASSWORD=mypassword
DB_HOST=localhost
DB_PORT=5432

in settings.pyinusingenvironmentvariable

# settings.py
from decouple import config

DEBUG = config('DEBUG', default=False, cast=bool)
SECRET_KEY = config('SECRET_KEY')
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=lambda v: [s.strip() for s in v.split(',')])

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': config('DB_NAME'),
        'USER': config('DB_USER'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST'),
        'PORT': config('DB_PORT'),
    }
}

warning

不要将.envfilesubmitting to version控制systemin, 应该将其添加 to .gitignorefilein.

security性configuration

produceenvironmentin security性configuration非常 important , 可以防止各种攻击, such asSQL注入, 跨站脚本攻击, 跨站request伪造etc..

1. 设置强SECRET_KEY

SECRET_KEY用于encryptionsessiondata, passwordresettokenetc., 必须设置 for 强随机string:

# 生成强SECRET_KEY
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"

# settings.py
SECRET_KEY = config('SECRET_KEY')

2. 启用HTTPS

in produceenvironmentin, 必须启用HTTPS, 防止data in 传输过程in被窃取:

  • usingLet's Encrypt免费SSLcertificate.
  • configurationWebserver强制HTTPS重定向.
  • 设置SECURE_SSL_REDIRECT = True.

3. configurationsecurity头

设置各种security头, improvingapplication security性:

# settings.py
# 强制HTTPS重定向
SECURE_SSL_REDIRECT = True

# HSTSconfiguration, 告诉浏览器始终usingHTTPS访问
SECURE_HSTS_SECONDS = 31536000  # 1年
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

# 防止点击劫持攻击
X_FRAME_OPTIONS = 'DENY'

# 防止XSS攻击
SECURE_BROWSER_XSS_FILTER = True

# 防止MIMEclass型嗅探
SECURE_CONTENT_TYPE_NOSNIFF = True

4. configurationCSRF保护

确保CSRF保护已启用:

# settings.py
MIDDLEWARE = [
    # otherin间件...
    'django.middleware.csrf.CsrfViewMiddleware',
    # otherin间件...
]

5. 限制management员访问

限制management界面 访问, 只允许specificIP访问:

Nginxconfiguration

location /admin/ {
    allow 192.168.1.100;
    deny all;
    
    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;
}

logprocessing

in produceenvironmentin, 必须configurationlogprocessing, 以便及时发现 and 解决issues:

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': {
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'file': {
            'level': 'INFO',
            'class': 'logging.Fileprocessingr',
            'filename': '/var/log/django/debug.log',
            'formatter': 'verbose',
        },
        'console': {
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.Streamprocessingr',
            'formatter': 'simple',
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailprocessingr',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file', 'console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'blog': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
}

monitor and maintenance

deployment after , 需要定期monitor and maintenanceapplication, 确保其正常run:

1. monitortool

  • Prometheus + Grafana: monitorapplication CPU, memory, diskusingcircumstances, 以及requestresponse时间etc..
  • New Relic: providingapplicationperformancemonitor, error跟踪etc.functions.
  • Sentry: 实时error跟踪 and monitor.
  • ELK Stack: 收集, store and analysislog.

2. 定期maintenance

  • update依赖library: 定期update依赖library, 修复security漏洞.
  • backupdatalibrary: 定期backupdatalibrary, 防止dataloss.
  • cleanlog: 定期cleanlogfile, 防止disk空间不足.
  • optimizationdatalibrary: 定期optimizationdatalibrary, such as重建index, clean无用dataetc..

3. automationdeployment

usingautomationdeploymenttool, such asJenkins, GitLab CI/CD, GitHub Actionsetc., 可以简化deployment流程, improvingdeploymentefficiency:

GitHub Actionsexample

# .github/workflows/deploy.yml
name: deployment Django App

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.10'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      run: python manage.py test
    
    - name: Collect static files
      run: python manage.py collectstatic --noinput
    
    - name: deployment to server
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USERNAME }}
        password: ${{ secrets.SERVER_PASSWORD }}
        script: |
          cd /path/to/project
          git pull origin main
          pip install -r requirements.txt
          python manage.py migrate
          python manage.py collectstatic --noinput
          systemctl restart gunicorn
          systemctl restart nginx

练习 1: 准备deploymentenvironment

  1. creation一个 new Djangoproject.
  2. 设置DEBUG for False, configurationALLOWED_HOSTS.
  3. configuration静态file收集Table of Contents.
  4. 生成requirements.txtfile.
  5. creation.envfile, store敏感information.
  6. usingpython-decouple in settings.pyin加载environmentvariable.

练习 2: usingNginx+GunicorndeploymentDjangoapplication

  1. installationGunicorn and Nginx.
  2. usingGunicornrunDjangoapplication.
  3. configurationNginx反向proxy and 静态fileprocessing.
  4. testapplication is 否可以正常访问.

练习 3: usingDockerdeploymentDjangoapplication

  1. creationDockerfile.
  2. creationdocker-compose.ymlfile, package含Djangoapplication and PostgreSQLdatalibrary.
  3. 构建并runDockercontainers.
  4. testapplication is 否可以正常访问.