DB ユーザーと migration の規約
各サービスの PostgreSQL (Cloud SQL / AlloyDB) は、接続ユーザーを役割で分離する。 dev / stg / prd の 3 環境すべてで同じ構成にすること。
| 役割 | ユーザー | 権限 | 用途 |
|---|---|---|---|
| app user | サービス専用 (cms / mdmsjp 等) | DML のみ (SELECT / INSERT / UPDATE / DELETE) | アプリ runtime の通常接続 |
| migration user | postgres | テーブル所有者として DDL 可 | schema migration の実行のみ |
テーブル所有者は全環境で postgres に統一する。
なぜこの構成か
- DDL は所有者限定: PostgreSQL の
ALTER TABLE等は GRANT では付与できず、テーブル所有者(またはそのロールのメンバー)しか実行できない。migration 実行ユーザーとテーブル所有者は必ず一致させる必要がある - 毎朝の db import と両立する所有者は postgres だけ: dev / stg の DB は毎朝
db_import_*.ymlが prd ダンプから--user=postgresで作り直すため、テーブル所有者は必ず postgres になる。migration を app user で実行する構成にすると、import 直後から DDL migration がmust be owner of table ...で失敗する - 最小権限: app user から DDL を外すことで、アプリの脆弱性経由で schema を破壊される blast radius を減らす
- stg が prd のリハーサルになる: 3 環境で migration の実行ユーザー・所有者が同一なら、「stg で通った migration が prd で落ちる」ことが原理的に起きない
サービス別の実装
| サービス | migration の実行方法 | migration 接続の定義 |
|---|---|---|
| backend (Go) | デプロイ時の Job backend-migrate-* | backend/k8s/migration/{env}/kustomization.template.yaml |
| mdms_jp (Prisma) | デプロイ時の Job mdmsjp-migration | GSM mdmsjp-migration-database-url |
| auth | デプロイ時の migration | GSM auth-migration-database-url |
| cms (Payload) | Pod 起動時に payload migrate | GSM cms-migration-database-username / -password から MIGRATION_DATABASE_URI を組み立て |
cms は Payload の運用推奨に従い起動時 migrate 方式のため、Dockerfile の CMD で migrate だけ MIGRATION_DATABASE_URI に切り替える:
sh
DATABASE_URI="${MIGRATION_DATABASE_URI:-$DATABASE_URI}" pnpm exec payload migrate && next startMIGRATION_DATABASE_URI 未設定時(ローカル開発)は app 接続にフォールバックする。
db import との関係
dev / stg の DB は毎朝 prd ダンプで作り直されるため、prd に未リリースの migration は import のたびに消える。cms のように起動時 migrate のサービスは、import 後に Pod を 再起動しないと稼働中 Pod が消えた schema を参照し続けて 5xx になる。 このため db_import_cms.yml は import 後に kubectl rollout restart deployment/cms を実行し、 migration を毎朝再適用する。
WARNING
db import の対象サービスで「デプロイ時 Job」以外の migration 方式を採る場合は、 import 後の再適用手段(rollout restart 等)を import workflow に必ず組み込むこと。
新サービス追加時のチェックリスト
- app user をサービス専用名で作成し、DML のみ GRANT する(テーブル所有者にしない)
- migration は
postgres接続で実行する(専用 Job またはMIGRATION_DATABASE_URI方式) - migration 接続の secret は GSM に
{service}-migration-database-*で投入する - db import 対象なら、import タスクの GRANT ブロックに app user への再付与を追加する (
taskfiles/db_import.yamlの既存サービスの並びに合わせる)