🌊

Amazon RDS Blue/Green Deployments x Terraform で MySQL 変更

2025/01/31に公開

1. はじめに

Amazon RDS Blue/Green Deployments を活用することで、
データベースの更新時のダウンタイムを最小限に抑えることができます。
本記事では、MySQL を対象に手順を紹介します。

2. RDS Blue/Green Deployments

Amazon RDS Blue/Green Deployments では、データベースの設定変更を安全に行えます。
今回、私が試した際の ダウンタイムは1秒程度 でした。(公式には1分未満とされています)
ダウンタイムの確認方法は Locust で0.5秒毎に healthcheck を叩いて確認しています。

  • Blue 環境(既存のDB)
    現在運用中のRDSインスタンス。トラフィックを処理中。
  • Green 環境(新しいDB)
    Blue 環境の複製を作成し、バージョンアップや設定変更を適用。

2.1 メリット

ダウンタイム最小化: 事前に新しい環境を準備し、検証後に切り替え。
簡単なロールバック: 問題があれば元の Blue 環境に戻せる。
本番環境への影響なし: Green 環境で動作確認ができる。

3. 事前準備

3.1 コンソール or CLI VS Terraform

切り替える方法としては、AWSマネジメントコンソール、CLI、Terraform があります。
切り替え前に Green 環境で検証するのがベストプラクティスとされていますが、
Terraform から実施する場合は一連の作業が自動的に行われるため不可能になります。
また、リードレプリカな構成の場合は Terraform では実施できません。

今回は、Terraformで更新することにします。

3.2 ユーザーの IAM 権限を確認

  • Blue/Green Deployment を作成
    • rds:CreateBlueGreenDeployment
    • rds:AddTagsToResource
    • rds:CreateDBInstanceReadReplica
  • Blue/Green Deployment を切り替える
    • rds:SwitchoverBlueGreenDeployment
    • rds:ModifyDBInstance
    • rds:PromoteReadReplica
  • Blue/Green Deployment を削除
    • rds:DeleteBlueGreenDeployment
    • rds:DeleteDBInstance

3.3 制約事項の確認

一般的な制約

  • Secrets Manager: マスターユーザーパスワード管理は非対応。
  • DLVの有効化: Blue 環境でDLV有効時、全リードレプリカにも適用が必要。
  • Redshift統合: 切り替え時に統合を削除・再作成が必要。
  • Event Scheduler: Green 環境では無効化が必要(不整合防止)。
  • 暗号化の変更不可: 暗号化/非暗号化間の変更は不可。
  • エンジンバージョン: Blue 環境を Green 環境より新しくすることは不可。
  • リソースのAWSアカウント: 同一AWSアカウント内でのみ利用可能。
  • 非対応機能:
    • Amazon RDS Proxy
    • カスケードリードレプリカ
    • クロスリージョンリードレプリカ
    • AWS CloudFormation
    • マルチAZ DBクラスター

RDS for MySQL の制約

  • 外部バイナリログレプリカ: Blue 環境で設定不可。
  • カスタムオプショングループ: メジャーバージョンアップ指定は不可(後でアップグレード可)
  • AWS JDBCドライバー: 非対応(詳細はGitHub参照)。

RDS for PostgreSQL の制約

  • 自己管理の論理ソース/レプリカ: Blue 環境では設定不可。
  • FDW拡張機能: 外部サーバー設定時にIPアドレスではなくエンドポイント名の使用が必須。
  • 論理レプリケーションスロット: 各データベースに必要。DB数が増えると負荷増大の可能性。
  • Babelfish: バージョン 15.7 以降、16.3 以降のみサポート。
  • 拡張機能の制約:
    • pg_partman: Blue 環境では無効化が必要(DDLがレプリケーションを阻害)。
    • pg_cron: Green 環境では無効のままにする必要あり(競合防止)。
    • pglogical / pgactive: Blue 環境で無効化が必要(スイッチオーバー後に有効化可能)。
    • pgAudit: Blue/Green 両環境の shared_preload_libraries に設定が必要。

4. Blue/Green Deployment を実施

4.1 blue_green_update の追加

