DockerでDjango環境を作成

# 概要
下記を満たす環境を作成してみます。

1. DockerでDjangoの実行環境を作成したい。
2. ソースコード(Django)はホスト(Windows10)に置いてあるファイルを参照したい。開発と確認が楽そうだから・・・
3. Nginxを用いてDjangoを動かしたい。

# 前提
ホスト(Windows10)には、Python、Django、Docker for Windowsがインストール済み。

・Python 　　　　　：　3.6.4
・Django 　　　　　：　2.0.3
・Docker 　　　　　：　18.03.1-ce, build 9ee9f40
・docker-compose　：　1.21.1, build 7641a569

# 手順
## 1. ホスト(Windows10)にDjangoプロジェクト作成
1. コマンドプロンプトで任意のフォルダに移動。
2. `django-admin startproject gyunyu` を実行する。

この段階では下記のような構成になっています。

```
gyunyu/・・・（１）
    ┣━ manage.py
    ┗━ gyunyu/
        ┣━ __init__.py
        ┣━ settings.py
        ┣━ urls.py
        ┗━ wsgi.py
```

（１）のフォルダ名は変更可能なので、`gyunyu` から `gyunyu_kanri` に変更。

```
gyunyu_kanri/
　┣━ mange.py
  ┗━ gyunyu/
    　┣━__init__.py
　　　・・・
```

## 2. 開発用サーバーの起動と確認
1. コマンドプロンプトで `gyunyu_kanri` フォルダ直下に移動。
2. `python manage.py runserver` を実行。
3. ブラウザで `http://127.0.0.1:8000/` にアクセスし、Djangoの画面（ロケットが離陸している画面）が表示される事を確認する。

## 3. アプリケーションの作成
1. コマンドプロンプトで `gyunyu_kanri` フォルダ直下に移動。
2. `python manage.py startapp coffee` を実行。

この段階で下記のような構成になっています。

```
gyunyu_kanri/
    ┣━ manage.py
    ┣━ gyunyu/
    ┃   ┣━ __pycache__
    ┃   ┃    ┗・・・
    ┃   ┣━ __init__.py
    ┃   ┣━ settings.py
    ┃   ┣━ urls.py
    ┃   ┗━ wsgi.py
    ┗━ coffee/
        ┣━ migrations
        ┃      ┗━ __init__.py
        ┣━ __init__.py
        ┣━ ・・・
        ┗━ views.py
```

## 4. Viewを作成

``` python:coffee/views.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
    return HttpResponse("Coffee Gyunyu !!!")
```

## 5. ViewとURLの紐づけと確認

1. `coffee/urls.py` を作成する。
2. `gyunyu/urls.py` を修正する。
3. ブラウザで `http://127.0.0.1:8000/coffee/` にアクセスし、4.で作成した画面「Coffee Gyunyu !!!」が表示される事を確認する。

```python:coffee/urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('', views.index)
]
```

```python:gyunyu/urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
    path('admin/', admin.site.urls),
    path('coffee/', include('coffee.urls'))
]
```

## 6. DockerでPythonの実行環境作成

下記のような構成になるように、`gyunyu_kanri` フォルダと同じ階層に `python` フォルダなどを作成。

```
/
┣━ gyunyu_kanri/
┃    ┗━ ・・・
┣━ python/
┃    ┣━ work/
┃    ┃   ┣━ requirements.txt
┃    ┃   ┗━ uwsgi.ini
┃    ┗━ Dockerfile
┗━ nginx/
     ┣━ work/
     ┃   ┗━ nginx.conf
     ┗━ Dockerfile
```

```text:python/Dockerfile
FROM python:3.6
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
RUN mkdir /home/work
COPY work/ /home/work
WORKDIR /home/work
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
CMD ["uwsgi", "--ini", "/home/work/uwsgi.ini"]
```

```text:python/work/requirements.txt
django==2.0.3
uwsgi==2.0.17.1
```

```text:python/work/uwsgi.ini
[uwsgi]
chdir=/home/work/gyunyu_kanri
module=gyunyu.wsgi
master=True
vacuum=True
max-requests=5000
socket=:8000
py-autoreload=1
```

**chdir** 　　： Djangoのプロジェクトを指定。
　　　　　　Docker Composeで `./gyunyu_kanri:/home/work/gyunyu_kanri` をボリュームに設定しています。
**module**　： `gyunyu` フォルダ直下にある `wsgi.py` を指定。

## 7. DockerでNginxのコンテナ作成

下記のような構成になるように、`gyunyu_kanri` フォルダと同じ階層に `nginx` フォルダなどを作成。

```
/
┣━ gyunyu_kanri/
┃    ┗━ ・・・
┣━ python/
┃    ┗━ ・・・
┗━ nginx/
     ┣━ work/
     ┃   ┗━ nginx.conf
     ┗━ Dockerfile
```

```text:nginx/Dockerfile
FROM nginx:1.13.1-alpine
COPY work/nginx.conf /etc/nginx
RUN apk --no-cache add tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    apk del tzdata
CMD ["nginx", "-g", "daemon off;"]
```

```text:nginx/work/nginx.conf
worker_processes auto;
error_log /var/log/nginx/error.log;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    server {
        listen       80 default_server;
        server_name  _;
        root         /home/www/localhost/htdocs;
        location ~ ^/admin|coffee/ {
            include uwsgi_params;
            uwsgi_pass 172.22.0.3:8000;
        }
    }
}
```

## 8. docker-compose.ymlを作成

`gyunyu_kanri` フォルダと同じ階層に `docker-compose.yml` を作成。

```
/
┣━ gyunyu_kanri/
┃    ┗━ ・・・
┣━ python/
┃    ┗━ ・・・
┣━ nginx/
┃    ┗━ ・・・
┗━ docker-compose.yml
```

```text:docker-compose.yml
version: '2'
services:
  gyunyu_kanri-nginx:
    build: "./nginx/"
    ports:
      - "80:80"
    networks:
      gyunyu_kanri-network:
        ipv4_address: 172.22.0.2
  gyunyu_kanri-python:
    build: "./python/"
    volumes:
      - ./gyunyu_kanri:/home/work/gyunyu_kanri
    ports:
      - "8000:8000"
    networks:
      gyunyu_kanri-network:
        ipv4_address: 172.22.0.3
networks:
  gyunyu_kanri-network:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.22.0.0/24
```

## 9. サービスの起動と確認

※Djangoの開発用サーバが動いている場合は停止させる。

1. コマンドプロンプトで gyunyu_kanri フォルダ直下に移動。
2. `docker-compose up --build -d` を実行。
3. ブラウザで `http://127.0.0.1/coffee/` にアクセスし、4.で作成した画面「Coffee Gyunyu !!!」が表示される事を確認する。

　・`Invalid HTTP_HOST header: 'IPアドレス'. You may need to add 'IPアドレス' to ALLOWED_HOSTS.`と表示された場合
　   　参考：https://www.deep-blog.jp/engineer/archives/4287/

# 最後に
勤務先の本番環境で運用する場合、オンプレミスな環境にコンテナを生成して運用することになると思います。
その場合、勤務先の業務フローに従うと、コンテナの上げ下げ手順を記載したドキュメントを作成、
その手順に沿ってインフラ担当者に作業を実施して貰う流れになってしまいます。
ソースコードを修正する度にインフラ担当のスケジュールを抑えて、手順書作成してと言う作業が煩わしかったので、
ソースコードはDockerイメージに含めず、ディレクトリをマウントする構成を試してみました。