发布于 2026-01-06 0 阅读
0

启动一个可用于生产环境的 Docker 化 Django 项目

启动一个可用于生产环境的 Docker 化 Django 项目

在 Docker 容器内构建可用于生产环境的 Django 应用对开发者来说非常有用。它最大限度地减少了设置和部署的麻烦,使开发者能够专注于真正重要的部分,例如开发和业务逻辑。

目录

  1. 先决条件
  2. 介绍
  3. 项目配置
  4. 针对不同环境的拆分设置
  5. 环境变量
  6. Postgres 配置
    1. 在启动 Django 之前,请确保 Postgres 系统运行正常。
  7. Celery 和 Redis 配置
  8. 针对生产环境调整 Docker Compose
  9. 结论

先决条件

本指南假定您已熟悉以下技术:

  • 中级 Django
  • 初级到中级 Docker
  • 熟悉 Postgres、Celery、Redis 和 Nginx

介绍

本指南旨在帮助您启动和组织 Django 项目,使其能够在不同的环境中运行,主要是开发和生产环境。您可以参考此模板,根据自身需求进行修改,最终将其部署到您选择的云服务提供商,例如 AWS、Azure 或 Digital Ocean 等。

注意:如果您在学习本教程的过程中遇到任何问题,可以查看 GitHub 仓库中的代码。

项目配置

首先,在 GitHub 上创建一个仓库。使用 PythonREADME文件和模板初始化该仓库。.gitignore

GH仓库

现在,在你的电脑上,打开终端并运行以下命令来设置并打开你的项目。

mkdir django-docker-template
cd django-docker-template
git clone <link-to-repo> .
code .
Enter fullscreen mode Exit fullscreen mode

在项目根目录中,创建一个名为的文件requirements.txt

touch requirements.txt
Enter fullscreen mode Exit fullscreen mode

并添加以下依赖项:

celery==5.2.7
Django==4.1.2
gunicorn==20.1.0
psycopg2-binary==2.9.5
python-decouple==3.6
redis==4.3.4
Enter fullscreen mode Exit fullscreen mode

然后,创建Dockerfile

touch Dockerfile
Enter fullscreen mode Exit fullscreen mode

并添加以下代码片段:

FROM python:3.10.2-slim-bullseye

ENV PIP_DISABLE_PIP_VERSION_CHECK 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

WORKDIR /code

COPY ./requirements.txt .
RUN pip install -r requirements.txt

COPY . .
Enter fullscreen mode Exit fullscreen mode

然后,创建一个docker-compose.yml文件:

touch docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

web并在其中添加一项服务:

version: "3.9"

services:
  web:
    build: .
    volumes:
      - .:/code
    ports:
      - 8000:8000
Enter fullscreen mode Exit fullscreen mode

最后,创建一个.dockerignore文件,以便 Docker 忽略某些文件,从而加快镜像的构建过程。

touch .dockerignore
Enter fullscreen mode Exit fullscreen mode

其中添加以下内容:

.venv
.git
.gitignore
Enter fullscreen mode Exit fullscreen mode

很好,运行以下命令构建镜像:

docker-compose build
Enter fullscreen mode Exit fullscreen mode

这需要一些时间。现在您可以使用此镜像创建 Django 项目。

docker-compose run --rm web django-admin startproject config .
Enter fullscreen mode Exit fullscreen mode

针对不同环境的拆分设置

务必考虑项目运行的不同环境/模式:通常包括开发环境和生产环境。当然,您也可以将类似的逻辑应用于其他可能需要包含的环境。

您可以拆分设置,以指定项目运行的环境,类似于下面所示的示例:

config
└───settings
│   │   __init__.py
│   │   base.py
│   │   development.py
│   │   production.py
Enter fullscreen mode Exit fullscreen mode

base.py这将包含与环境无关的通用设置。因此,请将settings.pyDjango 默认创建的所有内容复制到此处settings/base.py,然后删除settings.py不再需要的内容。

然后,base.py在两个环境中导入。环境特定的设置稍后会更新。

