アップグレード運用手順
Merlon はコンテナに状態を持たない。アップグレードとはイメージを置き換えることであり、データは PostgreSQL に残ったままである。アップグレードを重大な作業にしているのはイメージの入れ替えではなく、前方向のみのスキーママイグレーションである。
先に方針を決める
| 状況 | 方針 |
|---|---|
| ローカル評価 | 最新のバージョンタグを取得し、自由にアップグレードする |
| 共有環境・テスト環境 | バージョンタグを固定し、意図的にアップグレードし、バックアップを保持する |
| 本番 | ダイジェストを固定し、本番データの複製でリハーサルし、直前にバックアップを取得し、2バージョン以上を無検証で飛ばさない |
自動更新は存在せず、リリースの存在を通知する仕組みも無い。理由はデータ送出を参照。Releases を購読すること。
1. アップグレード前
- 現在稼働中のバージョンから移行先までのすべてのバージョンのリリースノートを読む。移行先のものだけでは不十分である。
- データベースと暗号鍵リングをバックアップする(バックアップと復元)。これが唯一のロールバック手段である。
- 現在のバージョン(
GET /healthz)とネイティブエンジンの設定ダイジェスト(GET /api/v1/system/config-digests)を記録する。 - 本番の設定とデータを代表する環境でリハーサルする。
2. リリース成果物を検証する
各タグ付きリリースは、イメージに加えて「プロジェクトがビルドしたものを実際にデプロイしている」ことを確認するための証跡を公開する。ロールアウト前に検証すること。検証されていないイメージをデプロイすることは、来歴の連鎖全体を捨てることに等しい。
GitHub Release から release-manifest.json、sbom-image.cdx.json、SHA256SUMS を取得し、次を実行する。
# 1. 添付ファイルが公開されたチェックサムと一致すること。
sha256sum -c SHA256SUMS
# 2. マニフェストから不変のイメージダイジェストを読み取る。可変タグではなく
# ダイジェストでデプロイする。
IMAGE=$(jq -r .image release-manifest.json)
DIGEST=$(jq -r .image_digest release-manifest.json)
# 3. このダイジェストが本リポジトリのリリースワークフローによって、マニフェスト
# が示すコミットからビルドされたことを GitHub が証明する。
gh attestation verify "oci://${IMAGE}@${DIGEST}" --repo ksuk/merlon
# 4. 検証済みのダイジェストを取得する。
docker pull "${IMAGE}@${DIGEST}"
${IMAGE}@${DIGEST} をデプロイし、そのダイジェストをデプロイ記録に残すこと。各タグの意味はコンテナイメージを参照。
3. マイグレーションを適用する
マイグレーションは起動時には実行されない。サービング用ロールが持たないロールを使う、独立した明示的な手順である。
export MERLON_MIGRATION_DATABASE_URL='postgres://merlon_migrate:...@host:5432/merlon'
make migrate
make audit-harden
ランナーはすべてのファイル名と SHA-256 を schema_migrations に記録し、アドバイザリロックを取得し、各ファイルを個別のトランザクションで適用する。2回目の実行は no-op である。チェックサムの不一致はロールアウトを停止させる。トラブルシューティング: データベースを参照。
make audit-harden は必須の2段階目である。対象リリースが新たに作成した表を含むすべてのアプリケーション表について、serving role にレビュー済みの権限だけを付与し、監査証跡は追記専用、migration ledger は owner 専用に維持する。同じ MERLON_MIGRATION_DATABASE_URL で実行し、serving role が既定の merlon_app でない場合は MERLON_APP_ROLE を設定すること。
:::warning スキーマ変更をまたぐローリングアップグレードは未対応
旧バージョンと新バージョンを同一データベースに対して同時に稼働させると失敗する。旧コードは新しいスキーマを理解しない。旧バージョンをサービスから外し、マイグレーションと serving-role grant の再適用を完了してから、新バージョンを起動すること。
:::
4. アップグレードを検証する
# 意図したバージョンであること。
curl -s http://localhost:8080/healthz
# プロセスの生存だけでなく、全サブシステムが ready であること。
curl -s http://localhost:8080/healthz/ready
# エンジン設定ダイジェストが手順1で記録した値と一致するか、
# 説明できる理由で変化していること。
curl -s http://localhost:8080/api/v1/system/config-digests
# マイグレーションをまたいで監査チェーンが維持されていること。
cd api && go run ./cmd/merlon-audit verify
その上で代表的なワークフローを実行する。顧客をスコアリングし、アラートをレビューし、ケースを作成する。ヘルスチェックが緑であることはプロセスが起動したことを意味するのであって、スコアリングが自組織のルールの期待どおりに振る舞い続けていることを意味しない。
5. ロールバック
:::danger マイグレーションは一方向である
リリース固有のロールバックが提供されない限り、SQL マイグレーションは前方向のみである。コンテナイメージを戻してもスキーマは戻らない。マイグレーションが適用済みであれば、戻る唯一の方法はアップグレード前のバックアップを復元することであり、それ以降に書き込まれたすべてを失う。
:::
検証に失敗した場合の対応は次のとおり。
- ロールアウトを停止する。以降のマイグレーションを適用しない。
- マイグレーションが未適用であれば、以前のダイジェストを再デプロイする。それでロールバックは完了である。
- マイグレーションが適用済みであれば、fresh databaseを作成し、そこでアップグレード前のbackupをrestore・検証してから(バックアップと復元)、
MERLON_DATABASE_URLをcutoverし、以前のダイジェストを再デプロイする。現在のschemaへin-place restoreしてはならない。 - 再試行の前に原因を調査する。
ロールアウトを「通す」ために schema_migrations の行を削除したり、適用済みのマイグレーションを編集したりしてはならない。それはスキーマの不整合を解消せず、不整合が起きた証跡だけを消す。