Django開発備忘録：AWS 環境の ECS で実際に使用した本番用 Dockerfile を体系的にまとめてみた

## はじめに
まず、大前提として、ここから先は現在キャッチアップしているコンテナ関連の学習のために、ECR や ECS を活用しながら、さまざまなコードを書いていきます。

:::note alert
**※補足事項**
***そのため、内容は完全に自分向けとなっています。***
:::

また、このブログ投稿サイトは、自分自身の備忘録としても活用する予定です。***記録を積み重ねながら、メモを残していきます。***

## それぞれのソースコードはこちら

**ローカル開発用リポジトリ**

https://github.com/free-honda/reverse-proxy-django-dev

**ローカル開発の備忘録記事**

https://qiita.com/free-honda/items/57bd55b1f70348295a13

**本番 ECS 用リポジトリ**

https://github.com/free-honda/reverse-proxy-django-prd

**本番 ECS 用の備忘録記事**

https://qiita.com/free-honda/items/41f2b96ef57edc21c82a

https://qiita.com/free-honda/items/7e0a5a02dad7c3bdb981

現在、それぞれのリポジトリには README などの説明は記載していませんが、今後追加していく予定です。

## こんなシナリオのアプリ開発を想定

- **AWS ECS Fargate** を利用し、サーバーレスで Django アプリを運用  
- **Nginx をリバースプロキシ** として使用し、外部からのリクエストを適切に振り分け  
- **アプリのログを AWS CloudWatch Logs に集約** して監視  

**こんな感じ👇**

![Screenshot 2025-02-01 at 5.05.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/d1481a63-25ec-e41e-9d99-b5082ac32ea2.png)


## どのように動作するか？

この ECS タスクは **Django + Nginx のコンテナを Fargate** で動作させる構成になっています。

**リクエストの流れ**

```css
クライアント → Nginx → Django → Nginx → クライアント
　　　　　　　↘ CloudWatch Logs
```

**ポイント**

1. **Nginx（`nginx` コンテナ）** がポート `80` でリクエストを受ける。
2. Nginx がリクエストを **Django（`django` コンテナ）** に転送。
3. **Django** がリクエストを処理し、レスポンスを **Nginx** に返す。
4. **Nginx** が最終レスポンスをクライアントに送る。

**こんな感じ👇**

![Screenshot 2025-02-01 at 5.06.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/a838bfb4-1ae7-ccc4-632c-a43f3c911573.png)

**ログ管理**

- **Django** と **Nginx** のログは共に **CloudWatch Logs** に送信。
  - ロググループ: `/aws/ecs/reverse-proxy-cluster`

## この Dockerfile でできること

- Python 3.10 の環境を準備  
- Django アプリの依存パッケージをインストール  
- データベースのマイグレーションを適用  
- 静的ファイルを収集して適切な場所に配置  
- Gunicorn を使って Django アプリを 8000 番ポートで起動  

この `Dockerfile` を使えば、**Django アプリを Docker コンテナ内で簡単にデプロイ** できる構成になっています！ 

## 実際に使った Dockerfile（Django本番用）

この Dockerfile は、Django アプリケーションを Docker コンテナ内で動作させるためのものです。

```Dockerfile
FROM python:3.10

WORKDIR /app

COPY requirements.txt /app/

RUN pip install --upgrade pip && pip install -r requirements.txt

COPY . /app/

CMD ["sh", "-c", "python manage.py migrate && python manage.py collectstatic --noinput && gunicorn --bind 0.0.0.0:8000 mysite.wsgi:application"]
```

各ステップの処理を説明します。

### 1. Python の公式イメージを使用

```Dockerfile
FROM python:3.10
```

- **Python 3.10 の公式 Docker イメージ** を基にコンテナを構築  
- 必要な **Python 環境** を整備し、アプリケーションの動作をサポート  
- **依存関係の管理** も含め、環境を安定させる

**公式 Docker イメージ**

https://hub.docker.com/_/python

### 2. 作業ディレクトリの設定

```Dockerfile
WORKDIR /app
```

- コンテナ内の作業ディレクトリを **`/app`** に設定  
- 以降の **`COPY` や `RUN` コマンド** は `/app` ディレクトリ内で実行 

### 3. `requirements.txt` をコンテナにコピー

```Dockerfile
COPY requirements.txt /app/
```

- ホスト側（ローカル）の `requirements.txt` をコンテナの **`/app/`** にコピー  
- `requirements.txt` は **Python パッケージの依存関係** を記述したファイル  
- これにより、コンテナ内で必要なパッケージを適切にインストールできる  

### 4. 必要な Python パッケージをインストール

```Dockerfile
RUN pip install --upgrade pip && pip install -r requirements.txt
```

- `pip` を **最新バージョン** にアップグレード  
- `requirements.txt` に記載されたパッケージを `pip install` でインストール  

### 5. アプリケーションのコードをコンテナにコピー

```Dockerfile
COPY . /app/
```

- ホスト側（ローカル）の **アプリケーションコード** をコンテナの `/app/` にコピー  
- **Django プロジェクトのすべてのファイル** が `/app/` 内に配置される  

### 6. コンテナ起動時に実行するコマンド

```Dockerfile
CMD ["sh", "-c", "python manage.py migrate && python manage.py collectstatic --noinput && gunicorn --bind 0.0.0.0:8000 mysite.wsgi:application"]
```

- **コンテナが起動したときに実行する処理** を `CMD` で定義  
- `"sh", "-c", "..."` を使うことで **複数のコマンドを順番に実行** 可能 

### 実行されるコマンド
**データベースのマイグレーションを適用**

```sh
python manage.py migrate
```

- **データベースのスキーマを最新の状態** に更新  
- `manage.py migrate` を実行し、適用されていないマイグレーションを適用  

**静的ファイルの収集（`STATIC_ROOT`）**

```sh
python manage.py collectstatic --noinput
```

- **Django の静的ファイルを `STATIC_ROOT` に収集**  
- `collectstatic` コマンドを実行し、アプリの静的ファイルを指定ディレクトリに集約  
- `--noinput` オプションを指定することで、**確認プロンプトをスキップし、自動で処理を進める**

**Gunicorn で Django アプリを起動**

```sh
gunicorn --bind 0.0.0.0:8000 mysite.wsgi:application
```

- **Gunicorn（WSGI サーバー）を起動し、Django アプリを提供**  
- `--bind 0.0.0.0:8000` を指定し、**コンテナの 8000 番ポートで待機** 

## まとめ

基礎的な部分ではありますが、**Dockerfile 内でどのような処理が行われているのか** を詳しく振り返ることができました。

:::note info
***もしこの記事の内容が少しでも参考になれば嬉しく思います。***
:::

今後も同様の内容を継続して投稿していきますので、**温かく見守っていただけると嬉しいです！**