Python初学者向け：FlaskアプリとMySQLをDockerで作成するステップバイステップガイド

## はじめに

今回は、FlaskアプリケーションとMySQLデータベースをDockerコンテナを用いて構築し、データベースにデータを保存して表示するWebアプリケーションを作成します。

FlaskはPythonでのWebアプリケーション開発に適した軽量フレームワークであり、MySQLは一般的に使用されるリレーショナルデータベース管理システムです。

Dockerを使うことで、これらの環境を簡単に構築・管理できます。

この記事では、プロジェクトの構成から各ファイルの作成手順、さらにアプリケーションの動作確認までの手順を詳細に説明します。

## 知識整理

:::note
今回、必要な知識は以下になります。
**Docker**
Dockerは、アプリケーションとその依存関係をコンテナ化して、どの環境でも同じように動かせる仮想化技術です。開発環境と本番環境の整合性が取りやすくなります。

**Dockerfile**
Dockerfileは、Dockerイメージを作るための設定ファイルです。ベースイメージや依存パッケージのインストール、アプリの起動方法などを記述し、これをもとにイメージを作成します。

**Docker Compose**
Docker Composeは、複数のコンテナを一括で管理するツールです。docker-compose.ymlファイルを使い、複数のサービス（例：アプリとデータベース）の設定や連携を簡単に定義できます。

**Flask**
Flaskは、Pythonで書かれたシンプルで軽量なWebフレームワークです。小規模なアプリやAPIの構築に向いており、ルーティングやテンプレートエンジンの機能を提供します。

**MySQL**
MySQLは、広く使用されているリレーショナルデータベース管理システム（RDBMS）です。データの保存・検索・管理を行うのに適しており、Webアプリのバックエンドでよく使用されます。
:::

## プロジェクト構成
今回作成するFlaskアプリケーションとMySQLデータベースのディレクトリ構成は以下のとおりです。

```bash
/flask-app/
├── Dockerfile         # Flask用のDockerイメージを構築する設定ファイル
├── docker-compose.yml # FlaskとMySQLコンテナをまとめて管理する設定ファイル
├── requirements.txt   # FlaskなどのPythonライブラリの依存関係を記述
├── app.py             # Flaskアプリケーションのメインファイル
└── /templates/        # HTMLテンプレートを格納するディレクトリ
    └── index.html
```

## 各ファイルの作成手順

### 1. Dockerfileの作成
以下の内容でDockerfileを作成します。このファイルにより、Pythonベースのイメージを使用してFlaskアプリケーションを実行するコンテナを構築します。

```Dockerfile
# ベースイメージとして公式のPythonイメージを使用
FROM python:3.9-slim

# 作業ディレクトリを設定
WORKDIR /app

# 必要なパッケージをインストール
RUN apt-get update && apt-get install -y \
    build-essential \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# ローカルのrequirements.txtをコンテナにコピー
COPY requirements.txt .

# Pythonの依存関係をインストール
RUN pip install --no-cache-dir -r requirements.txt

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

# 環境変数の設定（Flaskアプリを起動するため）
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0

# コンテナのポート5000を公開
EXPOSE 5000

# Flaskアプリケーションを起動
CMD ["flask", "run"]
```

### 2. docker-compose.ymlの作成

FlaskアプリケーションとMySQLコンテナを定義するdocker-compose.ymlファイルを作成します。

```docker-compose.yml
version: '3'  # Docker Composeのバージョン

services:
  web:  # Flaskアプリケーション
    build: .  # Dockerfileからビルド
    ports:
      - "5001:5000"  # ホストの5001をコンテナの5000にマッピング
    environment:
      - FLASK_ENV=development  # デバッグモードを有効化
    depends_on:
      - db  # MySQLサービスに依存

  db:  # MySQLデータベース
    image: mysql:8.0  # MySQLの公式イメージを使用
    environment:
      MYSQL_ROOT_PASSWORD: password  # rootユーザーのパスワード
      MYSQL_DATABASE: flask_db  # 初期作成するデータベース名
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci      
    ports:
      - "3306:3306"  # MySQLのデフォルトポートをマッピング
    volumes:
      - db_data:/var/lib/mysql  # データ永続化

volumes:
  db_data:  # MySQLのデータを保持するボリューム
```

### 3. requirements.txtの作成
Flaskアプリケーションの依存関係を管理するrequirements.txtを作成します。FlaskとMySQL用のライブラリをインストールするため、以下の内容を記載します。

```requirements.txt
Flask==2.3.2
mysql-connector-python==8.0.33
```

### 4. app.pyの作成
Flaskアプリケーションのメインファイルapp.pyを作成し、以下の内容を記述します。このファイルでは、MySQLに接続し、データを挿入・取得して表示します。

