LoginSignup
249
242

More than 3 years have passed since last update.

DockerでDjangoの開発環境を構築!(Docker-compose/Django/postgreSQL/nginx)

Last updated at Posted at 2020-01-31

再構築してみました!
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_filedocker-compose.prod.ymlと同様のディレクトリに置いて、以下の様に記載しましょう

この際に、.envDEBAG=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ディレクトリを作成し、その中にDockerfilenginx.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プロジェクトを改修してください!

お疲れ様でした!!

249
242
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
249
242