5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは!ITスクールRareTECHにてCS(Customer Support)を担当している池村です。今回の記事はDocker Composeの続きの記事になります。
連続した記事なので先に前回の記事を見ていただけますと幸いです。

複数コンテナの連携

早速本題です。前回までは単一のコンテナをComposeで動かすことを行いました。
ただ、やはりアプリを作るときはプログラムが動くコンテナ、データベースのコンテナなどを連携させたいと思います。⑥のネットワークの記事で二つのコンテナ間通信を実現していたわけですが、それをDocker Composeで実現したいと思います。

ではまず今回作成する環境のdocker-compose.ymlファイルの構成を見ていきましょう。

書き方
services:
  flask:
    build:
      context: .
    ports:
      - "5000:5000"
    volumes:
      - ./src:/app
    environment:
      FLASK_DEBUG: 1
    depends_on:
      - db

  db:
    image: mysql:latest
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    volumes:
      - db_data:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d/

volumes:
  db_data:

前回の記事では紹介しなかったいくつかの項目があります。

1. environment

これは環境変数を設定する部分です。環境変数とは、プログラムとかPCとかが動く際に使う設定情報のようなものとお考えください。

FLASK_ENVについて
FLASK_DEBUG: 1

これはFlaskの設定としてデバッグモードで起動してね!と設定しておく値です。コンテナの中でこの値が読み込まれて、Flaskアプリが動く際に使われています。自動リロードがされるようになって、コードの変更などを察知してくれるものです。

開発環境前提のお話です。

MySQLの環境変数
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
MYSQL_USER: user
MYSQL_PASSWORD: password

同様に、MySQLでも環境変数としてこちらの値が使われます。
これはデータベースの設定ですね。

MySQLの詳細は省きます。

2. depends_on

では次にdepends_onですが、こちらはコンテナの作成順を決めている記述です。なので、MySQLのコンテナが作成された後にFlaskのコンテナが動くということです。

書き方
depends_on:
    - db

dbというのはservicesの名前ですね。

ハンズオン環境を作って動かしてみよう

このセクションでは、先ほどのdocker-compose.ymlファイルと、コンテナを動かすためのファイル類を作っていきましょう。そして実行までしていきます。

ディレクトリ構成を作成
mkdir -p flask_project/src flask_project/sql && touch flask_project/src/app.py flask_project/src/requirements.txt flask_project/sql/init.sql flask_project/docker-compose.yml flask_project/Dockerfile
作成したディレクトリ構成
flask_project/
├── src/
│   ├── app.py
│   ├── requirements.txt
├── sql/
│   ├── init.sql
├── docker-compose.yml
├── Dockerfile

上記のようなディレクトリができていればOKです。
次にDockerfileです。

中身
# ベースイメージ
FROM python:3.9-slim

# 作業用のディレクトリを設定しています
WORKDIR /app

# 必要なファイル類をコピーしてライブラリをインストールしています
COPY src/ /app/
RUN pip install -r requirements.txt

# コンテナがリッスンするポート番号を指定してます
EXPOSE 5000

# Flaskアプリを起動します
CMD ["python", "app.py"]

ではapp.pyに移ります。前の記事よりも少しだけ難しく作成します。

app.pyの中身
from flask import Flask, request, jsonify
import mysql.connector
from mysql.connector import Error

app = Flask(__name__)

# データベースの接続情報
DB_HOST = "db"  # ここはdocker-compose.yml の `services` で指定した名前を
DB_USER = "user"
DB_PASSWORD = "password"
DB_NAME = "test_db"

# データベースとの接続をするための関数
def get_db_connection():
    try:
        connection = mysql.connector.connect(
            host=DB_HOST,
            user=DB_USER,
            password=DB_PASSWORD,
            database=DB_NAME
        )
        return connection
    except Error as e:
        print(f"エラー: {e}")
        return None

# ここからがAPI
@app.route('/')
def home():
    return "Welcome to the Flask-MySQL App!"