Terraform で RDS Blue/Green Deployment を実施する場合、
Blue/Green Deployment の作成、変更、切り替え、削除が全て自動的に行われます。

  blue_green_update {
    enabled = true
  }

4.2 インスタンスに変更を加える

  # aws_db_instance.sample_db will be updated in-place
  ~ resource "aws_db_instance" "sample_db" {
        id                                    = "db-XXXXXXXXXXXXXXXXXXXXXXXXXX"
      ~ instance_class                        = "db.m7g.xlarge" -> "db.m7g.large"
        tags                                  = {
            "Name"      = "sample-db"
            "autosleep" = "false"
        }
        # (70 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

4.3 Terraform 適用時のエラー 😭

1時間以上待って失敗しました 😭

terraform apply

terraform apply
~

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_db_instance.sample_db will be updated in-place
  ~ resource "aws_db_instance" "sample_db" {
        id                                    = "db-XXXXXXXXXXXXXXXXXXXXXXXXXX"
      ~ instance_class                        = "db.m7g.xlarge" -> "db.m7g.large"
        tags                                  = {
            "Name"      = "sample-db"
            "autosleep" = "false"
        }
        # (69 unchanged attributes hidden)

      + blue_green_update {
          + enabled = true
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_db_instance.sample_db: Modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX]
aws_db_instance.sample_db: Still modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX, 10s elapsed]
~
aws_db_instance.sample_db: Still modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX, 57m21s elapsed]
╷
│ Error: updating RDS DB Instance (sample-db): creating Blue/Green Deployment: waiting for Green environment: unexpected state 'storage-initialization', wanted target 'available, storage-optimization'. last error: %!s(<nil>)
│ 
│   with aws_db_instance.sample_db,
│   on db_instance.tf line 7, in resource "aws_db_instance" "sample_db":
│    7: resource "aws_db_instance" "sample_db" {
│ 
╵

その頃AWSコンソールでは...

失敗した場合は

から以下のように自動的に削除(ロールバック)されるようです。
(おそらくTerraform側でコントロールしてると思われます。たぶん)

4.3 成功 🎉

1時間以上かかりましたが、成功しました 🎉

terraform apply

terraform apply
~

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_db_instance.sample_db will be updated in-place
  ~ resource "aws_db_instance" "sample_db" {
        id                                    = "db-XXXXXXXXXXXXXXXXXXXXXXXXXX"
      ~ instance_class                        = "db.m7g.xlarge" -> "db.m7g.large"
        tags                                  = {
            "Name"      = "sample-db"
            "autosleep" = "false"
        }
        # (70 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_db_instance.sample_db: Modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX]
aws_db_instance.sample_db: Still modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX, 10s elapsed]
~
aws_db_instance.sample_db: Still modifying... [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX, 1h8m0s elapsed]
aws_db_instance.sample_db: Modifications complete after 1h8m8s [id=db-XXXXXXXXXXXXXXXXXXXXXXXXXX]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Outputs:

sample_password = <sensitive>

その頃AWSコンソールでは...

開始直後はプライマリが「変更中」になっていますが、ダウンタイムはありませんでした。
おそらく見かけ上「変更中」になっているだけだと思います、たぶん。

しばらく経つと「利用可能」になりますが、まだ Blue/Green は切り替わってないません。

そして、いつのまにかこのように Blue/Green が削除されていました。
(キャプチャ撮り忘れましたが、ちゃんと切り替わるフェーズは目視で確認できました)

想定通り、"db.m7g.xlarge" -> "db.m7g.large" へ変更されています。

Locust での監視結果

  • 切り替えの時に1秒程度ダウンタイムが発生しました(0.5秒毎 x 2リクエスト失敗)
  • レスポンスタイムについては、ブルーグリーン作成時に2秒間100sから300sに増加しました。

5. まとめ

Blue/Green Deployment で MySQL をスムーズにバージョンアップ/変更可能
事前に Green 環境で動作確認し、リスクを最小化
カットオーバーでダウンタイムを抑えつつ安全に移行

Amazon RDS Blue/Green Deployments を活用することで、
MySQL の変更のダウンタイムを最小限の影響で実施できる ようになります。
ぜひ試してみてください!🚀

Discussion