Docker-composeを使用した Django + uWSGI + Nginx + MySQL ローカル開発環境の構築

# Djangoローカル開発環境の構築
DjangoとMySQLとNginxを使用してそれぞれのコンテナを作成します。
Nginxでリクエストを受け取りuWSGIでDjangoへ接続。
Djangoで使用するDBをMySQLとする構成です。

Docker-composeを使用してまとめます。

## ディレクトリ構成

最初のディレクトリ構成は以下の通りです。
それぞれディレクトリで分けてそれぞれのDockerfileを作成します。
後でDjangoプロジェクトを作成するのでアプリケーションのディレクトリが追加されます。

```bash:directory-struct
<work-dir>
  docker-compose.yml
  mysql/
    Dockerfile
    my.cnf
    data/
    sql/
      init.sql
  nginx/
    Dockerfile
    nginx.conf
  python/
    Dockerfile
    requirements.txt
    uwsgi.ini
```

## ファイルの中

### docker-compose

```docker-compose.yml
version: "3"
services:
  pythonapp:
    build: ./python
    volumes:
      - ./python:/var/www
    links:
      - mysql
    ports:
      - "3031:3031"
      - "8000:8000"
    environment:
      TZ: "Asia/Tokyo"
    
  mysql:
    build: ./mysql
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/sql:/docker-entrypoint-initdb.d
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    ports:
      - "3306:3306"
    environment:
      TZ: "Asia/Tokyo"
      MYSQL_ROOT_PASSWORD: "{root-password}"

  nginx:
    build: ./nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    links:
      - pythonapp
    ports:
      - "4231:80"
    environment:
      TZ: "Asia/Tokyo"
```

### MySQL

MySQLは日本語化の為にUTF-8にしています。

```Dockerfile:mysql/Dockerfile
FROM mysql:5.7

CMD ["mysqld"]
```
```conf:mysql/my.cnf
[mysqld]
character-set-server=utf8
max_allowed_packet=1G

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8
```

init.sqlでDjangoで使用するDBと接続用のユーザーを作成します。

```sql:init.sql
CREATE DATABASE IF NOT EXISTS {db-name} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS '{user-name}'@'%' IDENTIFIED BY '{password}';
GRANT ALL PRIVILEGES ON {db-name}.* TO '{user-name}'@'%';

FLUSH PRIVILEGES;
```

### Nginx

3031番ポートを使用してuWSGI経由でDjangoに接続します。

```Dockerfile:nginx/Dockerfile
FROM nginx:1.17.3
CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
```

```nginx/nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;

    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;

    #gzip  on;

    upstream uwsgi {
        server pythonapp:3031;
    }

    server {
        listen 80;
        charset utf-8;

        location / {
            include uwsgi_params;
            uwsgi_pass uwsgi;
        }
    }
}
```

### Django

MySQLへの接続にはMySQLClientを使用します。
Djangoが推奨していたはず。PyMySQLは使用できなくなった（？）。

```Dockerfile:python/Dockerfile
FROM python:3.7.4

RUN mkdir -p /var/www

WORKDIR /var/www

COPY requirements.txt ./

RUN pip install -U pip setuptools && \
    pip install --no-cache-dir -r requirements.txt

WORKDIR /var/www/{work-dir}

CMD ["uwsgi", "--ini", "/var/www/uwsgi.ini"]
#CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
```
```requirements:python/requirements.txt
Django==2.2.5
mysqlclient==1.4.4
uWSGI==2.0.18
```

{project-name}は任意ですが後でDjangoで作成するプロジェクト名と一致させておく必要があります。

```python/uwsgi.ini
[uwsgi]

chdir = /var/www/{project-name}
module = {project-name}.wsgi:application

master = true
vacuum = true

processes = 1
socket = :3031
chmod-socket = 666
die-on-term = true
py-autoreload = 1

# ログの設定
# logto = /dev/stdout #default#
#logto = /var/www/uwsgi.log
```

## Django project 作成

### プロジェクトの作成。

同じ名前のディレクトリが再帰的に2つ作られます。

```bash:console
$ docker-compose run pythonapp django-admin startproject {project-name} ./
```

### MySQLを使用するので設定を書き換える
settings のDB設定にMySQLへの接続情報を記載する

```py:python/{project-name}/{project-name}/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
```

↓

```py:python/{project-name}/{project-name}/settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '{db-name}',
        'USER': '{user-name}',
        'PASSWORD': '{password}',
        'HOST': 'mysql',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
            'sql_mode': 'TRADITIONAL,NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY',
        },
    },
}

```

### MySQLにマイグレーション

```console:console
$ docker-compose run pythonapp python manage.py makemigrations
$ docker-compose run pythonapp python manage.py migrate
```