再構築してみました!
DockerでDjangoの開発環境を再構築!!!!
はじめに
チーム開発…環境構築がめっちゃめんどくさいっすよね…そんな時はDockerを使いましょう(雑)
この記事はqrunchにあげたものの再投稿になります!元記事
チームでの開発に非常に便利なDockerとDocker-composeを利用してDjango/postgreSQL/gunicorn/nginxの開発環境を構築していきましょう!!
全体の流れはほぼ以下のサイトを参考にさせてもらっていますが、設定ファイル等のほぼ全行にコメントを挟むなど理解しやすいような記事にしたつもりです!
Dockerizing Django with Postgres, Gunicorn, and Nginx
結構長い記事になってしまったので淡々と進めます!
この記事でやること
- DockerとDocker-composeのインストール
- pipenvのインストールと仮想環境構築
- Dockerコンテナの構築
- Django
- postgres
- gunicorn
- nginx
静的ファイルの処理
DockerとDocker-composeのインストール
皆さんはご存知かと思いますが、Dockerは簡単に言えば(簡単にしか言えない)お手持ちのPCのなかに仮想的に別のOSを入れて動かせる上にその環境を丸ごとコピーして他の人に渡せるツールのことです!
詳しくは以下のページなどを参考ください!
Docker入門(第一回)~Dockerとは何か、何が良いのか~
なにはともあれDockerをインストールしましょう!
docker
https://docs.docker.com/docker-for-mac/install/からインストール
docker-compose
$ curl -L https://github.com/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
バージョンの確認
以下のコマンドでバージョンが表示されればインストール完了です!
$ docker --version
Docker version 18.09.2
$ docker-compose --version
docker-compose version 1.23.2
Django用のディレクトリを作成
次にDjangoプロジェクトを作成するためのディレクトリを作成しましょう
<!-- プロジェクト用のディレクトリを作成(appディレクトリがdjangoプロジェクトのルートディレクトリ) -->
$ mkdir docker-demo-with-django && cd docker-demo-with-django
$ mkdir app && cd app
pipenvでホスト側の環境構築
pipenvは最近開発されたvenvやvenv-virtuarenvなどと比較されるpythonの仮想環境構築ツールです
pipとvirtuarenvが合体した様な機能を持っており、pipfile
およびPipfile.lock
の2種類のファイルで仮想環境およびパッケージのバージョンを管理できる優れものです
DockerでDjangoの環境を構築する際には上記2ファイルをコピーしてpipenvを実行するだけで同様のpython開発環境を作成できますのでこれを使用していきましょう
docker-demo-with-django/app/
にPipfileを用意してpackages
の欄にDjango = "==2.2.3"
を入れるのを忘れない様にしましょう
docker-demo-with-django/app/Pipfile
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
Django = "==2.2.3"
[requires]
python_version = "3.7"
pipfile
を作成したら同ディレクトリで以下のコマンドを入力しますy
<!-- pipenv本体のインストール -->
:app$ pip install pipenv
<!-- Pipfileから仮想環境構築 -->
:app$ pipenv install
<!-- 仮想環境に入る -->
:app$ pipenv shell
<!-- Djangoプロジェクトのスタート -->
(app) :app$ django-admin.py startproject django_demo .
<!-- モデルの内容をデータベースに適用 -->
(app) :app$ python manage.py migrate
<!-- 開発用サーバーの起動 -->
(app) :app$ python manage.py runserver
http://localhost:8000/にアクセスしてみてください。Djangoのwelcome screenが表示されるはずです
現在のディレクトリ構成
:docker-demo-with-django$ tree
.
└── app
├── Pipfile
├── Pipfile.lock
├── db.sqlite3
├── django_demo
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Dockerコンテナの構築
Django
appディレクトリに以下の様なDockerfile
を追加します
今回は最低限の環境を作るのが目的のため、公式からインストールするDockerイメージはすべて軽量なalpine linux
を利用します
これによってubuntu等のイメージと比較して1/10程度の容量で環境を構築できます
docker-demo-with-django/app/Dockerfile
# 公式からpython3.7 on alpine linuxイメージをpull
FROM python:3.7-alpine
# 作業ディレクトリを設定
WORKDIR /usr/src/app
# 環境変数を設定
# Pythonがpyc filesとdiscへ書き込むことを防ぐ
ENV PYTHONDONTWRITEBYTECODE 1
# Pythonが標準入出力をバッファリングすることを防ぐ
ENV PYTHONUNBUFFERED 1
# Pipenvをインストール
RUN pip install --upgrade pip \
&& pip install pipenv
# ホストのpipfileをコンテナの作業ディレクトリにコピー
COPY ./Pipfile /usr/src/app/Pipfile
# pipfileからパッケージをインストールしてDjango環境を構築
RUN pipenv install --skip-lock --system --dev
# ホストのカレントディレクトリ(現在はappディレクトリ)を作業ディレクトリにコピー
COPY . /usr/src/app/
次にプロジェクトのルート(docker-demo-with-django
)にdocker-compose.yml
を追加
version: '3.7'
services:
# サービス名は自由に設定
django:
# appディレクトリの中から`Dockerfile`を探す
build: ./app
# サービス起動後に入力されるコマンドを設定
command: python manage.py runserver 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- ./app/:/usr/src/app/
# 開放するポートを指定。`host:container`でポートを記載
ports:
- 8000:8000
# 環境変数を指定
environment:
# 1ならデバックモード
- DEBUG=1
# setting.pyに記載されているSECRET_KEYを記入
- SECRET_KEY=hoge
djangoプロジェクトのsetting.pyを修正します。
修正項目はSECRET_KEY
,DEBUG
,ALLOWED_HOSTS
の3項目
# 環境変数からSECRET_KEYを取得する設定
SECRET_KEY = os.environ.get('SECRET_KEY')
# 環境変数からDEBUGを取得。デフォルトはTrue(本番環境モード)
DEBUG = int(os.environ.get('DEBUG', default=0))
# 許可するホストを記載
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
修正が終わったらdocker-compose up -d --build
コマンドでビルドと起動を同時に行います
-d
オプションはバックグランドで起動することを意味します
http://localhost:8000/に接続してwelcome screenが表示されれば成功です
Postgres
psotgresを追加するにはdocker-compose.yml
に新しいサービスを追加します
同時に、djangoサービスにデータベースの設定をする必要があります
version: '3.7'
services:
# サービス名は自由に設定
django:
# appディレクトリの中から`Dockerfile`を探す
build: ./app
# サービス起動後に入力されるコマンドを設定
command: python manage.py runserver 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- ./app/:/usr/src/app/
# 開放するポートを指定。`host:container`でポートを記載
ports:
- 8000:8000
# 環境変数を指定
environment:
# 1ならデバックモード
- DEBUG=1
- SECRET_KEY=hoge
- DATABASE_ENGINE=django.db.backends.postgresql
- DATABASE_DB=django_db
- DATABASE_USER=django_db_user
- DATABASE_PASSWORD=password1234
- DATABASE_HOST=postgres
- DATABASE_PORT=5432
# 接続するサービスを指定
depends_on:
- postgres
postgres:
# 公式からイメージをpull
image: postgres:11.4-alpine
# データベースの永続化
# ホストのディレクトリにマウントしない様に、先頭に`./`をつけない
volumes:
- postgres_data:/var/lib/postgresql/data
# su権限を持つ、指定されたユーザーと同じ名前のデータベースを作成
# valueはdjangoサービスで指定したものと同じ様に記載する
environment:
- POSTGRES_USER=django_db_user
- POSTGRES_PASSWORD=password1234
- POSTGRES_DB=django_db
# トップレベルに書く「名前付きvolumes」は複数サービスから参照できる
volumes:
postgres_data:
次にsetting.pyのDATABASES
の項目を書き換えます
DATABASES = {
'default': {
'ENGINE': os.environ.get('DATABASE_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('DATABASE_DB', os.path.join(BASE_DIR, 'db.sqlite3')),
'USER': os.environ.get('DATABASE_USER', 'user'),
'PASSWORD': os.environ.get('DATABASE_PASSWORD', 'password'),
'HOST': os.environ.get('DATABASE_HOST', 'localhost'),
'PORT': os.environ.get('DATABASE_PORT', '5432'),
}
}
djangoからpostgresに接続するためにはドライバーを利用する必要があります
今回はもっともメジャーなドライバーであるpsycopg2
を利用するためにdocker-demo-with-django/app/Dockerfile
を修正しましょう
Dockerfileは以下の様になります
alpine linuxのパッケージマネージャーであるapk
を利用しで依存関係をインストールした後にpip
からpsycopg2
をインストールしましょう
# 公式からpython3.7 on alpine linuxイメージをpull
FROM python:3.7-alpine
# 作業ディレクトリを設定
WORKDIR /usr/src/app
# 環境変数を設定
# Pythonがpyc filesとdiscへ書き込むことを防ぐ
ENV PYTHONDONTWRITEBYTECODE 1
# Pythonが標準入出力をバッファリングすることを防ぐ
ENV PYTHONUNBUFFERED 1
# psycopg2のインストール
RUN apk update \
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
&& pip install psycopg2 \
&& apk del build-deps
# Pipenvをインストール
RUN pip install --upgrade pip \
&& pip install pipenv
# ホストのpipfileをコンテナの作業ディレクトリにコピー
COPY ./Pipfile /usr/src/app/Pipfile
# pipfileからパッケージをインストールしてDjango環境を構築
RUN pipenv install --skip-lock --system --dev
# ホストのカレントディレクトリ(現在はappディレクトリ)を作業ディレクトリにコピー
COPY . /usr/src/app/
先ほど起動していたコンテナ群をdocker-compose down -v
でいったん停止させて、再度docker-compose up -d --build
を入力してコンテナを再起動させましょう
-v
オプションはボリュームの削除を表します
<!-- コンテナの停止 -->
$ docker-compose down -v
<!-- コンテナの起動 -->
$ docker-compose up -d --build
<!-- マイグレーション -->
<!-- $ docker-compose exec <service_name> python manage.py migrate --noinput -->
$ docker-compose exec django python manage.py migrate --noinput
何度か同じ様なことをやっていると稀にDjangoとpostgresが接続されず、postgresコンテナが停止します
その際にはlogを確認してみましょう
おそらくpostgres_1 | initdb: directory "/var/lib/postgresql/data" exists but is not empty
の様な記載が確認できると思いますのでホスト側のdocker-demo-with-django/postgres_data
を削除してあげましょう
docker-compose ps
コマンドで以下の様に両方のコンテナが起動中(StateがUp)なことを確認します
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------
docker-demo-with-django_django_1 python manage.py runserver ... Up 0.0.0.0:8000->8000/tcp
docker-demo-with-django_postgres_1 docker-entrypoint.sh postgres Up 5432/tcp
次にデータベースに指定したデータベースが作成されていることも確認してください
$docker-compose exec postgres psql --username=django_db_user --dbname=django_db
psql (11.4)
Type "help" for help.
django_db=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------------+----------+------------+------------+-----------------------------------
django_db | django_db_user | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | django_db_user | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | django_db_user | UTF8 | en_US.utf8 | en_US.utf8 | =c/django_db_user +
| | | | | django_db_user=CTc/django_db_user
template1 | django_db_user | UTF8 | en_US.utf8 | en_US.utf8 | =c/django_db_user +
| | | | | django_db_user=CTc/django_db_user
(4 rows)
django_db=# \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------------+-------+----------------
public | auth_group | table | django_db_user
public | auth_group_permissions | table | django_db_user
public | auth_permission | table | django_db_user
public | auth_user | table | django_db_user
public | auth_user_groups | table | django_db_user
public | auth_user_user_permissions | table | django_db_user
public | django_admin_log | table | django_db_user
public | django_content_type | table | django_db_user
public | django_migrations | table | django_db_user
public | django_session | table | django_db_user
(10 rows)
django_db=# \q
確認できたら、postgresへの接続を確認した後にマイグレーションを自動で行うためにentrypoint.sh
をappディレクトリに追加します
#!/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
python manage.py flush --no-input
python manage.py migrate
exec "$@"
追加後にchmod +x app/entrypoint.sh
コマンドで実行権限を付与します
最後にentrypoint.sh
を実行するためにDockerfileを修正し、環境変数$DATABASE
を追加します
# 公式からpython3.7 on alpine linuxイメージをpull
FROM python:3.7-alpine
# 作業ディレクトリを設定
WORKDIR /usr/src/app
# 環境変数を設定
# Pythonがpyc filesとdiscへ書き込むことを防ぐ
ENV PYTHONDONTWRITEBYTECODE 1
# Pythonが標準入出力をバッファリングすることを防ぐ
ENV PYTHONUNBUFFERED 1
# psycopg2のインストール
RUN apk update \
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
&& pip install psycopg2 \
&& apk del build-deps
# Pipenvをインストール
RUN pip install --upgrade pip \
&& pip install pipenv
# ホストのpipfileをコンテナの作業ディレクトリにコピー
COPY ./Pipfile /usr/src/app/Pipfile
# pipfileからパッケージをインストールしてDjango環境を構築
RUN pipenv install --skip-lock --system --dev
# entrypoint.shをコピー
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh
# ホストのカレントディレクトリ(現在はappディレクトリ)を作業ディレクトリにコピー
COPY . /usr/src/app/
# entrypoint.shを実行
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
少し待って起動完了後にhttp://localhost:8000/に接続できれば完了です
ひとまずこれで個人開発環境は整いました
しかし本番環境の場合、環境変数を非公開にしなければいけません。また、python manage.py runserver
では機能が不足していたり、セキュリティ面で問題があるため別の方法でサーバーを起動させる必要もあります。
そのためにアプリケーションとWebサーバーのインターフェイスであるgunicorn
(WSGIサーバー)のインストールやenv_file
の設定、静的ファイルを処理するためにgunicorn
のリバースプロキシとして動作するnginx
の設定などを行わなければなりません
次はそれらを行なっていきます
Gunicornのインストールと本番用設定ファイルの作成
pipfileにgunicornを追記しましょう
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
django = "==2.2"
gunicorn= "==19.9.0"
[dev-packages]
[requires]
python_version = "3.7"
さらにdocker-compose.yml
と同じディレクトリにdocker-compose.prod.yml
を追記し、本番環境用の設定を記載します
version: '3.7'
services:
# サービス名は自由に設定
django:
# appディレクトリの中から`Dockerfile`を探す
build: ./app
# サービス起動後に入力されるコマンドを設定
command: gunicorn django_demo.wsgi:application --bind 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- ./app/:/usr/src/app/
# 開放するポートを指定。`host:container`でポートを記載
ports:
- 8000:8000
# 環境変数を指定
env_file: .env
# 接続するサービスを指定
depends_on:
- postgres
postgres:
# 公式からイメージをpull
image: postgres:11.4-alpine
# データベースの永続化
volumes:
- postgres_data:/var/lib/postgresql/data
env_file: .env.db
# トップレベルに書く「名前付きvolumes」は複数サービスから参照できる
volumes:
postgres_data:
開発環境の設定と比較するとenvironment:
がenv_file:
に変わっています。これにより本番環境用の設定を直接ymlに書かなくてよくなります
また、djangoサービスのcommand:
にgunicorn
の起動に関するコマンドを指定して、runserver
ではなくgunicorn
を起動させています
env_file
はdocker-compose.prod.yml
と同様のディレクトリに置いて、以下の様に記載しましょう
この際に、.env
のDEBAG=0
にするのを忘れない様にしましょう(DEBAG=0
でデバッグモードをオフ)
/docker-demo-with-django/.env
DEBUG=0
SECRET_KEY=hoge
DATABASE_ENGINE=django.db.backends.postgresql
DATABASE_DB=django_db
DATABASE_USER=django_db_user
DATABASE_PASSWORD=password1234
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE=postgres
/docker-demo-with-django/.env.db
POSTGRES_USER=django_db_user
POSTGRES_PASSWORD=password1234
POSTGRES_DB=django_db
加えて、現段階ではコンテナが起動するたびにmigrateが実行されてしまいますのでentrypoint.sh
も本番環境用にentrypoint.prod.sh
を作成しましょう
/docker-demo-with-django/app/entrypoint.prod.sh
#!/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も本番用のものを作成します
/docker-demo-with-django/app/Dockerfile.prod
# 公式からpython3.7 on alpine linuxイメージをpull
FROM python:3.7-alpine
# 作業ディレクトリを設定
WORKDIR /usr/src/app
# 環境変数を設定
# Pythonがpyc filesとdiscへ書き込むことを防ぐ
ENV PYTHONDONTWRITEBYTECODE 1
# Pythonが標準入出力をバッファリングすることを防ぐ
ENV PYTHONUNBUFFERED 1
# psycopg2のインストール
RUN apk update \
&& apk add --virtual build-deps gcc python3-dev musl-dev \
&& apk add postgresql-dev \
&& pip install psycopg2 \
&& apk del build-deps
# Pipenvをインストール
RUN pip install --upgrade pip \
&& pip install pipenv
# ホストのpipfileをコンテナの作業ディレクトリにコピー
COPY ./Pipfile /usr/src/app/Pipfile
# pipfileからパッケージをインストールしてDjango環境を構築
RUN pipenv install --skip-lock --system --dev
# entrypoint.shをコピー
COPY ./entrypoint.prod.sh /usr/src/app/entrypoint.prod.sh
# ホストのカレントディレクトリ(現在はappディレクトリ)を作業ディレクトリにコピー
COPY . /usr/src/app/
# entrypoint.shを実行
ENTRYPOINT ["/usr/src/app/entrypoint.prod.sh"]
当然、docker-compose.prod.yml
も本番用のファイルを読み込む様に書き換えます
version: '3.7'
services:
# サービス名は自由に設定
django:
build:
# 読み込むファイル名が`Dockerfile`ではない場合contextに相対パス、dockerfileにファイル名を記載
context: ./app
dockerfile: Dockerfile.prod
# サービス起動後に入力されるコマンドを設定
command: gunicorn django_demo.wsgi:application --bind 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- ./app/:/usr/src/app/
# 開放するポートを指定。`host:container`でポートを記載
ports:
- 8000:8000
# 環境変数を指定
env_file: .env
# 接続するサービスを指定
depends_on:
- postgres
postgres:
# 公式からイメージをpull
image: postgres:11.4-alpine
# データベースの永続化
volumes:
- postgres_data:/var/lib/postgresql/data
env_file: .env.db
# トップレベルに書く「名前付きvolumes」は複数サービスから参照できる
volumes:
postgres_data:
設定が終わったら再度コンテナを起動させてみましょう
$ docker-compose down -v
<!-- -fオプションでdocker-compose.prod.ymlを指定 -->
$ docker-compose -f docker-compose.prod.yml up -d --build
<!-- entrypoint.prod.shではmigrateをしていないので手動で実行 -->
$ docker-compose -f docker-compose.prod.yml exec django python manage.py migrate --noinput
起動したらhttp://localhost:8000/adminにアクセスしてみましょう
接続されてdjangoの管理用のログイン画面が表示されると思いますが、静的ファイル(CSS等)が表示されていないはずです
これはデバッグモードをオフにしたため静的ファイルが読み込まれなくなっています
また、設定通りGunicornが起動しましたがGunicorn静的ファイルの配信に対応しておらずアプリケーション(今回であればdjango)を提供するだけですので、上記2つの設定を修正しなければ静的ファイルの配信はできません
具体的にはpython manage.py collectstatic
で静的ファイルを1箇所に集めてそれを読み込む様にすることと、nginxなどのwebサーバーをgunicornのリバースプロキシとして利用することです
まずはnginxをサービスに追加しましょう
nginxを追加
プロジェクトのルート(/docker-demo-with-django/
)にnginxディレクトリを作成し、その中にDockerfile
とnginx.conf
を追加します
/docker-demo-with-django/nginx/Dockerfile
FROM nginx:1.15.12-alpine
# デフォルトのconfを消して、別の設定を追加
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d
/docker-demo-with-django/nginx/nginx.conf
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;
}
}
それからdocker-compose.prod.yml
にnginxを追記します
version: '3.7'
services:
# サービス名は自由に設定
django:
build:
# 読み込むファイル名が`Dockerfile`ではない場合contextに相対パス、dockerfileにファイル名を記載
context: ./app
dockerfile: Dockerfile.prod
# サービス起動後に入力されるコマンドを設定
command: gunicorn django_demo.wsgi:application --bind 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- ./app/:/usr/src/app/
# 指定されたポートは接続されたサービスからアクセス可能
expose:
- 8000
# 環境変数を指定
env_file: .env
# 接続するサービスを指定
depends_on:
- postgres
postgres:
# 公式からイメージをpull
image: postgres:11.4-alpine
# データベースの永続化
volumes:
- postgres_data:/var/lib/postgresql/data
env_file: .env.db
nginx:
build: ./nginx
ports:
- 1337:80
depends_on:
- django
# トップレベルに書く「名前付きvolumes」は複数サービスから参照できる
volumes:
postgres_data:
djangoサービスにホストOSから直接リクエストすることはなくなるのでports:
をexpose:
に変えましょう
これで指定されたポートはホストOSには公開されませんが、リンクされたサービスからは接続できる様になります
先ほどと同様にサービスを再起動します
$ docker-compose -f docker-compose.prod.yml down -v
$ docker-compose -f docker-compose.prod.yml up -d --build
$ docker-compose -f docker-compose.prod.yml exec djnago python manage.py migrate --noinput
http://localhost:1337/admin/に接続してみましょう。管理画面が表示されるはずです
これでnginxとの接続が完了しました。現段階でのディレクトリ構成は以下の通りです
$tree
.
├── app
│ ├── Dockerfile
│ ├── Dockerfile.prod
│ ├── Pipfile
│ ├── Pipfile.lock
│ ├── django_demo
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── entrypoint.prod.sh
│ ├── entrypoint.sh
│ └── manage.py
├── docker-compose.prod.yml
├── docker-compose.yml
└── nginx
├── Dockerfile
└── nginx.conf
静的ファイルの処理
次に静的ファイルを処理する設定です。djangoプロジェクトのsetting.py
を末尾を修正し、entrypoint.sh
に追記します
/docker-demo-with-django/app/django_demo/settings.py
STATIC_URL = '/staticfiles/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
/docker-demo-with-django/app/entrypoint.sh
#!/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
python manage.py flush --no-input
python manage.py migrate
python manage.py collectstatic --no-input --clear
exec "$@"
これでpython manage.py collectstatic
によって静的ファイルがSTATIC_ROOTで指定したパスに集められ、さらにそこにstaticfiles
ディレクトリに存在する静的ファイルを配信する様になります
次に、docker-compose.prod.yml
のdjangoとnginxのボリュームに同じものを設定し、nginxコンテナにdjangoプロジェクトを接続したのちに静的ファイルのリクエストをstaticfiles
ディレクトリにルーティングする様に設定しましょう
/docker-demo-with-django/docker-compose.prod.yml
version: '3.7'
services:
# サービス名は自由に設定
django:
build:
# 読み込むファイル名が`Dockerfile`ではない場合contextに相対パス、dockerfileにファイル名を記載
context: ./app
dockerfile: Dockerfile.prod
# サービス起動後に入力されるコマンドを設定
command: gunicorn django_demo.wsgi:application --bind 0.0.0.0:8000
# データを永続化させる場合の設定。`host:container`でパスを記載
volumes:
- static_volume:/usr/src/app/staticfiles
# 指定されたポートは接続されたサービスからアクセス可能
expose:
- 8000
# 環境変数を指定
env_file: .env
# 接続するサービスを指定
depends_on:
- postgres
postgres:
# 公式からイメージをpull
image: postgres:11.4-alpine
# データベースの永続化
volumes:
- postgres_data:/var/lib/postgresql/data
env_file: .env.db
nginx:
build: ./nginx
volumes:
- static_volume:/usr/src/app/staticfiles
ports:
- 1337:80
depends_on:
- django
# トップレベルに書く「名前付きvolumes」は複数サービスから参照できる
volumes:
postgres_data:
static_volume:
/docker-demo-with-django/nginx/nginx.conf
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;
}
# 静的ファイルの要求をstaticfilesにルーティング
location /staticfiles/ {
alias /usr/src/app/staticfiles/;
}
}
これですべての設定が完了しました!
改めてコンテナを起動してみましょう!
$ docker-compose -f docker-compose.prod.yml down -v
$ docker-compose -f docker-compose.prod.yml up -d --build
$ docker-compose -f docker-compose.prod.yml exec django python manage.py migrate --noinput
$ docker-compose -f docker-compose.prod.yml exec django python manage.py collectstatic --no-input --clear
起動を確認したらhttp://localhost:1337/adminに接続してみてください。管理画面にCSSが設定されているはずです!あとはお好きな様にDjangoプロジェクトを改修してください!
お疲れ様でした!!