# import this in development.py, production.py
from .base import *
Enter fullscreen mode Exit fullscreen mode

环境变量

使用环境变量可以描述不同的环境。`environment`python decouple是最常用的软件包之一,它可以将设置与源代码严格分离。该软件包已在项目根目录中添加,因此只需在项目根目录中requirements.txt创建一个文件即可:.env

touch .env
Enter fullscreen mode Exit fullscreen mode

并添加以下变量:

SECRET_KEY=

ALLOWED_HOSTS=.localhost, .herokuapp.com, .0.0.0.0
DEBUG=True

DJANGO_SETTINGS_MODULE=config.settings.development
Enter fullscreen mode Exit fullscreen mode

请据此更新您的设置:

# base.py

from decouple import config, Csv

SECRET_KEY = config("SECRET_KEY")

DEBUG = config("DEBUG", default=False, cast=bool)

ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=Csv())
Enter fullscreen mode Exit fullscreen mode

DJANGO_SETTINGS_MODULE告诉 Django 要使用哪个设置。通过在环境变量中提供其值,Djangomanage.py可以自动为不同的环境使用相应的设置。因此,请manage.py按如下方式更新:

# manage.py

from decouple import config

os.environ.setdefault("DJANGO_SETTINGS_MODULE", config("DJANGO_SETTINGS_MODULE"))
Enter fullscreen mode Exit fullscreen mode

同时更新文件web中的服务docker-compose.yml,使其从文件中读取环境变量.env

version: "3.9"

services:
  web:
    build: .
    volumes:
      - .:/code
    env_file:
      - ./.env
    ports:
      - 8000:8000
Enter fullscreen mode Exit fullscreen mode

那么,有哪些可能的特定环境设置呢?以下列举一些:

1)电子邮件

您可以在开发模式下使用控制台后端将电子邮件写入标准输出。

# development.py

from .base import *

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
Enter fullscreen mode Exit fullscreen mode

在生产模式下,使用类似 SendGrid、Mailgun 等的 SMTP 后端服务。

# production.py

from .base import *

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "'smtp.mailgun.org'"
EMAIL_PORT = 587
EMAIL_HOST_USER = config("EMAIL_USER")
EMAIL_HOST_PASSWORD = config("EMAIL_PASSWORD")
EMAIL_USE_TLS = True
Enter fullscreen mode Exit fullscreen mode

2)媒体和静态文件

在生产环境中,您可能需要使用 AWS S3 等服务来提供静态文件和媒体文件。在这种情况下,拥有多种设置就显得非常有用。

# development.py

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "../", "mediafiles")

STATIC_URL = "static/"
STATIC_ROOT = os.path.join(BASE_DIR, "../", "staticfiles")
Enter fullscreen mode Exit fullscreen mode

然后,您可以添加与 AWS 相关的配置。production.py

3)缓存

理想情况下,开发过程中不需要缓存网站,因此可以在production.py文件中单独添加缓存服务器,例如 Redis。

# production.py

# Redis Cache
CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": config("REDIS_BACKEND"),
    },
}
Enter fullscreen mode Exit fullscreen mode

此外,您还可以为您的环境单独添加应用程序、中间件等。

Postgres 配置

要配置Postgres,首先需要向 docker-compose.yml 文件中添加一个新服务:

version: "3.9"

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    env_file:
      - ./.env
    ports:
      - 8000:8000
    depends_on:
      - db
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=${DB_USERNAME}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}

volumes:
  postgres_data:
Enter fullscreen mode Exit fullscreen mode

接下来,更新.env文件以包含与数据库相关的变量:

# Database
DB_NAME=
DB_USERNAME=
DB_PASSWORD=
DB_HOSTNAME=db
DB_PORT=5432
Enter fullscreen mode Exit fullscreen mode

最后,更新设置,使用 Postgres RDBMS 而不是 Django 默认使用的 SQLite 引擎。

# base.py

