[01] デフォルト環境 runserver + SQLite3 の構築

# はじめに

Docker (docker-compose)と Linux に標準で搭載されているシェルを組み合せて、
下記 [概要](#概要) に挙げた Django 環境を 1コマンドで即座に立ち上げるためのコードとその解説です. 

本記事の内容は、Zenn で[書籍](https://zenn.dev/robozushi10/books/3d32504b4b5707)として販売している内容と同一です.
Zenn でも書籍の内容は全て無料公開しています.

本記事に記したコード差分を適用していけば、動作するコードが完成するようになっております.
可能な限り注意を払って執筆しました.


# 概要

今回は下図・下表の環境を構築する. (重要な点は🔥である)
具体的には次の通り.
**・初期設定の Django を Docker を使って立ち上げる**
**・Django admin ページの管理者アカウントも作成する**

## 概念図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/d9fadee4-9a8c-95c6-5e8b-ec177042e1db.png)


## コンテナ内の構成

|項目|値|補足|
|:--|:--|:--|
|Python|バージョン3.8.3|`python:3.8.3-slim-buster` を使う|
|Django|バージョン3.0.7||
|アプリサーバ|runserver|8000番ポートを使用する|
|データベース|SQLite3||
|settings.py|デフォルト値のままとする|ホスト上の `./web/assets/settings.py` が、<br/>コンテナ内に `/usr/src/app/config/settings.py` <br/>として配置される.🔥|
|Django admin ページ🔥||Djangoシェルを自動実行して管理者アカウントを作成する🔥.<br/>管理者アカウントは次の通り.<br/>・アカウント「`admin`」<br/>・パスワード「`admin`」🔥|

# セットアップコード

## 全文

本記事のコードを作成してください.

:::message alert
web/assets/settings.py より、「DEBUG = True」のみセットアップできることを確認している.
:::

## ファイル構成

```bash
$ tree . --charset=c -a
.
|-- docker-compose.yml
|-- setupapp.sh ............. セットアップスクリプト
`-- web
    |-- Dockerfile
    `-- assets .............. コンテナへコピーされるデータ
        |-- entrypoint.sh
        `-- requirements.txt
```

## 解説

### ./docker-compose.yml

・Django アプリは `./web/app/ 以下` に作成していく.

```yaml
version: '3.7'
 
services:
  web:
    build: ./web
    image:  mydjango307
    container_name: mydjango307
    command: >
      bash -c 'python manage.py runserver 0.0.0.0:8000'
    volumes:
      - ./web/app/:/usr/src/app/
    ports:
      - 8000:8000
```

### ./setupapp.sh

・本スクリプトを実行するたびに環境を一掃してから、構築し直す.
・Django コンテナが起動したかの判定条件として manage.py の有無を使っている.
・下記中の🛑の処理で Django admin ページの管理者アカウントを作成している.

```bash
#!/bin/bash

# 旧データを削除する
sudo rm -rf web/app

# docker-compose.yml で書かれたサービスのコンテナ、イメージ、ネットワークを削除する
docker-compose down --rmi all --volumes

# 環境を削除が目的の場合は、下記「exit 0」を有効にする
# exit 0

# 必須ディレクトリを作成する
sudo mkdir -p web/app

# entrypoint.sh を配置する
sudo cp ./web/assets/entrypoint.sh ./web/app/

# Dockerイメージビルドを行う. 
docker-compose build

# Docker コンテナ起動を行う. 
docker-compose up -d

# 起動完了を待つ. (== entrypoint.sh の成功を待つ)
sleep 2

# manage.py が作成されていなければ Django のプロジェクト作成に失敗したとみなす
test ! -f ./web/app/manage.py && {
  echo "ERROR: Django のプロジェクト作成に失敗した"
  exit 2
}

# コンテナ内でのマイグレーション終了を待つ.
sleep 4

# 「Django管理サイト」の管理者アカウントを作成する. (ID「admin」, PW「admin」とする)
docker-compose exec web bash -c "python manage.py makemigrations"
docker-compose exec web bash -c "python manage.py migrate auth"
docker-compose exec web bash -c "python manage.py migrate"
# 🛑
docker-compose exec web bash -c "echo \"from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@example.com', 'admin')\" | python manage.py shell"

# runserver を再起動する
docker-compose restart web


```


### ./web/assets/entrypoint.sh

・コンテナ起動時に実行される処理である.

```bash
#!/bin/sh

# ./manage.py が存在しなければ初期セットアップ未とみなす
test ! -f manage.py && { 
  # プロジェクトを作成する (config/ と manage.py が作成される)
  django-admin.py startproject config .
  # マイグレーションを実施する
  python manage.py makemigrations
  python manage.py migrate
  # 物理ホストから config/. 以下を編集できるように権限を付与する
  chmod -R 777 config
}
exec "$@"

```

### ./web/assets/requirements.txt

・必須パッケージは 1つ目の「`django`」のみである.
・その他パッケージは使用頻度が高いので記述している.

```bash
django==3.0.7
django-extensions==2.2.9
django-filter==2.2.0
djangorestframework==3.11.0
```

### ./web/Dockerfile

```bash
FROM python:3.8.3-slim-buster 

## プロキシサーバを使う場合
# ENV http_proxy="http://proxy.co.jp:8080"	
# ENV https_proxy="http://proxy.co.jp:8080"

# コンテナ内に /usr/src/app を作成して且つ移動する
WORKDIR /usr/src/app
 
# Python に関する環境変数
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
 
# 時刻を日本に合わせる
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

# pip を更新したうえで必要なパッケージをインストールする
RUN pip install --upgrade pip==21.0.1
COPY assets/requirements.txt .
RUN pip install -r requirements.txt
 
# entrypoint.sh の中で 初回の処理 (startproject, マイグレーション) を実施する
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]
```

# セットアップ方法

次の通りコマンドを実行する.

```
$ ./setupapp.sh
```

# セットアップ後

## ファイル構成

```bash
$ tree . --charset=c 
.
|-- docker-compose.yml
|-- setupapp.sh
`-- web
    |-- Dockerfile
    |-- app
    |   |-- config
    |   |   |-- __init__.py
    |   |   |-- asgi.py
    |   |   |-- settings.py
    |   |   |-- urls.py
    |   |   `-- wsgi.py
    |   |-- db.sqlite3
    |   |-- entrypoint.sh
    |   `-- manage.py
    `-- assets
        |-- entrypoint.sh
        `-- requirements.txt
```

## 動作確認方法

次の点を確認すれば良い.

✔ Dockerコンテナが次のように起動していること

```bash
$ docker-compose ps
    Name                  Command               State            Ports         
-------------------------------------------------------------------------------
mydjango307    /usr/src/app/entrypoint.sh ...   Up      0.0.0.0:8000->8000/tcp 
```

<br/>

✔ http://localhost:8000 にアクセスして次の画面が表示されること.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/d3ec0713-6dfa-369a-d110-cd8dde62e68f.png)


<br/>

✔ http://localhost:8000/admin にアクセスして、アカウント「`admin`」、パスワード「`admin`」でログインできること.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/ccb608ea-fcd5-aa6a-f555-c8200d7337be.png)


<br/>

✔ ホスト上にファイル「`db.sqlite3`」が存在していること

```bash
./web/app/db.sqlite3
```

<br/>

以上.