この記事はBeeX Advent Calendar 2024の10日目の記事です。
はじめに
外部クライアントからEC2で動作するMongoDBレプリカセットに接続する際、接続が上手くできずハマってしまいました。
今回は解消方法と、調査過程でわかったことを書いてみようと思います。
困っていたこと
コマンドライン上でMongoSh、あるいはGUIツール「MongoDBCompass」を使用して、MongoDBへのアクセスを試みました。
その際下記コマンドで複数ホスト名を指定すると接続できない事象が発生しました。
mongosh "mongodb://<ユーザ名>:<パスワード>@XXX.XXX.XXX.XXX:28017,@XXX.XXX.XXX.XXX:28018,@XXX.XXX.XXX.XXX:28019/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
ただし、下記コマンドで単一ホストを指定すると接続が可能でした。
- Mongoshの場合(directConnection指定なし)
mongosh "mongodb://<ユーザ名>:<パスワード>@XXX.XXX.XXX.XXX:28017/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false"
- MongoDBCompassの場合(directConnection=true)
"mongodb://<ユーザ名>:<パスワード>@XXX.XXX.XXX.XXX:28017/?replicaSet=rs0&readPreference=secondaryPreferred&retryWrites=false&directConnection=true"
結論
原因は「レプリカセット構築時のメンバーホスト名」がよろしくなかったようです。
今回私が構築した際は、3プロセスともに「localhost」を指定していました。
rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "localhost:28017"},{_id: 1, host: "localhost:28018"},{_id: 2,host:"localhost:28019"}]})
おそらく外部ホストから接続する際「directConnection=false」だと、接続URIの情報ではなく、レプリカセット内のホスト名を参照してしまい、その際「localhost」が指定されているとクライアント自身のlocalhostを参照してしまうのではないかと思われます。
警告
この辺は憶測のため、もし詳しい方がいればコメント欄で教えていただけますと幸いです。
修正方法としては、下記2パターンです。
-
レプリカセット構築時(rs.initate)に「EC2のIPアドレス」を指定して作成
-
ホスト名を「localhost」から「EC2のIPアドレス」に変更
今回は既にレプリカセットを構築しているので、2.変更のパターンで修正してみます。
修正方法
レプリカセットの修正方法は少し癖があります。
-
現状の設定を確認
$ config = rs.config
-
設定の変更
$ config.members[0].host = 'EC2のIPアドレス:port' $ config.members[1].host = 'EC2のIPアドレス:port' $ config.members[2].host = 'EC2のIPアドレス:port'
-
設定の反映
$ rs.reconfig(config)
-
設定が反映されているか確認
$ rs.conf
修正後はホスト名複数指定しても外部クライアントから接続可能になります。
※もちろん単一ホストだけの接続も可能です。
調査の過程でわかったこと
mongoshで接続する際に単一ホスト名を指定すると「directConnection=true」になる
公式ドキュメントによるとmongoshは以下の条件にあてはまらない場合に「directConnection=true」パラメータを自動で追加するようです。
- 接続文字列に replicaSet クエリパラメーターが存在する
- 接続文字列が mongodb+srv:// 接続文字列フォーマットを使用している
- 接続文字列に複数のホストを含むシードリストが含まれている
- 接続文字列に directConnection パラメーターが既に含まれている
directConnection=true の場合、すべての操作は接続 URI で指定されたホスト上で実行されます。
そのため、コマンドライン上からMongoShellで「directConnection=true」指定なしで接続できたのも、
MongoShell側で勝手に「directConnection=true」を追加してくれたことによるものでした。
おわりに
MongoDBレプリカセット構築時にはまったポイントを今回はまとめました。
読み取り設定やレプリカセットの選挙など、まだ整理したいことがあるので、今後も時間があればMongoDBの勉強は続けていきたいと思います。
この記事が誰かの参考になれば幸いです