使用Docker重新搭建Django的开发环境!!!!

首先

我以前写过这样一篇文章。
使用 Docker 搭建 Django 的开发环境!(Docker-compose/Django/postgreSQL/nginx)

这篇文章是相当久以前写的(大概一年前吧?),但是现在我的知识储备已经累积了一些,或许可以尝试做出更好的构思呢!所以我决定挑战一下!

不会涉及Docker安装等细节问题,如果您感兴趣的话,请参见原文!(我认为这篇文章可能会对您有所帮助。)

另外,与以前的文章明显不同的一点是,Django被视为API传递服务器并且假设使用Vue.js或React进行前端实现,因此不进行静态文件分发或模板设置。同时,本文没有创建docker-compose.yml和docker-compose.yml.prod来区分生产环境和开发环境,请谅解。

这是一个目录。

    • 目次

 

    • ディレクトリ構成

 

    • Django環境の構築

 

    • PostgreSQL環境の構築

 

    • docker-composeを利用してみる

 

    • nginx環境の構築

 

    docker-compose.ymlにnginxを追加する

目录结构

最后,目录结构变成了这样的感觉!

backend
└── containers
    ├── django
    │   ├── Dockerfile
    │   ├── Pipfile
    │   ├── Pipfile.lock
    │   ├── config
    │   │   ├── __init__.py
    │   │   ├── settings.py
    │   │   ├── urls.py
    │   │   └── wsgi.py
    │   ├── entrypoint.sh
    │   ├── manage.py
    ├── docker-compose.yml
    ├── nginx
    │   ├── Dockerfile
    │   └── nginx.conf
    └── postgres
        ├── Dockerfile
        └── sql
            └── init.sql

我们将每个容器放置在backend目录下的containers目录中。

与上一篇文章相比,添加了postgres目录等变动。

接下来,让我们立即从顶层的django目录开始构建!

建立Django环境

首先,让我们创建三个目录,分别是backend、containers和django!然后,进入django目录。

$mkdir -p backend/containers/django
$cd backend/containers/django

首先,在django目录中创建一个Pipfile文件。每个软件包的版本是本文撰写时的最新版本,并且没有特定要求。请随意更改(无法保证其运行)。

另外,如果只需要进行环境配置并且安装的包是可选的话,只要安装django、gunicorn和django-environ就没问题了。

[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
django = "==3.0.6"
djangorestframework = "==3.11.0"
djangorestframework-simplejwt = "==4.4.0"
djangorestframework-gis = "==0.15"
django-cors-headers = "==3.2.1"
django-environ = "==0.4.5"
djoser = "==2.0.3"
gunicorn = "==20.0.4"
psycopg2-binary = "==2.8.5"

[requires]
python_version = "3.8.2"

让我们使用pipenv在Python 3.8系列中创建虚拟环境,并进入虚拟环境来确认版本和已安装的包。

$pipenv install
$pipenv shell
(django) $python -V
Python 3.8.2
(django) $pip list
Package                       Version
----------------------------- -------
asgiref                       3.2.7
Django                        3.0.6
django-cors-headers           3.2.1
django-environ                0.4.5
django-templated-mail         1.1.1
djangorestframework           3.11.0
djangorestframework-gis       0.15
djangorestframework-simplejwt 4.4.0
djoser                        2.0.3
gunicorn                      20.0.4
pip                           20.0.2
psycopg2-binary               2.8.5
PyJWT                         1.7.1
pytz                          2020.1
setuptools                    46.1.3
sqlparse                      0.3.1
wheel                         0.34.2

如果在终端的左侧显示着(django)的文字,则表示已进入虚拟环境。(为简化起见,之后不再提及(django)这个字符串)

你已经成功地安装了Django!

在确定你正在django目录中时,可以使用Django命令来创建项目。

$django-admin startproject config .

通过以上步骤,Django项目已成功创建完成。你应该可以在django目录下确认到已创建了名为config的文件夹和名为manage.py的文件。

在这个阶段,你可以使用”python manage.py runserver localhost:8000″命令来启动调试服务器,并且在浏览器中连接到loaclhost:8000,应该会显示出比亲人脸还要熟悉的那个页面。

スクリーンショット 2020-05-07 17.16.32.png

接下来,让我们按照以下的方式来修改Django相关的文件。

请把 SECRET_KEY 注释掉或做其他处理,因为之后会用到它。

import os
from datetime import timedelta
import environ

env = environ.Env()
env.read_env('.env')

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = env.get_value('SECRET_KEY')

DEBUG = env.get_value('DEBUG')

ALLOWED_HOSTS = ['localhost', '127.0.0.1']

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'rest_framework',
    'rest_framework_gis',
    'corsheaders',
    'django.contrib.gis',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'config.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': env.get_value('DATABASE_ENGINE', default='django.db.backends.sqlite3'),
        'NAME': env.get_value('DATABASE_DB', default=os.path.join(BASE_DIR, 'db.sqlite3')),
        'USER': env.get_value('DATABASE_USER', default='django_user'),
        'PASSWORD': env.get_value('DATABASE_PASSWORD', default='password'),
        'HOST': env.get_value('DATABASE_HOST', default='localhost'),
        'PORT': env.get_value('DATABASE_PORT', default='5432'),
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}

