[Docker] MongoDB接続がタイムアウトする場合の対処法
目次
追記(2023年10月5日)
私のUbuntuシステム上のDockerがネットワーク接続の問題を起こすことが分かりました。特に、システムがスリープから復帰した後にDockerのブリッジインターフェイスがダウンします。
この問題は、以下のコマンドを使用してシステムのネットワーク設定を確認できます。
参考文献
問題を確認する作業
- ルーティングテーブルの確認:
ルーティングテーブルを確認し、必要なルートが存在しているかどうかを確認します。bash route -n
→Dockerコンテナに割り振っていたmy_networkのIPアドレスが表示されませんでした。 - ネットワークインターフェイスの確認:
各ネットワークインターフェイスの状態を確認し、Dockerのブリッジインターフェイスがアクティブであることを確認します。bash ip addr
→Dockerのブリッジインターフェイスがダウンしていることが確認されました。bash ip addr 1: (省略) 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state **DOWN** group default link/ether ****** 15: br-f94f9f11b616: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state **DOWN** group default link/ether ******
- Dockerブリッジインターフェイスの起動:
Dockerのブリッジインターフェイスがダウンしている場合、以下のコマンドを使用して手動で起動します。bash sudo ip link set docker0 up sudo ip link set br-f94f9f11b616 up
→Dockerのブリッジインターフェイス起動しませんでした。 - システムログの確認:
システムログを確認して、Dockerやネットワーク関連のエラーや警告がないか確認します。dmesg | grep docker
→dmesg
の出力から、いくつかのdocker0
インターフェイスに関連するエントリが表示されました。これらのエントリは、Dockerがコンテナを作成および削除するとき、またはネットワーク設定が変更されたときに生成されます。特に、いくつかのveth
(Virtual Ethernet)デバイスが作成され、状態が変更されていました。これらのveth
デバイスは、ホストシステムとDockerコンテナ間のネットワーク接続を管理するために使用されるそうです。 - Dockerネットワークの確認:
Dockerのネットワーク設定を確認し、カスタムネットワークが正しく設定されていることを確認します。bash docker network ls docker network inspect [your_network_name]
→カスタムネットワークが正しく設定されていることが確認されました。 - Dockerデーモンの状態確認と再起動:
Dockerデーモンの状態を確認し、正常に稼働していることを確認します。bash sudo systemctl status docker
→Dockerデーモンは正常可動しており、これを再起動しても問題は解決しませんでした。
私のケースでは、ルーティングテーブルやネットワークインターフェイスの状態が期待通りでないことが確認されましたが、問題の根本原因はまだ明確には特定できていません。
ワークアラウンド
MongoDBのデータのバックアップを作成する
まず、MongoDBのデータをバックアップします。これは、MongoDBのデータをホストマシンにエクスポートすることで実現できます。
(省略)
続く「カスタムネットワークの削除」をすると、コンテナが起動しなくなるので注意して下さい。
Dockerネットワークの再作成
現在のカスタムネットワークを削除し、新しいネットワークを作成して、コンテナをその新しいネットワークに接続します。
docker network rm my_network
docker network create --driver bridge my_new_network
docker network connect my_new_network my-mongodb-new
$ route -n
カーネルIP経路テーブル
受信先サイト ゲートウェイ ネットマスク フラグ Metric Ref 使用数 インタフェース
(省略)
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-97fa3f93d0bc
192.168.65.0 0.0.0.0 255.255.255.0 U 100 0 0 enp6s0
コンテナとカスタムネットワークを接続する
- 最初に、コンテナを新しいネットワークに接続します:
docker network connect my_new_network my-mongodb-new
- そして、コンテナを起動します:
docker start my-mongodb-new
[追記終わり]
はじめに
Dockerを使用してMongoDBコンテナを構築しました。構築から時間が経つと、接続がタイムアウトする問題に直面しました。
具体的には
client = MongoClient('mongodb://localhost:27019/')
のように、localhost
文字列を使用した場合、接続ができませんでした。(当たり前のような気もしますし、自分でもあいまいです。)
最終的には、以下のように、MongoDBコンテナのIPアドレスを使用することで、接続できるようになりました。
client = MongoClient('mongodb://172.18.0.2:27017/')
この記事では、そのような状況での対処法を詳しく解説します。
注意
Dockerのネットワークについて、本来適切な方法・手順があるかもしれません。この記事では、私が試行錯誤して解決した方法を紹介しています。
Dockerのネットワークについては、日本語のチュートリアルが存在します。以下のチュートリアルを参考にしてください。
環境
pymongoのバージョンは4.5.0です。
>>> import pymongo
>>> print(pymongo.__version__)
4.5.0
dockerのバージョンは24.0.6です。
docker --version
Docker version 24.0.6, build ed223bc
MongoDBのバージョンは7.0.1です。
Mongoshのバージョンは1.10.6です。
NOTE:
Mongosh
はMongoDBの公式シェルです。以前はmongo
コマンドを使用されていましたので、ググると普通にmongo
コマンドを使用した記事が出てきます。mongo
コマンドは非推奨(というかDockerコンテナ内にない)ですので、Mongosh
を使用してください。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6cf444d25f06 mongo "docker-entrypoint.s…" 5 hours ago Up 5 hours 0.0.0.0:27017->27017/tcp, :::27017->27017/tcp my-mongodb
$ docker exec -it my-mongodb mongosh
Current Mongosh Log ID: 651966a2a13f95aebb001e3d
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.10.6
Using MongoDB: 7.0.1
Using Mongosh: 1.10.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
------
The server generated these startup warnings when booting
2023-10-01T07:57:57.556+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
2023-10-01T07:57:58.534+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
2023-10-01T07:57:58.534+00:00: vm.max_map_count is too low
------
test> db.version()
7.0.1
Ubuntuのバージョンは20.04 LTSです。
$ uname -a
Linux terms 5.15.0-84-generic #93~20.04.1-Ubuntu SMP Wed Sep 6 16:15:40 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
MongoDBと繋がらなくなった時、調べるべき手順のリスト
- ufw設定の確認:
sudo ufw status
コマンドを使用して、ホストマシンのファイアウォール設定がMongoDBのポートを許可しているか確認します。 mongosh
コマンドの使用:mongosh
コマンドを使用して手動でMongoDBに接続し、動作を確認します。- MongoDBの設定確認: コンテナ内で
mongod.conf
ファイルを探し、bindIp
オプションが適切に設定されているか確認します。 - ポートマッピングの確認:
docker ps
コマンドで、ホストとコンテナのポートが正しくマッピングされているか確認します。 - Dockerのネットワークモード確認:
docker inspect <コンテナIDまたはコンテナ名> | grep NetworkMode
コマンドで、Dockerコンテナのネットワークモードを確認します。
他に考慮すべき点は、以下の通りです。
- MongoDBのログ確認: MongoDBのログを確認して、エラーメッセージや警告がないかチェックします。
- telnetまたはncでの接続テスト:
telnet
やnc
コマンドを使用して、MongoDBに接続できるかテストします。 - MongoDBのプロセス確認:
ps aux | grep mongod
コマンドで、MongoDBのプロセスが正常に動作しているか確認します。 - Dockerコンテナのリスタート: 問題が解決しない場合、Dockerコンテナをリスタートしてみます。
解法
ホストのファイアーウォール設定
ufw(Uncomplicated Firewall)をファイアウォールとして使用している場合、Dockerはホストマシンのネットワークを使用するため、ufwの設定がDockerコンテナの通信を遮断する可能性があります。
sudo ufw allow from 127.0.0.1 to any port 27019 proto tcp # ローカルホストからの通信だけを許可
この設定により、127.0.0.1(localhost)からの27019ポートへのTCP通信だけが許可されます。
設定が完了したら、ufwの設定を再読み込みして有効にしてください。
sudo ufw reload
そして、sudo ufw status
で設定が反映されているか確認してください。
sudo ufw status
状態: アクティブ
To Action From
-- ------ ----
(省略)
27019/tcp ALLOW 127.0.0.1
mongosh
コマンドの使用
mongosh
コマンドを使用して、手動でMongoDBに接続し、動作を確認します。
docker exec -it my-mongodb mongosh
Current Mongosh Log ID: 6519285a2cf91dd0da5bb580
Connecting to: mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+1.10.6
Using MongoDB: 7.0.1
Using Mongosh: 1.10.6
For mongosh info see: https://docs.mongodb.com/mongodb-shell/
To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).
You can opt-out by running the disableTelemetry() command.
------
The server generated these startup warnings when booting
2023-10-01T07:57:57.556+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
2023-10-01T07:57:58.534+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
2023-10-01T07:57:58.534+00:00: vm.max_map_count is too low
------
test> exit
MongoDBの設定確認
設定ファイルの確認: MongoDBの設定ファイル(通常はmongod.conf
)で、bindIp
オプションが適切に設定されているか確認します。
mongod.conf
ファイルで、どのIPアドレスからの接続を許可するかが制限されていないか確認するのですが、Docker内にはmongod.conf.orig
ファイルはあるものの、mongod.conf
ファイルはありませんでした。
このように設定ファイルがない場合、ps aux | grep mongod
で確認を行います。
docker exec -it mongodb-1 /bin/bash
root@b87f6a0ab623:/# ps aux | grep mongod
mongodb 1 0.3 0.9 2666480 149804 ? Ssl 08:18 0:37 mongod --bind_ip_all
root 80 0.0 0.0 3468 1640 pts/0 S+ 11:00 0:00 grep mongod
この出力から、MongoDBは--bind_ip_all
オプションで起動していることがわかります。このオプションは、MongoDBがすべてのIPアドレスからの接続を許可するように設定されていることを意味します。この設定はセキュリティ上のリスクがありますが、今回のように、ローカルネットワーク内での使用やテスト環境であれば問題ない場合もあります。
Dockerのネットワーク
Dockerにユーザー定義のネットワーク(my_network)を作成します。
NOTE:
本来ならbridge
から接続できるはずですが、この環境ではbridge
へ接続できませんでした。
docker network create my_network
ネットワークが作成されたら、新しいコンテナを作成する際や既存のコンテナを起動する際に、--network
オプションを使用してこのネットワークに接続できます。
既存のコンテナに新しいネットワークを接続するには、以下のコマンドを使用します。
docker network connect my_network my-mongodb
このコマンドで、my-mongodb
という名前のコンテナがmy_network
というネットワークに接続されます。
docker network inspect my_network
コマンドを使用して、my_network
という名前のネットワークの詳細情報を表示できます。このコマンドの出力には、そのネットワークに接続されているすべてのコンテナとそのIPアドレスが含まれます。
コマンドを実行すると、以下のような形式で情報が表示されるはずです。
$ docker network inspect my_network
[
{
"Name": "my_network",
"Id": "8672d61a39617cd6388c42dad055528e1f1d049d90b9b59b0af98010db79806c",
"Created": "2023-10-01T14:43:54.96084477+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"6cf444d25f06f338d16160cd143ff3437ea1a2447305d4a903a0a415b3b57c36": {
"Name": "my-mongodb",
"EndpointID": "189238e17c2cf137b7a325ccb9d917d0daa32f6f09fec178d120ca0bdd3aa0f9",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16", # この行が重要
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
Dockerネットワークの情報から、MongoDBコンテナ(my-mongodb
)のIPv4アドレスが172.18.0.2
であることがわかります。この情報を使用して、PythonからMongoDBに接続できます。
Pythonインタラクティブシェルで以下のコードを実行します。
from pymongo import MongoClient
# MongoDBコンテナのIPアドレスとポートを使用して接続
client = MongoClient('mongodb://172.18.0.2:27017/')
print(client.list_database_names())
この設定でPythonがMongoDBに接続できました。
Pythonのインタラクティブシェルでは、以下のように接続を確認できます。
>>> from pymongo import MongoClient
>>> client = MongoClient('mongodb://172.18.0.2:27017/')
>>> print(client.list_database_names())
['admin', 'config', 'local', 'my_database']
>>>
まとめ
この記事では、Dockerを使用して構築したMongoDBコンテナとの接続がタイムアウトする問題に対する対処法を詳細に解説しました。ufwの設定、mongosh
の使用、MongoDBの設定確認、Dockerのネットワーク設定など、多角的な視点から問題を解決する方法を模索しました。
また、docker network inspect
コマンドを使用して、コンテナの内部IPアドレスを確認することで、Pythonからの接続もスムーズに行えました。
Dockerのユーザー定義ネットワークを作成して、そのネットワークにMongoDBコンテナを接続する方法は、本来の運用(設定)方法とは違うかもしれません。その点はご留意下さい。
何らかの接続問題に直面した際には、この記事が皆さんの参考になれば幸いです。
以上です。ありがとうございました。