使用Docker+Django+Nginx+PostgreSQL+Gunicorn进行环境配置,支持M1Mac

前提

    • フレームワークはDjango

 

    • DBはPostgreSQL

 

    • アプリケーションサーバはGunicorn

 

    • WebサーバはNginx

 

    • Dockerとdocker-composeをインストール済み

 

    • Dockerについてある程度の知識がある方が望ましい

 

    • DB側のコンテナ名はpostgres、Django側のコンテナ名はapp、Nginx側はwebにします

 

    • 開発用はdocker-compose.yml(Django+PostgreSQL)として作成します

 

    • 本番用はdocker-compose.prod.yml(Django+PostgreSQL+Nginx)として作成します

 

    作成するプロジェクト名はdjangopjにしていますが別のプロジェクト名で作成する際はdjangopjと置き換えて作成してください

概要 – 摘要

題名如標所示,

    • Django

 

    • Postgres

 

    • Nginx

Gunicorn

我将解释如何创建一个使用Docker容器的开发环境,并且在其中使用requirements.txt作为软件包管理工具。

此外,作为应用部分在文章的后半部分。

    • Poetryを使った開発環境の構築方法

 

    Pydanticを使った環境変数の管理方法

希望首先了解使用Docker的人,先理解基本的requirements.txt构建方法,然后再尝试挑战。

目录结构

初次创建时的目录结构如下:
请创建一个 containers 文件夹,并在其中创建 Django、Postgres 和 Nginx 文件夹。
另外,在 Nginx 文件夹中也创建一个 conf.d 文件夹。

❯ tree
.
├── containers
│   ├── django
│   │   ├──  Dockerfile
│   │   └──  entrypoint.sh
│   ├── postgres
│   │   └── Dockerfile
│   └── nginx
│       ├── Dockerfile
│       └── conf.d
│           └── default.conf
├── .gitignore
├── .env
├── .env.prod
├── docker-compose.prod.yml
├── docker-compose.yml
└── requirements.txt

创建文件

    • DjangoのDockerfile

 

    • PostgreSQLのDockerfile

 

    • NginxのDockerfile

 

    • default.conf(Nginx用の設定ファイル)

 

    • docker-compose.yml(開発用)

 

    • docker-compose.prod.yml(本番用)

 

    • requirements.txt(ざっくり言うとRailsでいうGemfileにあたる)

 

    • .env(開発用の環境変数の設定ファイル)

 

    • .env.prod(本番用の環境変数の設定ファイル)

 

    • entrypoint.sh(Djangoのコマンドを実行する用のシェルスクリプト)

 

    .gitignore

我將按照順序來解釋關於此建立方法。

为什么要将开发和生产环境分开?

如果使用Django+PostgreSQL+Nignx的配置进行开发,由于Nginx只能显示静态文件,因此需要每次重新启动容器才能反映视图和模型的更改(换句话说,无法进行热加载,开发效率低下)。
因此,开发可以在Django+PostgreSQL容器中进行,而生产环境中则通过Nginx端口查看页面。
本文还将解释开发和生产环境下的Dockerfile和docker-compose.yml的编写方法。

请在每个文件中写入所需的代码。

(Paraphrased in Simplified Chinese)

请在每个文件中填写所需的代码。

Dockerfile 的中文释义为:龙舟文件。

Django – 仅提供一种选择。

# Pythonのイメージを指定
FROM python:3
# PYTHONDONTWRITEBYTECODEとPYTHONUNBUFFEREDはオプション
# pycファイル(および__pycache__)の生成を行わないようにする
ENV PYTHONDONTWRITEBYTECODE=1
# 標準出力・標準エラーのストリームのバッファリングを行わない
ENV PYTHONUNBUFFERED=1
# コンテナのワークディレクトリを/codeに指定
WORKDIR /code
# ローカルのrequirements.txtをコンテナの/codeフォルダ直下に置く
COPY requirements.txt /code/
# コンテナ内でpipをアップグレードした後、pip install -r requirements.txtを実行
RUN pip install --upgrade pip && \
    pip install -r requirements.txt
# ソースコードをコンテナにコピー
COPY . /code/
COPY ./containers/django/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

用于Postgres

