Django の開発環境の Dockerfile を作成してみた

# はじめに
Python のフレームワークである Django のアプリケーションを用いて Dockerfile を作成してみた備忘録です。

# 事前準備

事前準備として Docker の image と container は空の状態からスタートします。

```
$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

$docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS                  NAMES
```

# Django プロジェクトの作成

今回は[こちらの記事](https://qiita.com/sugurutakahashi12345/items/d4377a16c0e42cf48287)で作成した Django で作成したアプリを使用します。

記事を読まなくもよいように抑えておくべきことだけを説明すると、以下のコマンドを実行することでアプリが起動します。

```
$ python manage.py runserver
```

アプリが起動している状態で `http://localhost:8000/hello` にアクセスすると以下のような Hello World が表示される簡単なアプリです。

<img width="314" alt="スクリーンショット 2020-08-10 23.08.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259125/cf11644e-2cde-09f9-5fd5-e1978d80aa6d.png">


##  構造

以下に示したような構造になります。

[GitHub](https://github.com/suguruTakahashi-1234/django-sample) にも公開しております。

```Dockerfile:Dockerfile
$ tree
.
├── Dockerfile
├── requirements.txt
├── hello
│   └── （省略）
├── helloWorldProject
│   └── （省略）
├── README.md
├── db.sqlite3
└── manage.py
```

`Dockerfile` と `requirements.txt` は今回作成すべきファイルになるのでそちらについて解説します。


# Dockerfile の作成

今回は以下のように作成しました。

```Dockerfile:Dockerfile
# python:3.8の公式 image をベースの image として設定
FROM python:3.8

# 作業ディレクトリの作成
RUN mkdir /code

# 作業ディレクトリの設定
WORKDIR /code

# カレントディレクトリにある資産をコンテナ上の指定のディレクトリにコピーする
ADD . /code

# pipでrequirements.txtに指定されているパッケージを追加する
RUN pip install -r requirements.txt

# 起動（コンテナのポート8002番で受け付けるように起動する）
CMD python3 manage.py runserver 0.0.0.0:8002
```
今回のファイルの内容は以下のようになります。

- python:3.8の公式 image をベースにして、作業ディレクトリ（ `/code` ） を作成する
- 現在のソースを全てこのコンテナに写し換える
- 必要なモジュールを pip でインストールする
- コンテナ起動時にアプリケーションを起動するということが書かれております。

Dockerfile の書き方については説明を省略いたします。

`RUN` と `CMD` の違いは[こちらの記事](https://qiita.com/YusukeHigaki/items/044164837daa5e845d50)がわかりやすかったです。
（簡単に説明すると、`RUN` は build 中に実行されるコマンドで、`CMD` はコンテナ起動時に実行されるコマンドです。）

# requirements.txt の作成

Dockerfile で記述したように pip コマンドでインストールするモジュールは `requirements.txt` に記述するようにしました。

今回は Django が必要になるため、そちらを記述します。

```txt:requirements.txt
Django==3.1
```

今回のようにモジュールが一つの場合は外部ファイルにする必要はあまりないですが、インストールするモジュールが複数ある場合はこのように記載すると管理が楽です。

# Dockerfile から image の作成

Dockerfile を用意した後に `docker build -t [作成する image 名] [Dockerfileまでの相対パス]` コマンドを実行することで image が作成されます。

今回は `hello-world` という名前の image を作成します。

```
$ docker build -t hello-world .
（省略）
Successfully tagged hello-world:latest

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
hello-world         latest              6e2fc6616ab1        About a minute ago   922MB
python              3.8                 6feb119dd186        5 days ago           882MB
```

このように `hello-world` という image が作成されたことがわかります。
ついでに `python:3.8` の image も pull されて表示されます。

`SIZE` の項目をみると `python` よりも `hello-world` の方が大きいことから、元にした image に色々と追加されていることが伺えますね。

# コンテナの起動

image を作成したので、コンテナを起動させます。

```
$ docker container run -d -p 8001:8002 hello-world
$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ff92b40204f3        hello-world         "/bin/sh -c 'python3…"   About an hour ago   Up About an hour    0.0.0.0:8001->8002/tcp   funny_antonelli
```

`run` コマンドのオプションについて補足は以下の通りになります。

- `-d` ：バックグラウンドで起動する
- `-p` ：コンテナのポートを公開する

今回は `8001:8002`と指定しているので､「ホストの 8001 番ポート」と「コンテナの 8002 番ポート」を紐づけいているという意味になります。

（本来は 8001番 や 8002 番のポートは使用しませんが、ホストとコンテナのポート番号を意識するためにあえて変わった番号を用いております。）

`http://localhost:8001/hello` にアクセスすると以下のように表示されるはずです。
<img width="313" alt="スクリーンショット 2020-08-11 2.13.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259125/8a558a07-fdd4-60a0-a1ac-13c0f7265c3f.png">

# メリット
Dockerfile ファイルを記述することで、

『この Docker Image を pull してから、docker container run コマンドを実行した際は、必ず毎回、そのコンテナにログインして、このコマンドとこのコマンドを実行して〜（省略）』

などの手順書が

『 Dockerfile があるディレクトリで docker build -t [イメージ名] . コマンドを実行する。』

の1行で済むようになります。

例えば、今回のケースであれば Dockerfile の `FROM python:3.8` より下は全部手順書に示さなければなりません。

# まとめ
- Dockerfile を作成した
- Dockerfile から image を作成した
- 作成した image からコンテナを起動して挙動を確認した