Docker：Flask + Nginx + MySQL + phpMyAdminで環境構築

# この記事の目的
　以前、「Docker：Laravel9 + Nginx + MySQL + phpMyAdminで環境構築」というタイトルでLaravelのDocker環境構築を投稿しました。それ以来いろいろな言語でDockerでの環境構築にはまりました。

・以前の記事

https://qiita.com/MASEE/items/371582da884ae81ef3c1

　最近PythonのフレームワークであるFlaskの勉強を始めました。仮想環境を立ててFlaskをインストールする方法もあるのですが、せっかくなのでDockerで学習環境を構築してみたいと思い、備忘録として記事に残したいと思います。
（※Flaskは初めて使用するので、構築したFlaskのDocker環境に不備があるかもしれません。勉強し今後もこの記事をアップデートしていく予定です。）


# 構築するコンテナ
- Nginx
- Flask
- MySQL
- phpMyAdmin


# 構成
ディレクト、ファイルの構成は以下の通りです。
dockerディレクトリ直下にnginx、pythonのDockerfileを作成します。
pythonのバージョンは3.10.0を使用します。

MySQLとphpMyAdminのイメージはdocker Hubからプルしてきます。
コンテナ実行の定義は、docker-compose.ymlに記述します。

```
docker-flask
├── docker
│   ├── nginx
│   │   ├── Dockerfile
│   │   └── nginx.conf
│   └── php
│       ├── Dockerfile
│       └── requirements.txt
├── templates
│   └── index.html
├── static
│   ├── images
│   │   └── book.jpg <=これは好きな画像でOKです
│   └── css
│       └── style.css
├── app.py
└── docker-compose.yml
```

# Nginx関連のファイルを作成

・まずはNginxのDockertfileを作成します。
```dockerfile:Dockerfile
# コンテナベースとしてnginxを指定
FROM nginx:latest

# 次で作成するnginx.confファイルをDockerイメージにコピー
COPY nginx.conf /etc/nginx/conf.d/default.conf

# nginxをフォアグラウンドで動かすためデーモンをoff
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
```

・nginx.conf作成
```dockerfile:nginx.conf
server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

# Flask（Python）関連のファイル作成
・Dockertfileを作成します。
```dockerfile:Dockerfile
FROM python:3.10.0

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

# 次で作成するrequirements.txtをDockerイメージにコピー
COPY requirements.txt .

# requirements.txt内に記載したライブラリ群をインストール
RUN pip install -r requirements.txt

CMD ["gunicorn", "-b", ":5000", "app:app"]
```

・requirements.txt作成
```text:requirements.txt
Flask==2.3.2
gunicorn==20.0.4
sqlalchemy==2.0.15
```

requirements.txtにインストールするライブラリ群を記載しています。普段使っているLaravelでも利用できないか検討してみようと思いました。

いくつかの記事を参考にすると、「gunicorn（ジーユニコーン）」をインストールしていました。何なのか調べてみると、単純に考えるとNginxとFlaskの橋渡し役みたいです。

# docker-compose.ymlの作成
```docker:docker-compose.yml
version: '3.8'
services:
  nginx:
    build: ./docker/nginx/
    container_name: flask_nginx
    ports:
      - "80:80"
    depends_on:
      - python

  python:
    build: ./docker/python/
    container_name: flask_python
    volumes:
      - .:/code
    ports:
      - "5000:5000"
    depends_on:
      - db
  db:
    image: mysql:8.0
    container_name: flask_db
    hostname: mysql
    expose:
      - 3306
    ports:
      - 3306:3306
    command:
      - --sql-mode=NO_ENGINE_SUBSTITUTION
    environment:
      - MYSQL_ROOT_PASSWORD=flaskpass
      - MYSQL_DATABASE=flasktest
      - MYSQL_USER=flaskuser
      - MYSQL_PASSWORD=flaskpass

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: flask_pma
    hostname: phpmyadmin
    depends_on:
      - db
    ports:
      - "9090:80"
```

# コンテナ立ち上げ
起動用のapp.pyを作成します。

```python:app.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
@app.route("/index")
def index():
    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)
```
Webアプリケーションサーバであるgunicornを通してapp.pyを起動しますので、無いとエラーがでます。
templates/index.htmlは適当に用意してください。


docker-compose.ymlが存在するディレクトリに移動し、以下のコマンドを実行してdockerのイメージ作成、コンテナの立ち上げを行います。
一発で上手くいくかどうかの、この瞬間がいつも楽しみです。
（まあ大抵エラーが出ますが・・・）

```
$ docker-compose up -d
```
以下のような状態になれば、各コンテナが稼働しています。

```
Creating flask_db  ... done                               
Creating flask_pma  ... done                                    
Creating flask_python  ... done                                   
Creating flask_nginx  ... done  
```

# ページを整える

さてコンテナが立ち上がったのでさっそく画面を見てみましょう...　とその前にせっかくなので画面を少しきれいに整えましょう。

・templates/index.htmlを以下のように書き換えます。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="/static/css/style.css">
        <title>Flask学習テスト</title>
    </head>
    <body>
        <header>
            <h1>Flask学習テスト</h1>
        </header>
    
        <nav>
            <ul>
                <li><a href="#">ABOUT</a></li>
                <li><a href="#">MAIN</a></li>
                <li><a href="#">CONTACT</a></li>
            </ul>
        </nav>
    
        <main>
            <h2>メインコンテンツ</h2>
            <img src="/static/images/book.jpg" alt="">
        </main>
    
        <footer>
            <p>© 2023 Flask TEST</p>
        </footer>
    </body>
</html>
```

・static/css/style.css

```css:style.css
body {
    margin: 0;
    padding: 0;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
}

header, nav, main, footer {
    margin: 0;
    padding: 20px;
    color: white;
}

header {
    background-color: #ADD8E6;
}

nav {
    text-align: right;
    background-color: #4169e1;
}

nav ul {
    list-style-type: none;
    padding: 0;
}

nav ul li {
    display: inline;
    margin-right: 10px;
}

nav ul li a {
    color: white;
    text-decoration: none;
}

main {
    background-color: #ADD8E6;
}

img {
    width: 65%;
    height: 65%;
}

footer {
    text-align: center;
    background-color: #4169e1;
}
```

・static/images/ にはお好きな画像を入れてください。


# Flaskの起動
では、http://localhost:5000 に接続してみましょう。
以下のような画面がでればDocker環境構築完了です。

また、http://localhost:9090 にも接続してみましょう。
phpMyAdminの画面が出て、設定したユーザー名とパスワードを入力してログインできたら成功です。

![www.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661712/e6ba597c-be28-5cc9-9ccf-64445c7432cc.jpeg)


# 今後について
　今回はFlask学習のため、Dockerでの環境構築の例を紹介しました。画面表示まで確認できたので、今後はMySQLとの連携を試みたいと思います。