# Remove the sqlite engine and add this
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": config("DB_NAME"),
        "USER": config("DB_USERNAME"),
        "PASSWORD": config("DB_PASSWORD"),
        "HOST": config("DB_HOSTNAME"),
        "PORT": config("DB_PORT", cast=int),
    }
}
Enter fullscreen mode Exit fullscreen mode

注意:您可能需要为开发环境和生产环境使用不同的数据库。如果是这种情况,您可以移除该DATABASES设置base.py,并为开发环境和生产环境添加不同的数据库。

太好了!现在,重新构建容器,以确保目前为止的所有功能都能正常运行。

docker-compose build
Enter fullscreen mode Exit fullscreen mode

此外,请确保已应用迁移:

docker-compose run --rm web python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

在启动 Django 之前,请确保 Postgres 系统运行正常。

通常情况下,在 Docker 中使用 Postgres 和 Django 时,webDjango 服务会尝试连接db尚未db准备好接受连接的服务器。为了解决这个问题,您可以创建一个简短的 bash 脚本,并在 Docker 的ENTRYPOINT命令中使用它。

在项目根目录中创建一个名为的文件entrypoint.sh

touch entrypoint.sh
Enter fullscreen mode Exit fullscreen mode

添加以下脚本以监听 Postgres 数据库端口,直到它准备好接受连接,然后应用迁移并收集静态文件。

#!/bin/sh

echo 'Waiting for postgres...'

while ! nc -z $DB_HOSTNAME $DB_PORT; do
    sleep 0.1
done

echo 'PostgreSQL started'

echo 'Running migrations...'
python manage.py migrate

echo 'Collecting static files...'
python manage.py collectstatic --no-input

exec "$@"
Enter fullscreen mode Exit fullscreen mode

更新本地文件权限

chmod +x entrypoint.sh
Enter fullscreen mode Exit fullscreen mode

要使用此脚本,您需要Netcat在镜像中安装相应的工具。因此,请更新镜像Dockerfile以安装此网络实用程序,并将此 bash 脚本用作 Docker 入口点命令。

FROM python:3.10.2-slim-bullseye

ENV PIP_DISABLE_PIP_VERSION_CHECK 1
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

WORKDIR /code

COPY ./requirements.txt .

RUN apt-get update -y && \
    apt-get install -y netcat && \
    pip install --upgrade pip && \
    pip install -r requirements.txt

COPY ./entrypoint.sh .
RUN chmod +x /code/entrypoint.sh

COPY . .

ENTRYPOINT ["/code/entrypoint.sh"]
Enter fullscreen mode Exit fullscreen mode

重建镜像并启动容器。

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

访问http://localhost:8000/

Celery 和 Redis 配置

Celery 会在后台异步执行耗时任务,从而使您的 Web 应用能够持续快速响应用户请求。由于 Redis 可以同时作为消息代理和数据库后端,因此建议将其与 Celery 结合使用。

添加 Redis 和 Celery 服务docker-compose.yml

redis:
    image: redis:7

celery:
  build: .
  command: celery -A config worker -l info
  volumes:
    - .:/code
  env_file:
    - ./.env
  depends_on:
    - db
    - redis
    - web
Enter fullscreen mode Exit fullscreen mode

顺便也更新一下web服务吧:

depends_on:
    - redis
    - db
Enter fullscreen mode Exit fullscreen mode

设置完成后,导航到 config 文件夹并创建一个名为 的文件celery.py

cd config
touch celery.py
Enter fullscreen mode Exit fullscreen mode

然后,在其中添加以下代码片段:

# config/celery.py

import os

from decouple import config
from celery import Celery

os.environ.setdefault("DJANGO_SETTINGS_MODULE", config("DJANGO_SETTINGS_MODULE"))
app = Celery("config")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
Enter fullscreen mode Exit fullscreen mode

接下来,前往base.py并于底部添加以下配置:

# settings/base.py

# Celery
CELERY_BROKER_URL = config("CELERY_BROKER_URL")
CELERY_RESULT_BACKEND = config("REDIS_BACKEND")
Enter fullscreen mode Exit fullscreen mode

