個人的備忘録：FlaskとMySQLのDocker環境を一括シェルスクリプトで自動構築する方法まとめ

## はじめに

この記事では、FlaskアプリケーションをDocker上で構築し、MySQLと連携する開発環境を整える手順を紹介します。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

ディレクトリ構成から各ファイルの作成まで、すべてシェルスクリプトで自動化する方法も併せて解説します。

## ディレクトリ構成

```
/flask-app/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── app.py
└── /templates/
    └── index.html
```

## 1. Dockerfileの作成

Python公式の軽量イメージをベースに、Flaskアプリケーションを動かすためのDockerfileを作成します。

```Dockerfile
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/*

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["flask", "run"]
```

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

Docker Composeを用いて、Flaskアプリケーションの環境を定義します。ホスト側の5001番ポートを使用してコンテナの5000番ポートにアクセス可能にします。

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

services:
  web:
    build: .
    ports:
      - "5001:5000"
    environment:
      - FLASK_ENV=development
```

## 3. requirements.txtの作成

FlaskとMySQLとの接続に必要なライブラリを記載します。

```
Flask==2.3.2
mysql-connector-python==8.0.33
```

## 4. app.pyの作成

Flaskのエントリーポイントとなるapp.pyファイルを作成し、MySQLと接続してメッセージを挿入・表示する処理を記述します。

```python
from flask import Flask, render_template, request, redirect
import mysql.connector

app = Flask(__name__)

def get_db_connection():
    return mysql.connector.connect(
        host='YOUR_MYSQL_HOST',
        user='YOUR_USER',
        password='YOUR_PASSWORD',
        database='flask_db'
    )

@app.route('/')
def home():
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute("SELECT message FROM greetings")
    messages = cursor.fetchall()
    cursor.close()
    connection.close()
    return render_template('index.html', messages=messages)

@app.route('/add', methods=['POST'])
def add_message():
    message = request.form['message']
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute("INSERT INTO greetings (message) VALUES (%s)", (message,))
    connection.commit()
    cursor.close()
    connection.close()
    return redirect('/')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
```

YOUR_MYSQL_HOST, YOUR_USER, YOUR_PASSWORD は自身のMySQL環境に合わせて書き換えてください。

## 5. HTMLテンプレートの作成

templates/index.html には以下の内容を記述します。

```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. すべてを自動生成するシェルスクリプト

以下のスクリプトを使えば、上記のすべてのファイルを自動的に作成できます。

```.sh
#!/bin/bash

# Flaskアプリ用ディレクトリ作成
mkdir -p flask-app/templates
cd flask-app || exit

# Dockerfile作成
cat <<EOF > Dockerfile
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/*

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["flask", "run"]
EOF

# docker-compose.yml作成
cat <<EOF > docker-compose.yml
version: '3'

services:
  web:
    build: .
    ports:
      - "5001:5000"
    environment:
      - FLASK_ENV=development
EOF

# requirements.txt作成
cat <<EOF > requirements.txt
Flask==2.3.2
mysql-connector-python==8.0.33
EOF

# app.py作成
cat <<EOF > app.py
from flask import Flask, render_template, request, redirect
import mysql.connector

app = Flask(__name__)

def get_db_connection():
    return mysql.connector.connect(
        host='YOUR_MYSQL_HOST',
        user='YOUR_USER',
        password='YOUR_PASSWORD',
        database='flask_db'
    )

@app.route('/')
def home():
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute("SELECT message FROM greetings")
    messages = cursor.fetchall()
    cursor.close()
    connection.close()
    return render_template('index.html', messages=messages)

@app.route('/add', methods=['POST'])
def add_message():
    message = request.form['message']
    connection = get_db_connection()
    cursor = connection.cursor()
    cursor.execute("INSERT INTO greetings (message) VALUES (%s)", (message,))
    connection.commit()
    cursor.close()
    connection.close()
    return redirect('/')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
EOF

# templates/index.html作成
cat <<EOF > 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>
EOF

echo "Flaskアプリ用のファイル群を作成しました。"
```

## おわりに

Flaskを使った開発では、Docker環境を整えることで開発・本番環境の差異を減らすことができます。**さらに、MySQLなど外部サービスとの接続も含めた構成をシェルスクリプトで自動化することで、素早く再現性の高い開発環境を構築できます！**