```app.py
from flask import Flask, render_template, request, redirect  # Flaskアプリケーションに必要なモジュールをインポート
import mysql.connector  # MySQLデータベースに接続するためのモジュール

app = Flask(__name__)  # Flaskアプリケーションのインスタンスを作成

def get_db_connection():
    # MySQLデータベースへの接続を確立する関数
    return mysql.connector.connect(
        host='db',  # MySQLコンテナのホスト名（docker-compose.ymlのサービス名を指定）
        user='root',  # MySQLのユーザー名
        password='password',  # MySQLのパスワード
        database='flask_db'  # 接続するデータベース名
    )

@app.route('/')
def home():
    # ホームページを表示するルート
    connection = get_db_connection()  # データベース接続を取得
    cursor = connection.cursor()  # クエリを実行するためのカーソルを取得
    cursor.execute("SELECT message FROM greetings")  # greetingsテーブルからmessage列を取得
    messages = cursor.fetchall()  # 取得したメッセージをすべてリストで取得
    cursor.close()  # カーソルを閉じる
    connection.close()  # データベース接続を閉じる
    return render_template('index.html', messages=messages)  # messagesをテンプレートに渡してHTMLをレンダリング

@app.route('/add', methods=['POST'])
def add_message():
    # メッセージを追加する処理を行うルート（POSTリクエストを処理）
    message = request.form['message']  # フォームから送信されたメッセージを取得
    connection = get_db_connection()  # データベース接続を取得
    cursor = connection.cursor()  # クエリを実行するためのカーソルを取得
    cursor.execute("INSERT INTO greetings (message) VALUES (%s)", (message,))  # メッセージをgreetingsテーブルに挿入
    connection.commit()  # データベースに変更を反映
    cursor.close()  # カーソルを閉じる
    connection.close()  # データベース接続を閉じる
    return redirect('/')  # メッセージ追加後、ホームページにリダイレクト

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)  # アプリケーションをホスト0.0.0.0でポート5000番で実行（コンテナ内で利用）
```

### 5. templates/index.htmlの作成
HTMLテンプレートを保存するtemplatesディレクトリを作成し、その中にindex.htmlを配置します。以下はそのサンプルです。

```templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>今日もお疲れ様！！</title>
</head>
<body>
    <h1>今日は木曜日！明日行けば、華金ですね！！</h1>
    <form action="/add" method="post">
        <input type="text" name="message" placeholder="Enter your message" required>
        <button type="submit">Add Message</button>
    </form>
    <h2>Messages:</h2>
    <ul>
        {% for message in messages %}
        <li>{{ message[0] }}</li>
        {% endfor %}
    </ul>
</body>
</html>
```

### 6. MySQLテーブルの初期設定
MySQLにデータを挿入するために、まず greetings というテーブルを事前に作成する必要があります。以下の手順で設定を行います。

docker-composeでMySQLコンテナを起動します。

```bash
docker-compose up -d db
```

MySQLコンテナの画面は以下の通りです。

![スクリーンショット 2024-10-17 22.24.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/63447665-60d9-3533-ea3a-45ae8133f672.png)


MySQLコンテナに接続します。

```bash
docker exec -it flask-app-db-1 mysql -u root -p
```

本記事では、rootのパスワードを「password」として記述しています。問題なくMySQLコンテナに接続できました。

![スクリーンショット 2024-10-17 22.26.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/01c68fdb-2ed3-8d64-273c-f28e45de3819.png)

MySQLのコンソールで、以下のコマンドを実行してテーブルを作成します。

```sql
USE flask_db;
CREATE TABLE greetings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    message VARCHAR(255) NOT NULL
);
```

テーブルが正常に作成できていることを確認するために、SHOW コマンドを使用しました。

![スクリーンショット 2024-10-17 22.29.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/a1501b65-fc93-076b-2083-ca9a3029a143.png)

## Dockerのビルドと実行

プロジェクトの準備が整ったら、次にDockerイメージをビルドして、docker-composeでコンテナを起動します。以下のコマンドを実行してください。

```bash
# Dockerイメージをビルドし、コンテナを起動
docker-compose up --build
```

特にエラーなくコンテナが立ち上がっていることが確認できました。

:::note warn
注意点として、「docker-compose.yml」ファイルが存在する場所で上記コマンドを実行してください。
:::

![スクリーンショット 2024-10-17 22.31.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/dd7d33bc-462c-490f-dc7d-9c5b611a9164.png)



## アプリケーションの動作確認

FlaskとMySQLコンテナが起動したら、ブラウザで「http://localhost:5001」にアクセスします。

![スクリーンショット 2024-10-17 22.52.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/e41e4e84-0826-7842-9459-cc726ada0961.png)


Flaskのアプリログを確認すると、ページを取得した際にGETリクエストが記録され、メッセージを送信するとPOST処理が記録されていることが確認できました。

```bash
web-1  | 192.168.65.1 - - [17/Oct/2024 13:52:14] "GET / HTTP/1.1" 200 -
web-1  | 192.168.65.1 - - [17/Oct/2024 13:52:18] "POST /add HTTP/1.1" 302 -
web-1  | 192.168.65.1 - - [17/Oct/2024 13:52:18] "GET / HTTP/1.1" 200 -
web-1  | 192.168.65.1 - - [17/Oct/2024 13:52:22] "POST /add HTTP/1.1" 302 -
```

テキストボックスにメッセージを入力して送信すると、メッセージがMySQLに保存され、ページにも表示されていることが確認できました。

![スクリーンショット 2024-10-17 22.54.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/d46fb2f2-97cb-7b27-70b7-8749504151af.png)


## まとめ
今回の手順では、FlaskとMySQLをDockerを用いて効率的に連携させる方法を紹介しました。

Flaskはシンプルかつ柔軟なWebフレームワークであり、MySQLと組み合わせることでデータの永続的な保存や管理が可能です。また、Dockerを使うことで環境の構築と管理が容易になり、開発やテストをシームレスに進められます。

この構成を基に、さらなる機能の追加や他のAPI連携などを試みることで、Webアプリケーションのスキルを一層向上させることができるでしょう。

## 関連記事

https://qiita.com/free-honda/items/6273289e813eabcbd9d9