更新.env内容,添加上述环境变量:

# Celery
CELERY_BROKER_URL=redis://redis:6379/0

# Redis
REDIS_BACKEND=redis://redis:6379/0
Enter fullscreen mode Exit fullscreen mode

最终更新内容写入__init__.pyconfig 文件夹下的文件中:

# config/__init__.py

from .celery import app as celery_app

__all__ = ('celery_app',)
Enter fullscreen mode Exit fullscreen mode

再测试一次:

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

针对生产环境调整 Docker Compose

Django 的内置服务器不适合生产环境,因此在生产环境中应该使用像 Gunicorn 这样的生产级 WSGI 服务器。

此外,您还应该考虑添加 Nginx 作为 Gunicorn 的反向代理,并提供静态文件服务。

docker-compose.prod.yml因此,请在项目根目录创建一个名为 `.conf` 的文件,并添加/更新以下服务:

version: "3.9"

services:
  web:
    build: .
    restart: always
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    env_file:
      - ./.env
    expose:
      - 8000
    volumes:
      - static_volume:/code/staticfiles
      - media_volume:/code/mediafiles
    depends_on:
      - redis
      - db
  db:
    image: postgres:13
    restart: always
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=${DB_USERNAME}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}

  redis:
    image: redis:7

  celery:
    build: .
    restart: always
    command: celery -A config worker -l info
    volumes:
      - .:/code
    env_file:
      - ./.env
    depends_on:
      - db
      - redis
      - web

  nginx:
    build: ./nginx
    restart: always
    ports:
      - ${NGINX_PORT}:80
    volumes:
      - static_volume:/code/staticfiles
      - media_volume:/code/mediafiles
    depends_on:
      - web

volumes:
  postgres_data:
  static_volume:
  media_volume:
Enter fullscreen mode Exit fullscreen mode

上述文件中有几点值得注意:

  • 使用 `<service>`expose而不是 `<service>` ports。这使得该web服务可以暴露给 Docker 内部的其他服务,但不会暴露给宿主机。
  • 静态卷和媒体卷,用于持久化由服务生成和使用的web数据nginx

别忘了更新配置.env,添加NGINX_PORT环境变量:

# NGINX
NGINX_PORT=80
Enter fullscreen mode Exit fullscreen mode

然后,在项目根目录中,创建以下文件夹和文件:

mkdir nginx
cd nginx
touch Dockerfile
touch nginx.conf
Enter fullscreen mode Exit fullscreen mode

更新相关文件:

# nginx/Dockerfile

FROM nginx:stable-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d

EXPOSE 80
Enter fullscreen mode Exit fullscreen mode
  • 上述文件会拉取基础 Nginx 镜像,移除默认配置,并复制您创建的配置,即nginx.conf包含以下内容:
# nginx/nginx.conf

upstream web_app {
    server web:8000;
}

server {

    listen 80;

    location /static/ {
        alias /code/staticfiles/;
    }

    location /media/ {
        alias /code/mediafiles/;
    }

    location / {
        proxy_pass http://web_app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

}
Enter fullscreen mode Exit fullscreen mode
  • 值得注意的是,上述配置中,静态文件请求和媒体文件请求分别路由到静态文件文件夹和媒体文件文件夹。

在本地测试您的生产环境:

docker-compose -f docker-compose.prod.yml up --build
Enter fullscreen mode Exit fullscreen mode

访问http://localhost/,静态文件也应该能够正确加载。

结论

本教程引导您完成了 Django 应用的容器化,使其既可用于本地开发,也可用于生产环境。除了容器化部署的便捷性之外,在本地使用 Docker 进行开发还能节省时间,因为它最大限度地减少了您需要在机器上进行的配置工作。

如果你在阅读本指南的过程中遇到任何问题,可以查看GitHub上的项目。 

祝您编程愉快!🖤

文章来源:https://dev.to/documatic/start-a-production-ready-dockerized-django-project-5eop