TL;DR
- マルチリージョン構成の EKS アプリを大阪リージョンへデプロイしたら、Pod が
cannot execute INSERT in a read-only transactionで落ちてデプロイ失敗。 - 原因は 大阪リージョンの Aurora が Aurora Global Database のセカンダリ(読取専用) で、アプリの書込みクエリが拒否されたこと。
- 本質は アプリ層 = アクティブ-アクティブ/DB層 = アクティブ-パッシブ のミスマッチ。EKS に限らず、ECS / EC2 / Lambda でも構図は同じです。
環境
| 項目 | 内容 |
|---|---|
| クラウド | AWS |
| アプリ実行基盤 | EKS(東京・大阪両リージョンで Pod 稼働) |
| DB | Aurora PostgreSQL Global Database(東京=プライマリ/大阪=セカンダリ) |
| デプロイ | リージョンごとに個別実施(同時ではない) |
| 時期 | 2024年前半(Aurora Global Database writer endpoint リリース前) |
構成のイメージは下の図のとおりで、東京と大阪それぞれが独立した Aurora クラスターを持ち、ストレージレベルの非同期レプリケーションでつながっています。

図1: Aurora Global Database の基本構成(東京プライマリ/大阪セカンダリ)
起きたこと
東京リージョンへのデプロイは成功しました。続けて大阪リージョンへ同じアプリをデプロイしたところ、Pod が起動直後にクラッシュし、デプロイが失敗します。
Pod のログを確認すると、PostgreSQL への接続自体は成立していたものの、書込みクエリのところで以下のエラーが繰り返し出ていました。
ERROR: cannot execute INSERT in a read-only transaction
接続先 DB を確認したところ、大阪リージョンの Aurora(セカンダリ=読取専用)でした。アプリは「自分が動いているリージョンの Aurora」に接続するように設定されていて、大阪 Pod は大阪 Aurora を見にいっていた、という状況です。
なお、原因の最終的な特定は上位商流で実施されたので、ここでは「現象」と「原因」を結ぶ最低限の経緯にとどめます。
原因
Aurora Global Database のエンドポイントは各リージョン独立
Aurora Global Database はリージョンごとに独立した DB クラスターの集合体で、各リージョンに別個のエンドポイントが発行されます。共有のエンドポイントは持ちません(後述の writer endpoint がリリースされるまでは)。
| 役割 | エンドポイント例 | 書込み |
|---|---|---|
| プライマリ(東京) | my-global.cluster-XXXX.ap-northeast-1.rds.amazonaws.com |
✅ 可 |
| セカンダリ(大阪) | my-global.cluster-ro-XXXX.ap-northeast-3.rds.amazonaws.com |
❌ 読取専用 |
セカンダリのクラスターエンドポイントは命名規則に -ro が含まれ、読取専用です。書込みクエリは PostgreSQL のエンジン層が cannot execute INSERT in a read-only transaction で拒否します。
本質:アプリ層と DB層の DR 戦略のミスマッチ
本件の構成を整理すると、次のようになります。
図2: アプリ層は両リージョン稼働(A-A)、DB層は東京のみ書込可(A-P)。大阪 Pod の書込みがセカンダリで拒否される
- アプリ層: 両リージョンで Pod を稼働させる アクティブ-アクティブ 構成
- DB層: 書込みは東京プライマリのみ、大阪は読取専用の アクティブ-パッシブ 構成
両者を整合させるには、大阪アプリの書込み宛先を 東京プライマリのエンドポイント に向けるか、アプリ層を「DR時のみ大阪起動」のアクティブ-パッシブに揃える必要があります。本件はそのどちらも採られていなかったため、大阪アプリが大阪セカンダリへ書込み → 拒否、となりました。
「両リージョンでアプリが動いている」=「両方が同じように書込める」ではありません。Aurora Global Database に限らず、マルチリージョン構成では アプリ層と DB層の DR 戦略が揃っているか を必ず確認してください。
対処と再発防止
複数の対処パターンを、**当時の制約(writer endpoint 前)と現在の状況(writer endpoint 後)**に分けて整理します。
① Aurora Global Database writer endpoint(2024-10〜の本命)
2024年10月、Aurora Global Database に writer endpoint がリリースされました。これは「現在のプライマリの書込インスタンスに自動追従する単一エンドポイント」で、Route 53 ベースのマネージドサービスとして提供されます。
| 効果 | 内容 |
|---|---|
| エンドポイント統一 | 両リージョンのアプリが同一の writer endpoint に接続できる |
| 切替後の追従 | switchover / failover 後も接続文字列の変更は不要 |
| 注意点 | DNS キャッシュ TTL を 5 秒程度に下げる推奨。更新完了は RDS-EVENT-0397 で通知される |
現在の最適解です。両リージョンのアプリが writer endpoint に接続していれば、本件のような「大阪アプリが大阪セカンダリへ書込みにいってしまう」事象は発生しません。
② Route 53 CNAME + Lambda による自動更新(writer endpoint 前の定番)
writer endpoint リリース前は、カスタム CNAME を Route 53 に作成し、フェイルオーバー完了イベントを EventBridge で拾って Lambda が CNAME を更新する、というパターンが定番でした。AWS が aws-samples で実装例 を公開しています。
writer endpoint が登場した今は基本的に①へ移行できますが、既存システムで CNAME 運用が回っていれば無理に変更する必要はありません。
③ アプリ層の DR 戦略を見直す
DB がアクティブ-パッシブなら、アプリ側もそれに揃える、という選択肢です。
- 通常時は東京のみアプリ稼働、大阪はスタンバイ
- DR 発動時に大阪アプリを起動し、Aurora セカンダリを昇格
「常時両リージョン稼働」のメリット(負荷分散、リージョン障害時のゼロダウンタイム)を諦める判断ですが、構成がシンプルになり運用負荷が下がります。コストと可用性要件のバランスで選ぶ領域です。
④ 接続先を東京 Writer に一本化(最もシンプル)
両リージョンのアプリを 常に東京 Writer に接続 させる構成です。①が登場する前の現実解として実装されていることがあります。
| メリット | デメリット |
|---|---|
| 構成が単純、設定変更箇所が少ない | 東京リージョン障害時に手動でアプリ設定変更が必要 |
| アプリは書込み先で迷わない | クロスリージョンの DB 通信レイテンシが乗る |
当時の現実解と、現在の答え
本件の発生時点(2024年前半)では、②または④ が現実的でした。
2024年10月以降は ①の writer endpoint を採用するのが、ほぼ全方位で最適です。
設計思想の観点から本件のような失敗を防ぐためのエンドポイント設計の落とし穴を、別記事 Aurora Global Database のDRは「DBだけ」では完成しない(Zenn)にまとめています。あわせてどうぞ。
まとめ
| 教訓 |
|---|
| Aurora Global Database のセカンダリは 読取専用。書込みは即拒否される |
| 各リージョンに 独立したエンドポイント。共有されない(writer endpoint 登場前まで) |
| アプリ層の DR 戦略と DB層の DR 戦略は必ず揃える |
| 2024年10月以降は Global Database writer endpoint が第一選択 |
EKS の話として書きましたが、ECS / EC2 / Lambda でも、マルチリージョンで書込みが発生するアプリなら同じ落とし穴を踏みます。「両リージョンでアプリが動いている」=「両方が同じように書込める」と思い込まないよう、気をつけてください。
同じ AWS インフラ系のトラブル切り分けとして、ALB 502 の切り分け手順を別記事 ALB 502 エラーの原因を特定する「3層切り分け」定石パターン(AWS アクセスログ × Target Group × EKS Pod) にまとめています。あわせてどうぞ。
出典・参考
- Using switchover or failover in Amazon Aurora Global Database — AWS 公式ドキュメント
- Diving deep into the new Amazon Aurora Global Database writer endpoint — AWS Database Blog
- Automate Amazon Aurora Global Database endpoint management — AWS Database Blog
- aws-samples: amazon-aurora-global-database-endpoint-automation — GitHub
