ゴミアプリケーションをコンテナに乗っけてみた

# はじめに

どうも、年末暇人の新人SEです。数ヶ月前に暇すぎてDjangoアプリケーションを勉強として作成したのですが、それを記事にするには題材がしょぼすぎると思ったのでDockerを使ってコンテナに乗っけて動かしてみました。作ったアプリケーションがしょぼいことは自覚してるので触れないでね！

# 環境

- Mac OS Catalina 10.15.1
- Docker 19.03.5

# Djangoアプリケーションについて

まずはアプリケーションについて説明します。今回題材として使用するのは、以前僕が作成したサブスクリプションサービスの管理アプリケーションです。利用しているサービスと月額金額を登録するとその時点から現在までの累計課金額を計算できるようになっています。（できるのはそれだけです。。。）

<img width="1280" alt="スクリーンショット 2019-12-27 18.03.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507052/ec0a9879-33c5-4dfb-bf3d-002812252faf.png">

どんだけゴミなのか見てみたいよ！という方は以下のリンクからご覧ください。README.mdとかは書いてないから頑張って動かして！笑

[Djangoアプリケーション](https://github.com/Yoshiaki-Kanazawa/SubscManagement)

この記事ではすでに作成済みのDjangoアプリケーションをコンテナ環境に移植するということをやっていきます。

# コンテナの構成

コンテナの構成は以下の通りです。AP用とDB用で２つのコンテナを作成します。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507052/76b4d876-ccd0-4723-2cb7-c12b37d50837.png)

# ディレクトリ構成

ディレクトリ構成は以下の通り。

```
.
├── Dockerfile_db
├── Dockerfile_django
├── README.md
├── app
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── env
│   │   ├── bin
│   │   ├── include
│   │   ├── lib
│   │   ├── pyvenv.cfg
│   │   └── src
│   ├── manage.py
│   ├── management
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── __pycache__
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── apps.pyc
│   │   ├── forms.py
│   │   ├── migrations
│   │   ├── models.py
│   │   ├── models.pyc
│   │   ├── templates
│   │   ├── tests.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── static
│   │   ├── addService_style.css
│   │   ├── detail_style.css
│   │   ├── header_style.css
│   │   ├── login_style.css
│   │   ├── logout_style.css
│   │   ├── management_style.css
│   │   ├── password_change_done_style.css
│   │   ├── password_change_style.css
│   │   └── signup_style.css
│   ├── subscManagement
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── __pycache__
│   │   ├── settings.py
│   │   ├── settings.pyc
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── templates
│       └── registration
├── docker-compose.yml
└── requirements.txt
```

# AP用コンテナのDockerfile

AP用コンテナを作成するためのDockerfileを作成します。

```dockerfile:Dockerfile_django
FROM python:3
ENV LANG en_US.utf8
WORKDIR /app
ADD requirements.txt /app
RUN apt-get update
RUN pip install -r requirements.txt
```
```text:requirements.txt
Django==2.2.5
mysqlclient==1.4.4
```

今回はMySQLへの接続ドライバとしてmysqlclientを使っていますが、後述のMySQLイメージのバージョン（Tag）がmysql:8だとうまくいきませんでした。今回はダウングレードしてmysql:5.7を使用しています。

# DB用コンテナのDockerfile

DB用コンテナを作成するためのDockerfileを作成します。

```dockerfile:Dockerfile_db
FROM mysql:5.7
RUN apt-get clean && apt-get update && apt-get install -y locales locales-all
RUN locale-gen ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:en
ENV LC_ALL ja_JP.UTF-8
RUN ln -sf /usr/share/zoneinfo/Japan /etc/localtime
```

文字コードの設定は適当です。

# docker-compose.ymlの作成

docker-compose.ymlを作成します。

```yml:docker-compose.yml
version: '3'

services:
    db:
        build:
            context: .
            dockerfile: Dockerfile_db
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_USER: apuser
            MYSQL_PASSWORD: password
            MYSQL_DATABASE: subscManagement
            TZ: "Asia/Tokyo"
            BIND-ADDRESS: 0.0.0.0
        ports:
            - 3306:3306
        volumes:
            - db_data:/var/lib/mysql
        tty: true

    django:
        build:
            context: .
            dockerfile: Dockerfile_django
        command: python3 manage.py runserver 0.0.0.0:8000
        ports:
            - "8000:8000"
        volumes:
            - ./app:/app
        tty: true
        depends_on:
            - db

volumes:
    db-data:
```

コンテナを削除してもDB内のデータが消えないようにvolumes:でボリュームを作成しています。

# コンテナを実行

以下のコマンドでdocker-compose.ymlを基にコンテナを実行します。

```shell
$ docker-compose up --build -d
```

コンテナがしっかり動いているかを確認！

```shell
$ docker-compose ps
          Name                        Command               State                 Ports              
-----------------------------------------------------------------------------------------------------
subscmanagement_db_1       docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp
subscmanagement_django_1   python3 manage.py runserve ...   Up      0.0.0.0:8000->8000/tcp 
```

初回実行時のみDBへのテーブル作成のためにDjango側コンテナ内で以下のコマンドを実行する必要があります。

```shell
# "docker exec -it コンテナ名 /bin/bash"等でコンテナ内に入ってから実行
$ python manage.py migrate
```

# Webページにアクセス

ブラウザからWebページにアクセスできるかどうか確認します。
http://0.0.0.0:8000/accounts/login/
にアクセス！

<img width="1280" alt="スクリーンショット 2019-12-27 18.19.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507052/8f1fc011-dbc8-9907-acd5-c16e2c092b10.png">

アクセスに成功しました！アカウントを作成してログインし、データを入力するとしっかり保存されたのでDBへの保存もうまくいっているようです！

<img width="1280" alt="スクリーンショット 2019-12-27 18.21.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507052/66af744e-c68e-850e-2701-a965b173f2ef.png">

ちなみに一度コンテナを削除してからもう一度作ってもデータは残っていたので、永続的なデータの保存にも成功しました！

# 最後に

今回初めてコンテナを触りましたがコンテナ間（Django側からMySQL側）の接続に苦労しました。DBへの接続ドライバとMySQLイメージのバージョン（Tag）の組み合わせによってはうまく接続することができないようです。これはMySQL:8から導入された新たな認証機能に接続ドライバが対応していない場合があるために起っているようです。コンテナ2つでも結構苦労したので、複雑なシステムのコンテナ化はかなり難しそう。。。