SIMPLE_JWT = {
    'AUTH_HEADER_TYPES': ('JWT',),
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
}

CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    'http://localhost:8080',
    'http://127.0.0.1:8080',
)

最初创建Pipfile时,我添加了一个名为django-environ的包,它用于在.env文件中记录需要保密的信息,例如SECRET_KEY和与数据库的连接信息,并与源代码分开管理,可以通过setting.py等文件引用该包。

env = environ.Env()
env.read_env('.env')

以类似的方式使用。

我们赶快创建一个.env文件吧。

DEBUG=True
SECRET_KEY=<YOUR_SECRET_KEY>
DATABASE_ENGINE=django.contrib.gis.db.backends.postgis
DATABASE_DB=<YOUR_DB_NAME>
DATABASE_USER=<YOUR_DB_USER>
DATABASE_PASSWORD=<YOUR_DB_PASSWORD>
#entrypoint.shで利用
#compose.ymlに記載のサービス名で名前解決してくれる
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE=postgres
    • :setting.pyに元々記載されていたKEY

 

    (USER/PASSWORD):任意のもの入れてください。詳しくはPostgreSQLコンテナを立ち上げる際に説明します

接下来,我们将继续修复与之密切相关的文件。我们会在提供来自`backend`目录的路径的基础上,适时进行必要文件的创建、追加和修正操作。

# ubuntuのイメージをプルし、Pythonをインストールしていく
FROM ubuntu:20.04

SHELL ["/bin/bash", "-c"]

# pythonをインストール
RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get install -y python3.8 python3.8-dev \
    && source ~/.bashrc \
    && apt-get -y install vim

# 作業ディレクトリを設定
WORKDIR /usr/src/app

# 環境変数を設定
# Pythonがpyc filesとdiscへ書き込むことを防ぐ
ENV PYTHONDONTWRITEBYTECODE 1
# Pythonが標準入出力をバッファリングすることを防ぐ
ENV PYTHONUNBUFFERED 1
ENV DEBIAN_FRONTEND=noninteractive

# 依存関係のインストールとpipenvをインストール
RUN apt-get install -y curl \
    && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \
    && apt-get install -y python3.8-distutils \
    && python3.8 get-pip.py \
    && pip install -U pip \
    && apt-get install -y build-essential libssl-dev libffi-dev python-dev python3-dev libpq-dev

# pipenvのインストール
RUN pip install pipenv

# ローカルマシンののPipfileをコンテナにコピー
COPY Pipfile ./

# Pipfile.lockを無視してPipfileに記載のパッケージをシステムにインストール
# その後、pipenvをアンインストール
RUN pipenv install --system --skip-lock \
    && pip uninstall -y pipenv virtualenv-clone virtualenv

# 地理空間ライブラリをインストールする際の依存関係
RUN apt-get update -y \
    && apt-get upgrade -y \
    && apt-get install -y libgeos-dev binutils libproj-dev gdal-bin libgdal-dev \
    && apt-get install -y python3-gdal

RUN apt-get install -y netcat \
    && apt-get install -y expect

# シェルスクリプトをコピー
# COPY ./entrypoint.sh /usr/src/app/entrypoint.sh

COPY . /usr/src/app/

# シェルスクリプトを実行
# ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

让我们验证在这个阶段容器是否正常运行。

$docker build . -t pipenv_sample
...
$docker run -it pipenv_sample
root@e6bdfb335bee:/usr/src/app#

如果能够使用root用户登录到容器中,那么很可能就成功了!

