この記事では、Flaskを使用したウェブアプリケーションをGoogle App Engineにデプロイし、Cloud SQL(PostgreSQL)データベースに接続する手順を詳しく説明します。ウェブアプリの詳細については、別の記事で解説する予定です。
GCP(Google Cloud Platform)は初回でアカウントを作成すると、90日間で300ドル分貰えるのでおすすめです。また他にも、無料枠が多いのも特徴です。詳細はこちら
こちらが今回作成した簡単なwebアプリになります。UI,UXがこだわりきれてないのですが、カメラを起動して、ユーザーの手を認識して、ユーザーがコンピュータの指示に従うとスコアが増えていくようになっています。ぜひ、遊んで、スコアをリーダーボードにあげてみてください。
前提条件
以下は他の記事でも詳しく解説されているので、そちらをみてください。
・Google Cloud Platform(GCP)アカウントを持っていること
・Cloud SDKがインストールされていること
・Python 3.9 以上がインストールされていること
ステップ1: プロジェクトのセットアップ
1.1 プロジェクトディレクトリの作成
まず、新しいプロジェクトディレクトリを作成してここにつくってWEBアプリのコードをかいていきます。
mkdir janken-game
cd janken-game
1.2 必要なパッケージのインストール
requirements.txt ファイルを作成し、以下の内容を追加します。
以下は例です。
Flask==2.3.3
SQLAlchemy==1.4.36
gunicorn==20.1.0
cloud-sql-python-connector[pg8000]==1.2.2
ステップ2: Flaskアプリケーションの作成
ウェブアプリの詳細な実装については、別の記事で解説する予定です。
2.1 アプリケーションコードの作成
app.py ファイルを作成し、以下のコードを追加します。
import os
from flask import Flask, render_template, request, jsonify, redirect, url_for
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Base, LeaderboardEntrySingle, LeaderboardEntryBoth
# Cloud SQL Python Connector のインポート
from google.cloud.sql.connector import Connector
import pg8000
app = Flask(__name__)
# 環境変数からデータベース接続情報を取得
db_user = os.environ.get("DB_USER")
db_password = os.environ.get("DB_PASS")
db_name = os.environ.get("DB_NAME")
cloud_sql_connection_name = os.environ.get("CLOUD_SQL_CONNECTION_NAME") # app.yaml で設定
# Cloud SQL Python Connector を初期化
connector = Connector()
def getconn():
conn = connector.connect(
cloud_sql_connection_name,
"pg8000",
user=db_user,
password=db_password,
db=db_name,
)
return conn
# SQLAlchemy エンジンを作成
engine = create_engine(
"postgresql+pg8000://",
creator=getconn,
)
Base.metadata.create_all(engine)
DBSession = sessionmaker(bind=engine)
session = DBSession()
# ルートエンドポイント
@app.route('/')
def index():
return render_template('index.html')
# 片手モードのゲーム開始エンドポイント
@app.route('/start_game_single_hand')
def start_game_single_hand():
return render_template('game_single_hand.html')
# 両手モードのゲーム開始エンドポイント
@app.route('/start_game_both_hands')
def start_game_both_hands():
return render_template('game_both_hands.html')
# スコアの受け取りエンドポイント(片手モード)
@app.route('/submit_score_single', methods=['POST'])
def submit_score_single():
data = request.get_json()
username = data.get('username')
score = data.get('score')
if username and score is not None:
entry = LeaderboardEntrySingle(username=username, score=score)
session.add(entry)
session.commit()
return jsonify({'status': 'success'})
else:
return jsonify({'status': 'error'}), 400
# リーダーボード表示エンドポイント(片手モード)
@app.route('/leaderboard_single')
def leaderboard_single_hand():
leaderboard = session.query(LeaderboardEntrySingle).order_by(LeaderboardEntrySingle.score.desc()).all()
return render_template('leaderboard_single.html', leaderboard=leaderboard)
# スコアの受け取りエンドポイント(両手モード)
@app.route('/submit_score_both', methods=['POST'])
def submit_score_both():
data = request.get_json()
username = data.get('username')
score = data.get('score')
if username and score is not None:
entry = LeaderboardEntryBoth(username=username, score=score)
session.add(entry)
session.commit()
return jsonify({'status': 'success'})
else:
return jsonify({'status': 'error'}), 400
# リーダーボード表示エンドポイント(両手モード)
@app.route('/leaderboard_both')
def leaderboard_both_hand():
leaderboard = session.query(LeaderboardEntryBoth).order_by(LeaderboardEntryBoth.score.desc()).all()
return render_template('leaderboard_both.html', leaderboard=leaderboard)
if __name__ == '__main__':
app.run(debug=True)
2.2 モデルの定義
models.py ファイルを作成し、データベースのモデルを定義します。
(以下は例です)
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class LeaderboardEntrySingle(Base):
__tablename__ = 'leaderboard_single'
id = Column(Integer, primary_key=True)
username = Column(String)
score = Column(Integer)
class LeaderboardEntryBoth(Base):
__tablename__ = 'leaderboard_both'
id = Column(Integer, primary_key=True)
username = Column(String)
score = Column(Integer)
ステップ3: Cloud SQL(PostgreSQL)インスタンスの作成
3.1 インスタンスの作成
- Google Cloud Console にアクセスし、左側のメニューから「SQL」を選択します。
- インスタンスを作成」をクリックし、「PostgreSQL」を選択します。
- インスタンスID、パスワード、リージョン(例: asia-northeast2)を設定します。
- 「作成」をクリックしてインスタンスを作成します。
3.2 データベースとユーザーの作成
- インスタンスが作成されたら、その詳細ページに移動します。
- 「データベース」タブで、新しいデータベース(例: janken_db)を作成します。
- 「ユーザー」タブで、新しいユーザー(例: flask_user)を作成し、パスワードを設定します。
3.3 接続情報の取得
- インスタンス接続名(例: your-project-id:region:instance-id)をメモします。
- Private IP を使用する場合は、「接続」タブでPrivate IPを有効にします。
ステップ4: app.yaml の作成
App Engineの設定ファイル app.yaml を作成し、以下の内容を追加します。
runtime: python39
entrypoint: gunicorn -b :$PORT app:app
env_variables:
DB_USER: "flask_user" # データベースユーザー名
DB_PASS: "your-password" # データベースパスワード
DB_NAME: "janken_db" # データベース名
CLOUD_SQL_CONNECTION_NAME: "your-project-id:region:instance-id" # インスタンス接続名
vpc_access_connector:
name: "projects/your-project-id/locations/asia-northeast2/connectors/serverless-connector"
automatic_scaling:
target_cpu_utilization: 0.65
max_instances: 2
handlers:
- url: /static
static_dir: static
- url: /.*
script: auto
注意: your-password や your-project-id:region:instance-id などは、あなたの環境に合わせて置き換えてください。
ステップ5: サービスアカウントの権限設定
5.1 Cloud SQL Admin APIの有効化
- Google Cloud Console で左上のメニューから「APIとサービス」 > 「ライブラリ」を選択します。
- 「Cloud SQL Admin API」を検索し、選択します。
- 「有効にする」をクリックします。
5.2 サービスアカウントに役割を付与
- 左側のメニューから「IAMと管理」 > 「IAM」を選択します。
- サービスアカウント your-project-id@appspot.gserviceaccount.com を探します。
- 「編集」をクリックし、「+役割を追加」を選択します。
- 「Cloud SQL クライアント」の役割を選択し、追加します。
- 「保存」をクリックします。
ステップ6: アプリケーションのデプロイ
自分の作成したフォルダで、以下のコマンドを実行して、アプリケーションをデプロイします。
gcloud app deploy
デプロイが成功したら、次のコマンドでアプリケーションをブラウザで開きます。
gcloud app browse
ステップ7: トラブルシューティング
7.1 ログの確認
問題が発生した場合は、以下のコマンドでログを確認できます。
gcloud app logs tail -s default
7.2 よくある問題と解決策
・権限エラー: サービスアカウントに必要な役割(「Cloud SQL クライアント」など)が付与されていることを確認します。
・APIが有効化されていない: 「Cloud SQL Admin API」が有効になっていることを確認します。
・接続エラー: CLOUD_SQL_CONNECTION_NAME が正しく設定されていることを確認します。