# PostgreSQLのイメージを指定
# 今回は15.2を使用
FROM postgres:15.2

以下中文方式本地化重述:

使用Nginx

# Nginxのイメージを指定
FROM nginx:1.21-alpine

# ローカルのdefault.confをコンテナにコピー
COPY containers/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

默认.conf(用于NGINX的配置文件)

# Django(Gunicorn)の8000番ポートとつなぐ
upstream django {
    # サーバにDjangoのコンテナ名を指定。今回はapp
    # ポートはDjangoのコンテナの8000番ポート
    server app:8000;
}

server {
    # HTTPの80番ポートを指定
    listen 80;
    server_name 0.0.0.0;

    # プロキシ設定
    # 実際はNginxのコンテナにアクセスしてるのをDjangoにアクセスしてるかのようにみせる
    location / {
        proxy_pass http://django;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }
    
    # djangoの静的ファイル(HTML、CSS、Javascriptなど)を管理
    location /static/ {
		alias /static/;
	}
}

docker-compose.yml(用于开发)

# docker-composeのバージョンを指定
version: "3.9"

# db(Postgres),app(Django)のコンテナを作成
services:
  db:
    # コンテナ名をpostgresに設定
    container_name: postgres
    # PostgreSQLのDockerfileをビルドする
    build:
      # ビルドコンテキストはカレントディレクトリ
      context: .
      dockerfile: containers/postgres/Dockerfile
    # M1チップでも動くように
    # Intel Macの場合あってもなくても動く
    platform: linux/x86_64
    # DBのボリュームを指定
    # ローカルの/data/dbをコンテナの/var/lib/postgresql/dataにマウントする
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    # ヘルスチェック
    healthcheck:
      test: pg_isready -U "${POSTGRES_USER:-postgres}" || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    # コンテナ内の環境変数を.envを使って設定
    env_file:
      - .env
  app:
    # コンテナ名をappに設定
    container_name: app
    # DjangoのDockerfileをビルドする
    build:
      # ビルドコンテキストはカレントディレクトリ
      context: .
      dockerfile: containers/django/Dockerfile
    # ボリュームを指定
    # ローカルのカレントディレクトリをコンテナの/codeにマウントする
    # ローカルの/staticをコンテナの/staticにマウントする
    volumes:
      - .:/code
      - ./static:/static
    # ローカルの8000番ポートとコンテナの8000番ポートをつなぐ
    ports:
      - "8000:8000"
    # シェルスクリプトを実行
    command: sh -c "/usr/local/bin/entrypoint.sh"
    # コンテナ内の環境変数を.envを使って設定
    env_file:
      - .env
    # 先にdbを起動してからappを起動する
    depends_on:
      db:
        condition: service_healthy
volumes:
  db_data:
  static:

docker-compose生产环境配置文件

# docker-composeのバージョンを指定
version: "3.9"

# db(Postgres),app(Django)のコンテナを作成
services:
  db:
    container_name: postgres
    build:
      context: .
      dockerfile: containers/postgres/Dockerfile
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: pg_isready -U "${POSTGRES_USER:-postgres}" || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    # コンテナ内の環境変数を.env.prodを使って設定
    env_file:
      - .env.prod
  app:
    container_name: app
    build:
      context: .
      dockerfile: containers/django/Dockerfile
    volumes:
      - .:/code
      - ./static:/static
    # 8000番ポートをNginx側が接続できるよう開く
    expose:
      - "8000"
    # シェルスクリプトを実行
    command: sh -c "/usr/local/bin/entrypoint.sh"
    # コンテナ内の環境変数を.env.prodを使って設定
    env_file:
      - .env.prod
    depends_on:
      db:
        condition: service_healthy
  web:
    # コンテナ名をwebに指定
    container_name: web
    # NginxのDockerfileをビルドする
    build:
      # ビルドコンテキストはカレントディレクトリ
      context: .
      dockerfile: containers/nginx/Dockerfile
    # ボリュームを指定
    # ローカルの/staticをコンテナの/staticにマウントする
    volumes:
      - ./static:/static
    # ローカルの80番ボートをコンテナの80番ポートとつなぐ
    ports:
      - "80:80"
    # 先にappを起動してからwebを起動する
    depends_on:
      - app
volumes:
  db_data:
  static:

要求文件

    • Django

 

    • psycopg2

 

    Gunicorn

我将在Django容器中安装它,请记录。

Django>=3.0,<4.0
psycopg2>=2.8
gunicorn>=19.9.0,<20.1.0

.env文件。

由于在docker-compose.yml或Django的settings.py中写入PostgreSQL的root用户密码等信息是危险的,因此我们将使用.env文件。由于这是开发环境,所以需要将DEBUG设置为True。由于有.gitignore文件,.env文件不会在GitHub上被上传。本次的.env文件内容如下:

# POSTGRES_NAME="任意のデータベース名"
# POSTGRES_USER="任意のユーザ名"
# POSTGRES_PASSWORD="任意のパスワード"
POSTGRES_NAME=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
# SECRET_KEYは任意
SECRET_KEY=postgres
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
# 開発環境のためTrue
DEBUG=True

.env.prod => .环境.生产

接下来,我们将设置用于生产环境的环境变量。
实际上,生产环境的环境变量将保存在AWS参数存储中,但本次我们将使用.env.prod文件。
由于这是用于生产环境的,所以需要将DEBUG设置为False。

# POSTGRES_NAME="任意のデータベース名"
# POSTGRES_USER="任意のユーザ名"
# POSTGRES_PASSWORD="任意のパスワード"
POSTGRES_NAME=postgres
POSTGRES_USER=postgres-prod
POSTGRES_PASSWORD=postgres-prod
# SECRET_KEYは任意
SECRET_KEY="postgres"
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
# 開発環境のためTrue
DEBUG=False

入口点.sh

定义了用于收集Django的迁移、管理页面和Django Rest Framework的静态文件的命令。此外,在开发环境和生产环境中使用的命令不同,因此将它们写在一个shell脚本中可以提高可读性,而不需要在docker-compose.yml文件中重复相似的描述。

#!/bin/sh

请记得写上这个类似于执行shell脚本的咒语。

#!/bin/sh
python manage.py makemigrations --noinput
python manage.py migrate --noinput
python manage.py collectstatic --noinput
# 環境変数のDEBUGの値がTrueの時はrunserverを、Falseの時はgunicornを実行します
# シェルスクリプトでは`[`と`$DEBUG`、`1`と`]`の間にスペースを一つ空けておかないと[]内の式を認識できないので注意
if [ $DEBUG = 1 ]; then
    python manage.py runserver 0.0.0.0:8000
else
    # gunicornを起動させる時はプロジェクト名を指定します
    # 今回はdjangopjにします
    gunicorn djangopj.wsgi:application --bind 0.0.0.0:8000
fi

.gitignore

.gitignore文件

从GitHub的官方网站创建Python的.gitignore文件
由于.gitignore中没有.env.prod,因此需要追加
另外,migration和static在实际开发中不需要纳入Git的管理,因此也需追加到.gitignore中。

# Environments
.env
# .env.prodを.gitignoreする
.env.prod
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

・・・

# ignore static files
static/
# ignore migration files
migrations/

 

让我们构建图像,并展示Django的界面。

这次我希望通过访问Nginx的端口来显示Django的页面,所以我要使用docker-compose.prod.yml(生产环境文件)。如果要进行开发,请将命令中指定的文件替换为docker-compose.yml,并访问8000端口。

首次使用docker-compose创建Docker镜像。

在创建新项目时,请指定项目名称和要创建的目录,并执行以下命令。
这次我们将在当前目录下创建一个名为djangopj的项目。

# プロジェクトを新規作成
# docker-compose -f <指定するdocker-composeのファイル> run app django-admin startproject <プロジェクト名> <プロジェクトを作成するディレクトリ>
docker-compose -f docker-compose.prod.yml run app django-admin startproject djangopj .

执行后,本地目录结构如下:
由于data/db中的文件非常多,所以省略显示。

❯ tree
.
├── containers
│   ├── django
│   │   ├── Dockerfile
│   │   └── dev
│   │       └── Dockerfile
│   ├── postgres
│   │   └── Dockerfile
│   └── nginx
│       ├── Dockerfile
│       └── conf.d
│           └── default.conf
├── djangopj
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── .env
├── .env.prod
├── .gitignore
├── docker-compose.prod.yml
├── docker-compose.yml
├── entrypoint.sh
├── manage.py
├── requirements.txt
└── static

如果已经有项目存在的话

当需要克隆GitHub上的源代码或项目已经创建完成时,请执行以下命令。

docker-compose -f docker-compose.prod.yml build

更改settings.py文件中的DATABASES设置。

需要将Django默认的数据库从SQlite更改为Postgres。

import os
   
[...]

# SECRET_KEYを.envから取得
SECRET_KEY = os.environ.get("SECRET_KEY")

# DEBUGを.envから取得
# envファイルにTrue、Falseと書くとDjangoがString型と認識してしまいます
# os.environ.get("DEBUG") == "True"を満たすとboolean型のTrueになり、
# env内のDEBUGがTrue以外ならFalseになります
DEBUG = os.environ.get("DEBUG") == "True"

# ALLOWED_HOSTSを.envから取得
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")

[...]

# PostgreSQLのパラメータを.envから取得
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('POSTGRES_NAME'),
        'USER': os.environ.get('POSTGRES_USER'),
        'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
        'HOST': 'db',
        'PORT': 5432,
        "OPTIONS": {
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

[...]

# 言語を日本語に設定
LANGUAGE_CODE = ja
# タイムゾーンをAsia/Tokyoに設定
TIME_ZONE = Asia/Tokyo

# STATIC_ROOTを設定
STATIC_ROOT = "/static/"
STATIC_URL = "/static/"

启动容器

以容器的分離模式启动
通过分离模式启动,可以在后台启动容器而无需进入容器中。

docker compose -f docker-compose.prod.yml up -d

让我们尝试访问127.0.0.1/80。

从主机连接到Nginx的端口
通过浏览器访问,可以从Nginx的端口访问到Django的端口
将显示以下页面

スクリーンショット 2022-10-16 21.03.54.png

如果成功,访问 127.0.0.1/80/admin,出现下面的界面。

スクリーンショット 2022-10-16 21.06.04.png

如果将DEBUG设置为True,将显示下面的图像。

スクリーンショット 2022-08-17 21.10.44.png
当画面无法显示时,应该怎么办?

如果没有显示出类似上述的画面,则可能是因为在首次启动时,PostgreSQL容器没有成功启动的可能性。

docker-compose -f docker-compose.prod.yml down

在停止容器之后

docker compose -f docker-compose.prod.yml up -d

当无法通过再次运行”docker compose -f docker-compose.prod.yml up -d”来连接时

连接上游时失败(111:连接被拒绝)。

需要重新审查Nginx的default.conf。

upstream django {
    server app:8000;
}

请使用docker ps命令确认是否正确指定了FastAPI的容器名称,因为经常会出现在指定服务器之后错误指定了Nginx容器名称而不是Django的情况。

django.db.utils.OperationalError: 严重错误:数据库不存在

如果在.env文件中,POSTGRES_NAME的名称不符合命名规则,可能会出现如上所示的错误。请从以下网站检查您设置的数据库名称是否符合PostgreSQL的命名规则。

 

使用诗歌构建容器环境

可以更好地管理Python项目的依赖关系和版本。

    • コマンド一つでパッケージをインストールできる

 

    • パッケージ間の依存関係を自動で解消してくれる

 

    Blackなどの設定を共通のファイルにまとめることができる

如果可能的话,建议学习以下内容,因为它在实际的开发现场经常被使用,非常方便。您可以参考以下文章以获取更多详细信息。

 

目录结构

关于目录结构,requirements.txt将被替换为pyproject.toml。

tree
.
├── containers
│   ├── django
│   │   └── Dockerfile
│   ├── postgres
│   │   └── Dockerfile
│   └── nginx
│       ├── Dockerfile
│       └── conf.d
│           └── default.conf
├── .gitignore
├── .env
├── .env.prod
├── entrypoint.sh
├── docker-compose.prod.yml
├── docker-compose.yml
└── pyproject.toml

pyproject.toml可以用于定义Python项目的元数据和工具配置。

与requirements.txt类似

[tool.poetry.dependencies]

我将在内部安装以下软件包。

[tool.poetry]
name = "api"
version = "0.1.0"
description = "api"
authors = ["shun198"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
Django = "^4.2.3"
djangorestframework = "^3.14.0"
psycopg2 = "^2.9.6"
gunicorn = "^20.1.0"

Dockerfile(Django)

FROM python:3
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY pyproject.toml /code/
RUN pip install --upgrade pip && \
    pip install poetry
RUN poetry install
COPY ./containers/django/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

创建新项目

创建新项目时,请输入以下命令。

docker-compose run app poetry run django-admin startproject djangopj .

如果能达到以下的情况,就算成功了。

如果能实现以下的要求,就算是成功了。

如果能达到以下的标准,就可以算是成功了。

tree
.
├── containers
│   ├── django
│   │   └── Dockerfile
│   ├── postgres
│   │   └── Dockerfile
│   └── nginx
│       ├── Dockerfile
│       └── conf.d
│           └── default.conf
├── djangopj
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── .env
├── .env.prod
├── .gitignore
├── docker-compose.prod.yml
├── docker-compose.yml
├── entrypoint.sh
├── manage.py
├── poetry.lock
├── pyproject.toml
└── static

使用Pydantic进行环境变量管理

Pydantic是一个通过使用Python的类型注解来提供类型提示,并使验证错误变得容易的库。可以通过使用它来设置环境变量。

    • 使用している環境変数の型が直感的にわかる

 

    環境変数関連でエラーが発生するとPydanticのエラーが出るのでデバッグが容易になる

有哪些优点?

pyproject.toml的中文翻译是什么?

安装Pydantic

[tool.poetry]
name = "djangopj"
version = "0.1.0"
description = "api"
authors = ["shun198"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
Django = "^4.2.3"
djangorestframework = "^3.14.0"
psycopg2 = "^2.9.6"
gunicorn = "^20.1.0"
pydantic = "^1.10.6"

设置环境变量

本次在djangopj中创建environment.py。

tree
.
├── containers
│   ├── django
│   │   └── Dockerfile
│   ├── postgres
│   │   └── Dockerfile
│   └── nginx
│       ├── Dockerfile
│       └── conf.d
│           └── default.conf
├── djangopj
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── environment.py
│   ├── urls.py
│   └── wsgi.py
├── .env
├── .env.prod
├── .gitignore
├── docker-compose.prod.yml
├── docker-compose.yml
├── entrypoint.sh
├── manage.py
├── poetry.lock
├── pyproject.toml
└── static

环境.py

请按照下列方式设置环境变量。

"""環境変数定義用のモジュール"""

from pydantic import BaseSettings


class DjangoSettings(BaseSettings):
    """Django関連の環境変数を設定するクラス"""

    SECRET_KEY: str = "secretkey"
    ALLOWED_HOSTS: str = "localhost 127.0.0.1 [::1] back web"
    POSTGRES_NAME: str = "postgres"
    POSTGRES_USER: str = "postgres"
    POSTGRES_PASSWORD: str = "postgres"
    POSTGRES_HOST: str = "db"
    POSTGRES_PORT: int = 5432
    TRUSTED_ORIGINS: str = "http://localhost"


django_settings = DjangoSettings()

如果导入django_settings,可以设置环境变量,使用编辑器的自动补全功能可以无误地设置相应的环境变量,以便开发进展顺利。

from .environment import django_settings

# SECRET_KEYを.envから取得
SECRET_KEY = django_settings.SECRET_KEY

# ALLOWED_HOSTSを.envから取得
ALLOWED_HOSTS = django_settings.ALLOWED_HOSTS.split()

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        # コンテナ内の環境変数をDATABASESのパラメータに反映
        "NAME": django_settings.POSTGRES_NAME,
        "USER": django_settings.POSTGRES_USER,
        "PASSWORD": django_settings.POSTGRES_PASSWORD,
        "HOST": django_settings.POSTGRES_HOST,
        "PORT": django_settings.POSTGRES_PORT,
        "OPTIONS": {
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

以上 即为全部内容。 (jí

介绍这篇文章

如果您有空,希望您能阅读我也写的这篇文章。

 

文献引用

 

广告
将在 10 秒后关闭
bannerAds