NLB経由でAmazon DocumentDBに接続する方法を検証しました
モバイルアプリサービス部の五十嵐です。
今年は GraphQL + MongoDB + TypeScript なスタックを広めていきたいと思っていた矢先、AWSからMongoDB互換のデータベースサービス Amazon DocumentDB(以下、DocumentDBと書きます) が発表されてめちゃくちゃテンション上がりました!!
New – Amazon DocumentDB (with MongoDB Compatibility): Fast, Scalable, and Highly Available
DocumentDB(MongoDB)を利用したいケースとしては、Lambdaを利用したサーバーレスアプリケーションのデータストアとして利用している DynamoDB + Elasticsearch Service(より具体的には DynamoDB → DynamoDB Streams → Lmabda → Elasticsearch Serviceの組み合わせ)を、DocumentDB(MongoDB)に置き換えたいという場合も多いのではないでしょうか。その場合、DocumentDBは現在パブリックエンドポイントをサポートしていないため、Lambda を Lambda in VPC にしてVPC経由で接続するという方法もありますが、Lambda in VPCの考慮事項(起動速度やプライベートIPの枯渇など)を踏まえるとアプリケーションの特性によってはインターネット経由で接続できたほうが望ましい場合もあります。そこで、NLB経由でDocumentDBに接続する方法を検証しました。
ちなみに公式のドキュメントではSSHトンネルを使用できますとあります。オペレーション用でしたらこれで十分なのですが、アプリケーションから接続する場合は踏み台となるインスタンス(EC2など)がボトルネックとなるため、NLBの方が望ましいと考えました。
Amazon DocumentDB のトラブルシューティング
Amazon DocumentDB は仮想プライベートクラウド (VPC) 専用で、パブリックエンドポイントを現在サポートしていません。そのため、VPC の外部から Amazon DocumentDB クラスターに直接接続することはできません。 VPC の外部から Amazon DocumentDB クラスターに接続するには、SSH トンネルを使用できます。詳細については、「Amazon VPC 外部からの Amazon DocumentDB クラスターへの接続」を参照してください。
検証
Clusterの作成~接続確認
まずはDocumentDBのClusterを作成し、VPC内のEC2から接続できることを確認します。
Clusterの作成手順は誰かが書くことを期待して割愛します。
Clusterの準備ができたらEC2(Amazon Linux)にsshしてターミナルに接続します。
こちらの手順に従い、mongo shellをインストールし、CAの公開鍵をダウンロードして、DocumentDBに接続できることを確認します。
ステップ 3: mongo シェルを使用して Amazon DocumentDB クラスターにアクセスする
$ sudo vim /etc/yum.repos.d/mongodb-org-3.6.repo ### ここから [mongodb-org-3.6] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.6/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc ### ここまでを書き込み保存する $ sudo yum install -y mongodb-org-shell $ mongo --version MongoDB shell version v3.6.9 $ wget https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem $ mongo --ssl --host [DocumentDBのClusterのドメイン]:27017 --sslCAFile rds-combined-ca-bundle.pem --username [ユーザ名] --password [パスワード] MongoDB shell version v3.6.9 connecting to: mongodb:/[DocumentDBのClusterのドメイン]:27017/ Implicit session: session { "id" : UUID("20edbd71-b327-4d8f-8479-5810b263551c") } MongoDB server version: 3.6.0 rs0:PRIMARY>
コンソールが表示されたら接続成功です。
接続できない場合はSecurityGroupの設定などを確認してみてください。トラブルシューティングのドキュメントもあります。
Amazon DocumentDB のトラブルシューティング
SSH トンネルを使用した接続
せっかくなのでSSHトンネルを使用した接続を試してみましょう。
いま、先ほど使用したEC2のホスト名をworkとして、sshで接続できる状態になっています。 そして、workを踏み台にしてDocumentDBに接続できる状態にします。
$ ssh -F ~/.ssh/ssh_hosts work -Nf -L 27017:[DocumentDBのClusterのドメイン]:27017
これで、ローカル(localhost)の27017ポートを、リモート(work)の27017ポートに転送する状態になります。
Macにmongo shellがインストールされていない場合は、こちらの手順に従ってインストールします。
Install MongoDB Community Edition on macOS — MongoDB Manual
そして、mongo shellでホストをlocalhostにして接続します。注意点としては、公開鍵に署名されているホスト名が接続先のホスト名(localhost?work?)と不一致になってしまうため、ホスト名を検証しない --sslAllowInvalidHostnames
オプションが必要になります。
$ mongo --ssl --host localhost:27017 --sslCAFile rds-combined-ca-bundle.pem --username root --password password --sslAllowInvalidHostnames
コンソールが表示されたら接続成功です。
ここではmongo shellで接続しましたが、MongoDB CompassというMongoDBのクライアントアプリケーションでもSSHトンネルで接続できました。
NLBを使用した接続
それでは、本題のNLBを使用した接続を試してみましょう。
大まかな流れは以下のとおりです。
- DocumentDBのSecurityGroupにNLBを配置するサブネットからのアクセス許可を追加する
- DocumentDBのインスタンスのプライベートIPをターゲットとするTargetGroupを作成する
- NLBを作成してTargetGroupをアタッチする
- NLBのヘルスチェックが通れば準備完了
具体的には以下のリソースを作成します。
ターゲットグループの作成
- ターゲットグループ名: 任意
- ターゲットの種類: IP
- プロトコル: TCP
- ポート: 27017
- VPC: 任意
- ヘルスチェック: TCP
ターゲットグループにターゲットを追加
- ネットワーク: 任意のVPC
- IP: ターゲットのIP(DocumentDBのインスタンスのプライベートIP)
- ポート: 27017
ロードバランサ(Network Load Balancer)の作成
- 名前: 任意
- スキーム: インターネット向け
- リスナー: TCP 27017
- アベイラビリティゾーン: 任意(※DocumentDBのインスタンスと同じAZを含める!!)
- ターゲットグループ: 既存のターゲットグループから先ほど作成したターゲットグループを選択
接続するためのCAの公開鍵も先ほどのEC2(work)から取得します。
$ scp -F ~/.ssh/ssh_hosts work:/home/ec2-user/rds-combined-ca-bundle.pem ~/.ssh/ $ chmod 400 ~/.ssh/rds-combined-ca-bundle.pem
NLBのドメインを指定してDocumentDBに接続します。--sslAllowInvalidHostnames
オプションが必要な点はSSHトンネルの場合と同じです。
$ mongo --ssl --host [NLBのドメイン]:27017 --sslCAFile ~/.ssh/rds-combined-ca-bundle.pem --username root --password password --sslAllowInvalidHostnames
コンソールが表示されたら接続成功です。
2019/01/16 追記
ただしこの方法では、プライベートIPが変わると疎通できなくなること、エンドポイントがインターネットに露出してしまうためセキュアではないこと、などの問題点がありますのでご留意ください。
おわりに
本記事では、インターネット(NLB)経由でDocumentDBに接続できることを確認できました。次はLambdaからmongodbのクライアントライブラリを使ってインターネット経由で接続する方法を試してみたいと思います。