Docker-composeを使用したDjangoの開発環境構築(個人的備忘録)

##はじめに
データベースサーバには「postgres」環境構築に主眼を置いているため、pythonやDjangoに精通している必要はない。プロジェクトを開始するにあたり、任意の場所に作業ディレクトリを作成する。docker-composeを使用する場合、docker-compose.ymlファイルが置いてあるディレクトリ名が、コンテナ名やボリューム名の接頭辞として使用されるため、実際の環境においてはプロジェクト名などの**意味のあるディレクトリ名**を作成する。
##ディレクトリの作成
```haml
-# djangoというディレクトリの作成
% mkdir django
-# djangoディレクトリに移動
% cd django
```
djangoディレクトリをビルドコンテキストにするため不要なファイルは含めないようにする。
##Pythonの実行環境のイメージを作成するためのDockerfileを作成する。
```dockerfile
% vim Dockerfile
```
```dockerfile:Dockerfile
# python3の実行環境のイメージを指定
FROM python:3
# PYTHONUNBUFFEREDという環境変数に1を指定。この環境変数に何かしら設定しておくとバッファーを無効化できる。
ENV PYTHONUNBUFFERED 1
# codeディレクトリを作成
RUN mkdir /code
# 作業ディレクトリをcodeディレクトリに移動            
WORKDIR /code
# ビルドコンテキスト上にあるrequirements.txtをcodeディレクトリ内に置く
COPY requirements.txt /code/
# pipインストールを実行している。pipはpythonのパッケージツールで、
# -rで指定したrequirements.txtに記載されているパッケージのインストールを実行する。
# requirements.txtは、ビルドコンテキスト内に作成するがdjangoとPostgresのドライバーのパッケージ名を記述する。
RUN pip install -r requirements.txt
# ビルドコンテキストの内容を全て/code内に置いている。
COPY . /code/
```

##requirements.txtの作成
```haml
% vim requirements.txt
-# version2.0のDjangoのインストール
Django==2.0
-#pythonでpostgresに接続するためのドライバー
psycopg2
```

##docker-compose.ymlの作成
```docker:docker-compose.yml
version: '3'
services: 
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000 
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
```
**services** には「db」と「web」の2つのコンテナが起動する想定。
**web** にはbuildにドットが定義されているので先ほど定義したDockerfileからイメージをbuildして使用する。dbには「postgres」SQLのイメージを使用。
**command** はコンテナ起動時に実行されるコマンドを意味している。ここでは「python3」で「manage.py」を実行し、引数に開発用の軽量のサーバを立ち上げる「runserver」とリッスンするIPアドレス、ポート番号を指定している。「manage.py」はDjangoをインストールすると自動で生成されるファイル。しかし、ここに記載したコマンドは、コンテナ実行時にコマンドが渡された場合に上書きされる。そのため引数にコマンドを渡さなかった場合にdocker-composeのコマンドが実行される。
**valunes** はカレントディレクトリを/codeにバインドマウントしている。
**ports** は8000番で公開して、コンテナの8000番に転送されるように指定。転送先のポート番号は「runserver」のポート番号を合わせる必要がある。
**depends_on**「web」サービスを起動する前に「db」サービスが起動するように依存関係を定義する。

##Djangoプロジェクトの作成
```
% docker -compose run web django-admin.py startproject examplepj .
```
docker-compose runの引数にはymlに定義した「web」サービスを指定。以降はwebサービスのコンテナ起動時に実行するコマンド。django-admin.pyもDjangoのインストールによって作成されるもの。ここではdjango-admin.pyを実行して、「startproject」でdjangoのプロジェクトを作成している。プロジェクト名はexamplepjで保存先をカレントディレクトリにしている。カレントディレクトリはDockerfileで指定した/codeディレクトリになる。

```
% ls -l
```
現在のカレントディレクトリとコンテナの/codeディレクトリがバインドマウントされてことが確認できる。

##データベースの設定を記述して開発用のwebサーバを起動する。
```docker
% vim examplepj/settings.py
```
```py:settings.py
ALLOWED_HOSTS = ['*']

----省略----

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql', #ENGINEにpostgresqlを指定
        'NAME': 'postgres',                        #postgresの指定
        'USER': 'postgres',                        #postgresの指定
	'PASSWORD': 'password',
        'HOST': 'db',                              #docker-composeで立ち上げたコンテナはサービス名で名前解決を行うことができるのでHOSTの指定はdbとすることができる。
        'PORT': 5432,                              #postgresqlのデフォルトの5432番ポートを指定
    }
}
```

##各サービスの起動
```
% docker-compose up -d
Starting django_db_1 ... done
Creating django_web_1 ... done
```
Ip:8000で接続されていることが確認できる。manage.pyなどの管理用のスクリプトを実行する場合はコンテナで実行しないと失敗する可能性があることに注意する。あくまでpythonの実行環境はコンテナに用意されているため、pythonのスクリプト実行自体はコンテナ内で実行する。

##Djangoのチュートリアルのpollsアプリケーション作成
```haml
-# pollsアプリケーションのファイルをプロジェクト内に作成
% docker-compose run web python3 manage.py startapp polls
-# views.pyページの変更
% vim polls/views.py
```
```py:views.py
from django.http import HttpResponse

# Create your views here.
def index(request):
  return HttpResponse("Hello, world. You're at the polls index.")
```
これで「polls」というURLにアクセスが来た場合に表示されるメッセージを定義。

##polls.indexのルート設定
```
% vim polls/urls.py
```
```py:urls.py
from django.urls import path

from . import views

urlpatterns = [
  path('', views.index, name='index'),
]
```
作成したindexメソッドの結果を表示することを定義している。

##作成したurls.pyをメインのurls.pyから読み込むように設定する。
```
% vim examplepj/urls.py
```
```py:urls.py
urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]
```
これでip:8000/polls/でindexページが表示される。このようにソースコードを追加することでコンテナでdjangoを動作させながら、開発を進めることができる。

##コンテナの停止
```
% docker-compose stop
```