168
167

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DjangoをDocker Composeでupしよう!

Last updated at Posted at 2018-09-04

今更ながらDockerの勉強を始めました。
とりあえずプログラマのためのDocker教科書 第2版を読み終えたので力試しのトライです。
今回はnginx + (Gunicorn + Django) + PostgreSQLな構成で作成します。
本記事で使用しているコードはここにあるので気になった方は見てみてください。

##開発環境

  • macOS High Sierra 10.13.6
  • Docker for Mac
    • Engine : 18.06.1-ce
    • Compose : 1.22.0
  • Python : 3.7
  • Django : 2.1

##0.プロジェクトの雛形用意
今回のディレクトリの構成このようになっています。

docker-django
├── docker-compose.yml
├── django
│   ├── Dockerfile
│   ├── Dockerfile.base
│   ├── requirements.txt
│   └── requirements.base.txt
└── nginx
    ├── mime.types
    └── nginx.conf

コンテナ毎の設定ファイルをそれぞれのコンテナ名のディレクトリ下に配置しています。
例えばnginx用のコンテナに使用する設定ファイルはnginx/のフォルダに格納されています。

##1.Django+Gunicorn用のベースイメージを作成

はじめにDjangoプロジェクトをゴリゴリ開発するためのベースイメージを作成します。
このイメージの用途はdjangoのプロジェクト作成コマンド(django-admin startproject)を実行するときのコンテナに使ったり、後に作成するデプロイ用イメージのベースイメージとして使用します。

ベースイメージのDockerfileはこのようになります。

Dockerfile.base
FROM python:3.7

ENV APP_PATH /opt/apps

COPY requirements.base.txt $APP_PATH/
RUN pip install --no-cache-dir -r $APP_PATH/requirements.base.txt

WORKDIR $APP_PATH

また、requirements.base.txtの内容はこのようになっています。

requirements.base.txt
Django==2.1.11
gunicorn==19.9.0
psycopg2==2.7.5
psycopg2-binary==2.7.5

これをサクッとビルドしましょう。

$ docker build -t django2.1 -f ./django/Dockerfile.base ./django
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
django2.1           latest              c391e4c70e98        6 minutes ago       960MB
python              3.7                 825141134528        4 weeks ago         923MB

python:3.7のイメージをもとにdjango2.1:latestというイメージが作成されたのがわかります。

##2.Djangoプロジェクトのローカルへの作成
Djangoを使用できるイメージを作成したところで、
次はこのイメージを使ったコンテナからプロジェクトファイルを作成します。
ここでキモとなるのがコンテナ作成時にdocker-django/django/をmountオプションでバインドします。
こうすることで何が嬉しいかというとコンテナがあたかもvirtualenvのように扱えるのです!
早速次のコマンドを実行します。

$ cd django
$ docker run --rm \
--mount type=bind,src=$(pwd),dst=/opt/apps \
django2.1 \
django-admin startproject my_docker_project .

少しコマンドが長くなってしまいましたので改行をいれてあります。
一行ずつみていきましょう。
まずはDjangoプロジェクトを配置したい、./django/へカレントディレクトリを移動します。
次の行からコンテナの起動オプションです。
1行目の--rmはコマンドの実行が終えたらコンテナを削除するオプションです。
2行目の--mountはコンテナ起動時にマウントするホストディレクトリなどを設定します。今回はホストへの読み書きを許可するのでtypeはbind,srcはカレントディレクトリ,dstはコンテナ側のカレントディレクトリを指定します。
3行目にはコンテナのもととなるイメージを指定しています。
4行目がコンテナ内で実行されるコマンドです。今回はmy_docker_projectという名前のプロジェクトを作成しました。

実行後、djangoフォルダの中身をみてみると、

$ tree
.
├── Dockerfile
├── Dockerfile.base
├── manage.py
├── my_docker_project
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── requirements.base.txt
└── requirements.txt

Djangoのプロジェクトファイルがローカルに作成されています。素晴らしい!!
このようにDjangoのコマンドを使ってあれこれするときは、ホストをマウントしたコンテナで実行していきます。

ここまでできたらDjango関連は一旦おやすみです。

##3.docker-compose.ymlの作成と各コンテナ間の接続設定
Django+Gunicornな環境構築が落ち着いたところで、視点をコンテナの全体構成に向けます。
目標は、nginx + (Gunicorn + Django) + PostgreSQLな構成でした。
docker-compose.ymlは以下のようになります。

