使用docker-compose部署MongoDB与PyMongo应用时连接失败排查
问题重现
你尝试用Docker Compose启动搭载MongoDB的Python应用时,遇到了如下连接超时错误:
pymongo.errors.ServerSelectionTimeoutError: localhost:27017: [Errno 111] Connection refused
通过docker ps确认MongoDB容器已正常运行,但连接仍失败。你的docker-compose.yml配置如下:
version: '3.6' services: web: build: . ports: - "5000:5000" - "9000:9000" links: - db db: image: mongo:latest container_name: "mongodb" ports: - 27017:27017 command: mongod --smallfiles # --quiet redis: image: "redis:alpine"
docker ps输出显示容器状态正常:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fb5a00bb8867 composedir_web "python app.py" 20 seconds ago Up 19 seconds 0.0.0.0:5000->5000/tcp, 0.0.0.0:9000->9000/tcp composedir_web_1 56aeae245ad5 mongo:latest "docker-entrypoint.s…" 14 minutes ago Up 20 seconds 0.0.0.0:27017->27017/tcp mongodb 51c64650bab8 redis:alpine "docker-entrypoint.s…" 14 minutes ago Up 21 seconds 6379/tcp composedir_red
问题核心原因
在Docker Compose的内部网络环境中,每个容器都是独立的网络节点——容器内的localhost指向容器自身,而非宿主机或其他容器。你的Python应用代码里应该是用了localhost:27017来连接MongoDB,但这个地址在web容器里只会指向它自己,自然无法访问到db容器的MongoDB服务。
具体解决方案
你只需要做以下调整(两种方案可二选一,也可配合使用):
1. 修改Python代码中的MongoDB连接地址
把连接字符串里的localhost替换为Docker Compose中MongoDB的服务名db,示例代码如下:
# 原错误连接代码 client = pymongo.MongoClient("mongodb://localhost:27017/") # 修改后的正确代码 client = pymongo.MongoClient("mongodb://db:27017/")
Docker Compose会自动在内部网络中解析服务名db到对应的MongoDB容器IP,确保web容器能正常访问到db容器。
2. (可选)优化docker-compose.yml配置
虽然links在新版Docker Compose中已非必需(同一compose文件内的服务默认处于同一网络,可通过服务名互相访问),但你可以添加depends_on来保证web服务在db服务启动后再启动,避免因启动顺序导致的临时连接问题:
version: '3.6' services: web: build: . ports: - "5000:5000" - "9000:9000" depends_on: - db # 确保db容器启动后再启动web容器 # links: -db # 该配置可保留,但非必须 db: image: mongo:latest container_name: "mongodb" ports: - 27017:27017 command: mongod --smallfiles redis: image: "redis:alpine"
注意:depends_on仅保证启动顺序,不保证MongoDB服务完全就绪。如果应用启动过快,仍可能出现连接失败,此时可在应用中添加连接重试逻辑,或使用wait-for-it等工具等待MongoDB服务可用。
验证方法
修改完成后,重新启动服务:
docker-compose down docker-compose up --build
此时你的Python应用应该能正常连接到MongoDB服务了。
内容的提问来源于stack exchange,提问作者0x90