# python3 -V
Python 3.8.2
# pip list
Package                       Version
----------------------------- ----------
appdirs                       1.4.3
asgiref                       3.2.7
certifi                       2020.4.5.1
distlib                       0.3.0
Django                        3.0.6
django-cors-headers           3.2.1
django-environ                0.4.5
django-templated-mail         1.1.1
djangorestframework           3.11.0
djangorestframework-gis       0.15
djangorestframework-simplejwt 4.4.0
djoser                        2.0.3
filelock                      3.0.12
GDAL                          3.0.4
gunicorn                      20.0.4
numpy                         1.17.4
pip                           20.1
pipenv                        2018.11.26
psycopg2-binary               2.8.5
PyJWT                         1.7.1
pytz                          2020.1
setuptools                    46.1.3
six                           1.14.0
sqlparse                      0.3.1
virtualenv                    20.0.20
virtualenv-clone              0.5.4
wheel                         0.34.2

Python的版本是3.8.2,并且包已经成功安装了!

让我们使用 Control + d 进行注销。

最后,我们来编写并保存启动时与postgres容器连接的shell脚本。

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $DATABASE_HOST $DATABASE_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

exec "$@"

顺便说一句,在您编辑的 Dockerfile 文件的末尾附近,请取消两个注释。

# これ
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh

COPY . /usr/src/app/

# これ
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

暂时就这样,关于Django目录的讨论到此为止。

    ディレクトリ構成
backend
└── containers
    ├── django
    │   ├── Dockerfile
    │   ├── Pipfile
    │   ├── Pipfile.lock
    │   ├── config
    │   │   ├── __init__.py
    │   │   ├── settings.py
    │   │   ├── urls.py
    │   │   └── wsgi.py
    │   ├── entrypoint.sh
    │   ├── manage.py
    └── docker-compose.yml

搭建PostgreSQL环境

下一步是启动PostgreSQL容器。

首先,让我们进入容器目录并创建postgres等目录。

$cd ../../
$mkdir -p postgres/sql/

我认为这样,postgres目录和其中的sql目录就已经创建好了。

让我们在postgres目录中添加Dockerfile。

FROM mdillon/postgis:11

RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.UTF-8

我希望创建的是一个地图应用程序,因此我将使用PostGIS图像作为PostgreSQL的扩展功能。但我认为可以使用任何PostgreSQL图像。(我还没有验证过它的操作是否有效)

接下来,我们将把希望在容器启动时执行的SQL文件存储在sql目录中。

CREATE EXTENSION postgis;

本次只儲存了用於啟用擴展功能的SQL文件,但如果您有任何希望進行初始註冊的數據等,請自由儲存。

最后,我们会添加.env_db文件。

请写下与您在创建Django容器时填写的(USER/PASSWORD)相同的内容。

在此处所述的内容将自动创建数据库。

#envに書いておけば自動でDBが作成される
POSTGRES_DB=<YOUR_DB_NAME>
POSTGRES_USER=<YOUR_DB_USER>
POSTGRES_PASSWORD=<YOUR_DB_PASSWORD>

以上是PostgreSQL环境搭建的完成。

    ディレクトリ構成
backend
└── containers
    ├── django
    │   ├── Dockerfile
    │   ├── Pipfile
    │   ├── Pipfile.lock
    │   ├── config
    │   │   ├── __init__.py
    │   │   ├── settings.py
    │   │   ├── urls.py
    │   │   └── wsgi.py
    │   ├── entrypoint.sh
    │   ├── manage.py
    ├── docker-compose.yml
    └── postgres
        ├── Dockerfile
        └── sql
            └── init.sql

尝试使用Docker Compose

docker-compose是一个方便的工具,用于同时启动多个容器并连接它们。

立即转到containers文件夹,并开始创建配置文件。

$cd ../
$touch docker-compose.yml
version: "3.7"
services:
  django:
    # コンテナ名
    container_name: django
    # ビルドするdockerファイルが格納されたディレクトリ
    build: ./django
    # 正常起動後に実行するコマンド
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      # マウントするディレクトリ
      - ./django:/usr/src/app/
    ports:
      # ホスト側のポート:コンテナ側のポート
      - 8000:8000
    env_file:
      # 環境変数に設定するファイル
      - ./django/.env
    depends_on:
      # 接続するサービス
      - postgres

  postgres:
    container_name: postgres
    build: ./postgres
    volumes:
      # DBのデータはボリュームを作成して保存
      # ディレクトリとマウントとって実データをホストOSに直接残しても良い
      # /var/lib/postgresql/dataにDBのデータが格納されている
      - sample_postgis_data:/var/lib/postgresql/data
      # down -vなどでボリュームがない時などを含めた初回起動時に実行されるファイルを指定
      - ./postgres/sql:/docker-entrypoint-initdb.d
    env_file: ./postgres/.env_db
    ports:
      # ホスト側のポートはローカルのpsqlとバッティングするので5432以外にする
      - 5433:5432