docker-compose.yml
version: '3.7'
services:
  django:
    restart: always
    build: ./django
    expose:
      - "3031"
    depends_on:
      - postgres
    command: bash -c "python manage.py migrate && gunicorn my_docker_project.wsgi -b 0.0.0.0:3031"
    volumes:
      - "staticdata:/opt/static/"
  nginx:
    restart: always
    image: nginx
    depends_on:
      - django
    ports:
      - "80:80"
    volumes:
      - "./nginx/:/etc/nginx/"
      - "staticdata:/opt/apps/static/"
  postgres:
    image: postgres
    ports:
      - "5432:5432"
    volumes:
      - "dbdata:/var/lib/postgresql/data"
    environment:
      POSTGRES_PASSWORD: hogemojahogemoja

volumes:
  dbdata:
  staticdata:

ここでは、
「DBのデータは永続化したい。」
「静的ファイルはnginxコンテナから配信したい。」
がキモになります。

#####「DBのデータは永続化したい。」 <=> 「コンテナ外部のボリュームを使いたい」
ので、docker-compose.ymlのトップレベルに dbdataというボリュームを宣言し、
それをコンテナにマウントしています。
#####「静的ファイルはnginxコンテナから配信したい。」 <=> 「コンテナ間でリソースを共有したい。」
ので、同じくトップレベルにstaticdataというボリュームを宣言し、
それをdjangoとnginx両方のコンテナにマウントしています。

###3-1.nginxコンテナの設定
今回の構成ではnginxで受け取ったリクエストを適宜Django(Gunicorn)に振り分けたり、静的ファイルを配信したりします。
さっそくconfファイルに書いていきましょう。

nginx.conf
http {
#~中略~
  include /etc/nginx/mime.types;
#~中略~
  upstream django_server {
    #docker-compose.ymlに記入したサーバ名、ポートを指定します。 #
    server django:3031 fail_timeout=0;
  }
    
  server {
#~中略~
    location /static/ {
            #先ほどしていた静的ファイルのボリュームのマウント先を指定します。#
      alias /opt/apps/static/;
    }
    
    location / {
      try_files $uri @proxy_to_django;
    }

    location @proxy_to_django {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_redirect off;
      proxy_pass http://django_server;
    }
#~中略~
  }
}

nginxコンテナの設定は以上です。
今回は最小の構成で、mime.typesはデフォルトのまま使用しています。

###3-2.djangoコンテナの設定とビルド用のDockerfile作成
docker-compose.ymlやnginx.confファイルの情報をもとにsettings.pyを編集していきます。

settings.py
#〜中略〜
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',  #作成時のデフォルト
        'USER': 'postgres',  #作成時のデフォルト
        'PASSWORD' : 'hogemojahogemoja', #作成時にdocker-compose.ymlで設定
        'HOST' : 'postgres', #コンテナのサーバ名
        'PORT' : 5432,
    }
}
#〜中略〜
STATIC_URL = '/static/'
STATIC_ROOT = '/opt/static' #ボリュームマウント先のパス
#〜中略〜

続いてDockerfileを編集していきます。

Dockerfile
FROM django2.1:latest

ENV APP_PATH /opt/apps

COPY . $APP_PATH/
RUN pip install --no-cache-dir -r $APP_PATH/requirements.txt

WORKDIR $APP_PATH
RUN python manage.py collectstatic --noinput

こちらのイメージは先ほどのベースイメージとは異なり、デプロイ用のイメージです。
プロジェクトで使用しているpythonライブラリをインストールしたり、配信用に静的ファイルをまとめたりしてます。

##4.Docker Composeでupする。
お疲れさまでした。
あとはupするだけです。

$ docker-compose up --build

各コンテナが立ち上がったあとlocalhostにアクセスすると…
スクリーンショット 2018-09-04 20.08.47.png
素晴らしい!!

スクリーンショット 2018-09-04 20.09.01.png
CSSもちゃんと効いてます!

5.終わりに

Dockerを触り始めて日が浅いですが
こんな風に各コンテナが協調して動いてるのが作れると脳汁出まくりでホント楽しいです。
今後もっと業務や趣味にDocker取り入れて行きたいです!!

168
167
5

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
168
167

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?