Skip to content

DB ユーザーと migration の規約 ​

各サービスの PostgreSQL (Cloud SQL / AlloyDB) は、接続ユーザーを役割で分離する。 dev / stg / prd の 3 環境すべてで同じ構成にすること。

役割ユーザー権限用途
app userサービス専用 (cms / mdmsjp 等)DML のみ (SELECT / INSERT / UPDATE / DELETE)アプリ runtime の通常接続
migration userpostgresテーブル所有者として 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-migrationGSM mdmsjp-migration-database-url
authデプロイ時の migrationGSM auth-migration-database-url
cms (Payload)Pod 起動時に payload migrateGSM 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 start

MIGRATION_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 に必ず組み込むこと。

新サービス追加時のチェックリスト ​

  1. app user をサービス専用名で作成し、DML のみ GRANT する(テーブル所有者にしない)
  2. migration は postgres 接続で実行する(専用 Job または MIGRATION_DATABASE_URI 方式)
  3. migration 接続の secret は GSM に {service}-migration-database-* で投入する
  4. db import 対象なら、import タスクの GRANT ブロックに app user への再付与を追加する (taskfiles/db_import.yaml の既存サービスの並びに合わせる)