@app.route('/add', methods=['POST'])
def add_data(): # データベースに名前を登録する関数
    data = request.get_json()
    if not data or 'name' not in data:
        return jsonify({"error": "Invalid input"}), 400
    
    connection = get_db_connection()
    if connection is None:
        return jsonify({"error": "Database connection failed"}), 500

    try:
        cursor = connection.cursor()
        cursor.execute("INSERT INTO users (name) VALUES (%s)", (data['name'],))
        connection.commit()
        return jsonify({"message": f"User {data['name']} added successfully"}), 200
    except Error as e:
        return jsonify({"error": f"Database error: {e}"}), 500
    finally:
        connection.close()

@app.route('/users', methods=['GET'])
def get_users(): # データベースから登録されている名前を全て取得する関数
    connection = get_db_connection()
    if connection is None:
        return jsonify({"error": "Database connection failed"}), 500

    try:
        cursor = connection.cursor(dictionary=True)
        cursor.execute("SELECT * FROM users")
        rows = cursor.fetchall()
        return jsonify(rows), 200
    except Error as e:
        return jsonify({"error": f"Database error: {e}"}), 500
    finally:
        connection.close()

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

requirements.txtも作成します。

書き方
Flask
mysql-connector-python==8.0.32

最後にinit.sqlの中身を書いていきましょう。

init.sqlはデータベースの設定を書き込んでおくことで、コンテナ起動時などにデータベースとその中のテーブルを作っておけるファイルです。

※もちろんDocker関連の設定ファイルに書き込むことが前提です。

書き方
CREATE DATABASE IF NOT EXISTS test_db;
USE test_db;

CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

MySQLの公式イメージでは、/docker-entrypoint-initdb.d/に置いたSQLファイル(init.sqlとか)を起動時に自動で実行する仕組みがあります。

最後にdocker-compose.ymlですが。

docker-compose.ymlファイルは記事の最初に書いたものを使って下さい。

では実行しましょう!

実行コマンド
docker compose up

docker-compose.ymlファイルのあるディレクトリで実行して下さい。

以下の画像のように動いているのを確認できました。
image.png

では実際にGETリクエストである/にリクエストを送ってみましょう。

添付画像のようになっていればOKです。
image.png

次にユーザー登録をしていきます。
これはcurlコマンドを使ってPOSTリクエストを送っていきます。

curl -X POST -H "Content-Type: application/json" -d '{"name": "TestName"}' http://localhost:5000/add
成功メッセージ
{
  "message": "User TestName added successfully"
}

こうなっていれば問題ありません。

では最後に登録されたユーザーの一覧を出してみましょう。

image.png

無事登録ができていました!

あれ?これはどこでコンテナ同士が繋がってるの?

と思う人は勘がいいです。
Docker Composeではネットワークは内部的に作成されて勝手に連携されています。
勝手にやってくれるのはとてもいいことなんですが、中で何が行われているかわからないのは怖いですね。

まずはネットワーク一覧で探してみる
docker network ls

image.png
この実行結果にあるflask_project_defaultというのが、今回自動的に作られたネットワークです。ではこのネットワークの詳細を見てみましょう。

詳細を調べる
docker network inspect flask_project_default 

私の環境では以下の画像のような結果が表示されました。
image.png

Dockerネットワークの記事でこの中身については記述しているので、がっつり説明する気はありませんが、ラベル情報が追記されていますね。これも勝手に書き込まれているようです。

おわりに

さて、ここまでの読了お疲れ様でした。初学者が学ぶべきDocker基礎の記事はここまででおしまいです。新しい技術を最初から深ぼろうとはせず、さらっと全体をなぞるのが大事だと思っています。
ただ、Dockerは難しい技術です。Linuxの集大成のような技術ですし、各言語ごとの環境構築方法もわかっていないといけません。私のDocker記事は通してPython(Flask)を使ってきましたが、他の言語の場合はその環境構築方法、フレームワークの使い方を覚えてから応用してみて下さい。

まとめ記事に戻るにはこちら👇

715527be-86a3-4835-be5e-5b6b45d618f8_720.png

余談

フルリモートフルフレックスの会社にいるのに、家では仕事や学習をできないタイプなので、コワーキングかカフェにいることが多い人間です。PRONTカフェが好きです☕️

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?