volumes:
  sample_postgis_data:

写完后,让我们尝试启动docker-compose。

$docker-compose up -d --build

让我们尝试通过浏览器连接到 localhost:8000。

只要能够成功显示Django初始界面,就比仅仅看到兄弟的脸要重要得多。

您可以使用以下命令登录到容器中。

$docker exec -it <サービス名> bash

总的来说,关于这个问题,您可以通过以下方式进行连接。

$docker exec -it django bash
または
$docker exec -it postgres bash

既然确认了Django容器的启动情况,那我们也来确认一下postgres容器的情况吧。

$docker exec -it postgres bash
#psql -U <YOUR_DB_USER> -d <YOUR_DB_NAME>
psql (11.2 (Debian 11.2-1.pgdg90+1))
"help" でヘルプを表示します。

<YOUR_DB_NAME>=#
<YOUR_DB_NAME>=# SELECT postgis_version();
            postgis_version
---------------------------------------
 2.5 USE_GEOS=1 USE_PROJ=1 USE_STATS=1
(1 行)

我确认数据库是根据DB的规定创建的,并且postgis已经启用了。

请使用以下命令暂停容器并删除镜像。

$docker-compose down -v

搭建nginx环境

最后,让我们开始建立nginx环境。

首先创建nginx目录,并创建Dockerfile。

$mkdir nginx
$cd nginx/
$touch Dockerfile
FROM nginx:1.17.10

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

接下来

upstream config {
    # コンテナのサービス名を指定すると名前解決してくれる
    server django:8000;
}

server {
    # 80ポートで待ち受け
    listen 80;

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

    # 静的ファイルの要求をstaticにルーティング
    location /static/ {
        alias /usr/src/app/static/;
    }
}

我认为所需的文件都已经准备齐全了。

在docker-compose.yml文件中添加nginx。

请按照以下步骤,在服务器上添加nginx服务,并将django服务的命令从runserver改为gunicorn。

version: "3.7"
services:
  django:
    # コンテナ名
    container_name: django
    # ビルドするdockerファイルが格納されたディレクトリ
    build: ./django
    # 正常起動後に実行するコマンド
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    volumes:
      # マウントするディレクトリ
      - ./django:/usr/src/app/
    ports:
      # ホスト側のポート:コンテナ側のポート
      - 8000:8000
    env_file:
      # 環境変数に設定するファイル
      - ./django/.env
    depends_on:
      # 接続するサービス
      - postgres

  postgres:
    container_name: postgres
    build: ./postgres
    volumes:
      # DBのデータはボリュームを作成して保存
      # ディレクトリとマウントとって実データをホストOSに直接残しても良い
      # /var/lib/postgresql/dataにDBのデータが格納されている
      - sample_postgis_data:/var/lib/postgresql/data
      # down -vなどでボリュームがない時などを含めた初回起動時に実行されるファイルを指定
      - ./postgres/sql:/docker-entrypoint-initdb.d
    env_file: ./postgres/.env_db
    ports:
      # ホスト側のポートはローカルのpsqlとバッティングするので5432以外にする
      - 5433:5432

  nginx:
    container_name: nginx
    build: ./nginx
    volumes:
      - ./django/static:/usr/src/app/static
    ports:
      - 80:80
    depends_on:
      - django

volumes:
  sample_postgis_data:

我将尝试启动容器。

$docker-compose up -d --build

如果可以确认在nginx容器中可以从80端口进行分发,那么环境设置就完成了。

我们来尝试连接到本地主机吧。

看到的屏幕显示的比姐姐的脸还要清晰。

辛苦了。剩下的事情随你喜欢煮或者烤!

    最終的なディレクトリ構成(冒頭に記載のものと同じ)
backend
└── containers
    ├── django
    │   ├── Dockerfile
    │   ├── Pipfile
    │   ├── Pipfile.lock
    │   ├── config
    │   │   ├── __init__.py
    │   │   ├── settings.py
    │   │   ├── urls.py
    │   │   └── wsgi.py
    │   ├── entrypoint.sh
    │   ├── manage.py
    ├── docker-compose.yml
    ├── nginx
    │   ├── Dockerfile
    │   └── nginx.conf
    └── postgres
        ├── Dockerfile
        └── sql
            └── init.sql
广告
将在 10 秒后关闭
bannerAds