使用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,应该会显示出比亲人脸还要熟悉的那个页面。

接下来,让我们按照以下的方式来修改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