クラシマです。
弊社、AWSさんからスタートアップ支援としてアドバイスを受ける機会を定期的に作っていただいており、直近では主にコスト面やセキュリティ面について、アーキテクチャ図を見ながらご提案をいただいています。 使っていないときは止める、SavingsPlansやリザーブドインスタンスで前払い、などのご提案とともに、Graviton2インスタンスへの切り替えも提案いただきました。
Graviton2移行、いつかやりたい!と思っていたのですが、折よくMySQL8.0互換のAurora MySQL v3が登場しまして。さらに、AWSさんからAuroraのパッチバージョンを上げるよう通知もとんできました。ついでだし、この機会にやってやろう!と年末からstg環境に適用して検証を開始しました。
事前検証
terraformでengine_version書き換えてapplyすればOKでしょ!と軽く考えておりましたが、さすがにメジャーバージョンアップなのでクラスタから作り直さないとダメでした...。 インスタンス->クラスタの順に削除して、再度terraform applyし、事前にmysqldumpで取得しておいたSQLを流し込んで完了です。 さらに、パラメータグループもv2とは別になるため、新規に作成する必要があります。当然ながらMySQL 8.0用の設定に変更しなければなりません。ただ、弊社はローカル開発用およびCI用のdocker環境でMySQL8.0を使用してきており、特段の不具合が発生していなかったため、v2時のパラメータグループのデフォルトからの変更内容そのまま引き継いでおります。
作業検証の結果、サービスダウンが避けられないことがわかり、業務部門と相談して移行日に決定しました。
さらに、どうせサービス停止するなら、と以下もまとめて実施することにしました。
- RDSインスタンスをGraviton2化
- OpenSearchインスタンスをGraviton2化 -> Elasticsearchバージョン7.9以上のみ対応なのでこちらも上げる
- OpenSearchクラスタをシングルAZ->マルチAZに変更
- ElastiCache redisノードをGraviton2化
いずれも、stg環境で作業内容を検証、移行手順書を作成します。 弊社、本番DBでDDLやUPDATE/INSERT/DELETEなどを実行する場合はSQLレビューというGitHub Issueを立てて承認を得るようにしていたのですが、手順書レビューというIssueテンプレートを作って同じ運用に乗せるようにしました。

移行当日
まずはOpenSearchから作業を開始します。 と言ってもterraform applyするだけでしょ、とのんきに構えていた@watarukuraを待ち受けていたのは、applyエラーでした。
│ Error: InvalidTypeException: Invalid instance type: m6g.large.elasticsearch │ │ with module.prd.module.base.module.search.aws_elasticsearch_domain.search, │ on modules/search/aws.tf line 10, in resource "aws_elasticsearch_domain" "search": │ 10: resource "aws_elasticsearch_domain" "search" {
OpenSearchを運用されてる方ならお気づきかもしれません。Elasticsearchバージョンを上げてからでないとインスタンスタイプは変更できないのでした...。ということで2回に分けて実行します。 OpenSearch、とても良いサービスなのですがBlue/Greenデプロイメントのたびに結構な待ち時間が発生します...。1時間の想定だった作業は2時間かかりました。
ElastiCacheは流石になにもないでしょ、と想定しておりましたが、terraform applyが成功したのにノードのインスタンスタイプが変わりません。 マネジメントコンソールから変更したのと同様に、「変更の即時反映」が必要でした...。
最後に本命のAuroraです。 本番からまずはデータをExportします。更新が入らないようにapiサーバもbatchサーバも停止済みです。 ところが、全くExportが終わる気配がありません。JSON型で変更履歴を保持しているテーブルのサイズが大きく、Export完了に40時間くらいかかりそうと判明。 まだ諦めるには早いので、スナップショットを指定してインスタンスを作成するようにterraformを修正します。 最新のスナップショットを指定して再度plan、通ったのでapply。よしよし、と25分ほど待ったところでエラーが出ました。
│ Error: error creating RDS Cluster (madras-db-prd) Instance: InvalidParameterCombination: You can't create a DB instance using the instance class db.r6g.large in the DB cluster madras-db-prd. For the cluster's initial instance, use an instance class other than the AWS Graviton2 instance classes.
??? しゃーねーなーとマネジメントコンソールから作成しようと試みますが、同じエラーメッセージが出ます。 Aurora MySQL v3のクラスタ自体は作成できているのですが、r6gインスタンスを追加しようとするとエラーになる様子。 公式ドキュメントを読んでも挙動がよくわからなかったので、AWSサポートに投げてみます。 エラーメッセージを読んで、クラスタの最初のインスタンスがGraviton2だとダメよ、って話なのかと思い、r5インスタンスでクラスタを再作成したあとでインスタンスを削除してr6gインスタンスを追加してもやはりダメ。
はてさて...。 業務部門と約束したサービス停止時間はとうに過ぎており、何度か「もうちょっとかかります」とSlackで伝えています。 諦めて、今まで使っていたr5インスタンスを使うことにしました。 無事に起動を確認、止めていたapiサーバとbatchサーバを稼働させて、サービス再開を確認し、業務部門へ通知します。
その後
OpenSearch、ElastiCacheについては、特段の問題なく動作しています。コストも削減できました。 Auroraについては、なぜか一部のバッチ処理でINSERTの動作が遅くなり、処理時間が長くなるという影響が出たため調査中です。 個人的に、AuroraでCTEやウィンドウ関数が使えるようになったのでホクホクです。
AWSサポートからの回答では、AWS CLI の restore-db-cluster-from-snapshot および create-db-instance を試してほしいとのこと。ただ、これでは再度サービス停止してしまいます。 ↓こちらを読む限り、Graviton2インスタンスを後から追加してフェイルオーバーすればイケそう?1分位サービス断が発生しますが、近日中に試して見る予定です。
まとめに代えて教訓
- 一度にまとめて色々やっつけようとしないようにしましょう
- サービス停止時間は事前に検証環境で十分検証の上、余裕を持って見積もりましょう