運用寄りの話。
以前、AWS Database Specialtyの本にRDSのエンドポイントをRoute53のドメインで振り分けるみたいな記述があったのをふと思い出しました。これをAuroraのエンドポイントでTerraformのサンプルを交えて、クライアントによって動作が異なることを検証したいと思います。
記事の後半ではNestJS、Laravel、Laravel Octaneが出てきます。
AuroraとRoute53のTerraform
必要最低限で書いているのでVPCはIDを入力する形としてます。上記を実行すると設定値通りのプライベートドメイン、Auroraが出来ているはずです。
EC2のセットアップ
EC2インスタンスを作成します。あえてTerraformに書きませんでした。先日見つけた記事でRDS/Aurora - EC2インスタンス間の連携が簡単になったらしいのでついでに試してみたかったのです。
まず、RDSの画面から「EC2 接続のセットアップ」を選択します。
EC2を選択する画面が表示されるので新しくEC2を作成します。あとでRDS側で設定するのでセキュリティグループはAuroraに繋がっていないものを選択します。
ログインできる鍵が設定できていれば基本的に全部デフォルト値でOKです。
EC2がRunningになるとRDS側で作成したばかりのEC2が選択できるようになっていました。
進めていくとEC2インスタンスにAuroraを接続するためのセキュリティグループが設定されます。
EC2からRDSの疎通確認
EC2にログイン出来たらいよいよAuroraに接続します。まずは必要なものをインストールします。
sudo yum update -y
sudo yum install -y mysql
そしてプライベートドメインでAuroraに接続します。ターミナルを別タブで2つ開いておくと便利です。各タブでそれぞれ、
mysql -uadmin -p --host reader.aurora-private.com
mysql -uadmin -p --host writer.aurora-private.com
一応、Readerの方でCREATE TABLEができないことを確認します。
MySQL [demo]> create table hoge(id varchar(10));
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
Writerの方ではどうでしょう。
MySQL [demo]> create table hoge(id varchar(10));
Query OK, 0 rows affected (0.04 sec)
成功しました。ここまでは順調です。
Webアプリが稼働してる中で接続先を切り替える
ここからが本題です。起動時にデータベースのコネクションを張るWebアプリの場合、途中で接続先を変えるとどうなるのかを試してみます。
長くなるのでコードは省略しますが、NestJSをインストールし、TypeORMからAuroraのデータを取得するだけのAPIを用意しました。接続先のエンドポイントはもちろんwriter.aurora-private.comです。
[ec2-user@ip-192-168-2-240 ~]$ curl http://localhost:3000
[{"id":1,"name":"hello world!"}]
↑Auroraから取得したデータが表示されています。
分かりやすくRoute53からWriterのエンドポイントを削除します。検証なので思い切ったことができるのが強みです。
結果は、
[ec2-user@ip-192-168-2-240 project-name]$ curl http://localhost:3000
[{"id":1,"name":"hello world!"}][
コネクションが切れませんでした。しかし実際にはプライベートドメインはもう消えているので再接続(NestJSを再起動)すると繋がりません。
> nest start
[Nest] 5056 - 2022/10/28 7:28:36 LOG [NestFactory] Starting Nest application...
[Nest] 5056 - 2022/10/28 7:28:36 LOG [InstanceLoader] TypeOrmModule dependencies initialized +104ms
[Nest] 5056 - 2022/10/28 7:28:36 ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)...
Error: getaddrinfo ENOTFOUND writer.aurora-private.com
at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:109:26)
次にPHP(Laravel)で同じことをやってみます。先ほど削除したWriterエンドポイントを再度登録してAuroraからデータを取得します。
curl http://localhost
[{"id":1,"name":"hello world!"}]
そしてRoute53からWriterを削除します。数十秒くらいcurlを連打していたところ、途中で名前解決ができなくなってエラーになりました。
Illuminate\Database\QueryException: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
数十秒というのは先ほどのTerraformで指定していますがTTL 20秒と設定していたためその時間に依存していると思われます。300秒にするとしばらく繋がったので。
次にLaravel Octaneで同様のことをやってみましたが、20分ほどcurlで叩いても接続は維持されたままでした。
[{"id":1,"name":"hello world!"}]
そして./artisan octane:reloadやプロセス停止&開始を何回やっても接続は切れませんでした。これは予想してなかったのでなかなか興味深いです🤔🤔
ちなみにLaravel OctaneはDocker上で動作させていますが、ホスト側でWriterにnslookupしてみるとちゃんとエラーになってます。
nslookup writer.aurora-private.com
Server: 192.168.0.2
Address: 192.168.0.2#53
** server can't find writer.aurora-private.com: NXDOMAIN
やや強引ですがコンテナを再起動するとちゃんとエラーになってくれました。キャッシュといえばそれまでですが、Octaneを使う際にはもう少し調査したいところです。
root@0e92476e0f2c:/var/www/laravel_docker# ./artisan octane:start
INFO Server running…
Local: http://127.0.0.1:8000
Press Ctrl+C to stop the server
500 GET /
今回はNestJS、Laravel、Laravel Octaneと3つを試してみましたが、思っていたより違いが出たので検証して良かったです。
まとめ
IaCで構築すればRoute53の設定は簡単なので一考の余地ありそうです。ただ、導入の有無に関わらず前述のように接続するクライアントアプリケーションの実装・挙動を正しく理解したいところです。クライアントのコネクションもそうですが、接続情報はコンテナの起動時に環境変数に渡されたり、Secrets Manager等から都度読んだりするかによっても変わってきます。長くなったのでこの辺で。
そういえばReaderを作ったものの今回は使いませんでした。何かもっと実運用に近いことをやるつもりが開発者寄りの話に外れてしまい。。😇
DB周りの構築・運用はインフラ側と開発側の両方の知見がないとトラブルの元、というお話でした。