OrbStack + Docker Compose でFlask + PostgreSQL 環境を作る

docker
記事内に広告が含まれています。
スポンサーリンク
スポンサーリンク

はじめに

前にterraformを使ってローカルdocker(OrbStack)でnginxのコンテナを作成して、静的コンテンツを設定する、という作業をご紹介しました。

Gemini Code Assistと二人三脚で、TerraformによるローカルDocker環境を爆速構築してみた
タイトルの通り、VSCode + Gemini Code Assistを使って、ローカルのOrbStackにterraformでコンテナを作ってみました。環境の超概要はこちらmacOS Tahoe 26.4OrbStack 2.0.5Ter…

今回はもう少し進んで、ローカルで簡単なwebサービスを作ってみたいと思います。
さらにゆくゆくはAWSのECSとしてデプロイしたいと目論んでますので、お楽しみに。

ちなみに今回はClaudeと対話しながら構成を決めて実装を進めました。詰まったところも一緒にデバッグしてもらいながら進められたので、初めての構成でもスムーズに動かすことができました。

概要

技術スタック

項目技術
言語Python 3.12
フレームワークFlask
データベースPostgreSQL 16
ローカル環境Docker Compose / OrbStack

リポジトリ

flask-to-ecs/
├── docker-compose.yaml
├── app/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── main.py
├── .github/
│ └── workflows/ # 今後追加予定
└── terraform/ # 今後追加予定

構成

docker-compose.yaml

ローカルでのコンテナとしては、webとdbの2つで構成。

  • web
    • 後述するDockerfileでpythonのイメージ
    • ポートはホスト側(Mac)は5001、コンテナ側は5000(flaskのデフォルト)
      • Mac側のポート5000は、AirPlayで使っているので避けてます(動作確認で少しハマりましたw)
    • DB接続するための環境変数を定義
    • ボリュームはリポジトリのappディレクトリを使う
    • dbコンテナがservice_healthyになったら起動
  • db
    • postgresのイメージ
    • 環境変数としてDB接続情報を定義
      • 今はローカルなのでDB接続情報は平文で定義してますが、AWSに持っていく場合は環境変数などで管理していく予定です。んー、secrets使うおうかなぁw
    • DBのデータはDockerボリュームで管理。これによりコンテナを停止してもデータは保持されます。
    • ポートはデフォルト(5432)
    • ヘルスチェックをしてます。
services:
  web:
    build: ./app
    ports:
      - "5001:5000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
    volumes:
      - ./app:/app
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:

Dockerfileとrequirements.txt

webコンテナはDockerfileとrequirements.txtで構成。

  • pythonイメージ
  • requirements.txtで指定したライブラリをインストール
    • flask:フレームワーク
    • psycopg2-binary:postgresのライブラリ
    • flask-sqlalchemy :flaskでdbを扱うライブラリ
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD ["flask", "--app", "main", "run", "--host=0.0.0.0", "--reload"]
flask
psycopg2-binary
flask-sqlalchemy

main.py

簡単なwebサービス風のアプリ。
DBは idnameだけですが、postでデータを登録、querystringでnameの部分一致検索が出来るようにはなっています。

from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
import os

app = Flask(__name__)
app.json.ensure_ascii = False
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"]
db = SQLAlchemy(app)

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)

with app.app_context():
    db.create_all()

@app.route("/")
def index():
    return jsonify({"message": "Hello, Flask + PostgreSQL!"})

@app.route("/items", methods=["GET"])
def get_items():
    name = request.args.get("name")  # ?name=xxx を受け取る
    if name:
        items = Item.query.filter(Item.name.contains(name)).all()
    else:
        items = Item.query.all()
    return jsonify([{"id": i.id, "name": i.name} for i in items])

@app.route("/items", methods=["POST"])
def create_item():
    data = request.get_json()
    if not data or "name" not in data:
        return jsonify({"error": "name is required"}), 400
    item = Item(name=data["name"])
    db.session.add(item)
    db.session.commit()
    return jsonify({"id": item.id, "name": item.name}), 201

コンテナの起動

材料が出来ましたので、docker-compose.yamlがあるディレクトリで以下のコマンドを実行

docker compose up --build

動作確認

Hello メッセージ

ブラウザ、またはcurlでhttps://www.51weblab.jp:5001/へアクセス

curl https://www.51weblab.jp:5001/
{"message":"Hello, Flask + PostgreSQL!"}

データ登録

curl -X POST https://www.51weblab.jp:5001/items \
-H "Content-Type: application/json" \
-d '{"name": "テストアイテム"}'

データ表示

ブラウザかcurlで全件を表示

# 全件表示
curl https://www.51weblab.jp:5001/items
[{"id":1,"name":"テストアイテム"},{"id":2,"name":"テストアイテム2"},{"id":3,"name":"サンプル3"},{"id":4,"name":"サンプル4"}]
  • データ検索は文字コードが手抜きなので、ブラウザで動作確認
    「テスト」を含むレコードを抽出してます。

まとめ

非常に簡単なアプリではありますが、まずはローカルdockerで作ってみました。
もう少しブラッシュアップしながら(?)最終的にAWS ECSを使ったwebサービス構築までのステップを進めていこうと思います。

ではでは。