Flask应用连接MongoDB失败求助(Docker-Compose环境)
问题详情
执行Flask应用的GET/POST请求时遇到以下错误:
mongo:27017: [Errno -2] Name does not resolve (configured timeouts:
socketTimeoutMS: 20000.0ms, connectTimeoutMS: 20000.0ms), Timeout:
30s, Topology Description: <TopologyDescription id:
657c619ae1e4696f65e708c2, topology_type: Unknown, servers:
[<ServerDescription ('mongo', 27017) server_type: Unknown, rtt: None,
error=AutoReconnect('mongo:27017: [Errno -2] Name does not resolve
(configured timeouts: socketTimeoutMS: 20000.0ms, connectTimeoutMS:
20000.0ms)')>]>
相关代码
app.py
from flask import Flask, jsonify from pymongo import MongoClient from loguru import logger from bson.json_util import dumps app = Flask(__name__) MONGO_URI = "mongodb://admin:admin@mongo:27017/" @app.route('/', methods=['GET']) def get_data(): try: logger.info('Connecting to MongoDB') client = MongoClient(MONGO_URI) logger.info('Connected to MongoDB') db = client.test collection = db.test data = collection.find({}) serialized_data = dumps(data) logger.info('Data retrieved successfully') return jsonify({"data": serialized_data}), 200 except Exception as e: return jsonify({"error": f"{str(e)}"}), 500 @app.route('/', methods=['POST']) def create_data(): try: logger.info('Connecting to MongoDB') client = MongoClient(MONGO_URI) logger.info('Connected to MongoDB') db = client.test collection = db.test data = collection.insert_one({"name": "test"}) logger.info('Data created successfully') return jsonify({"data": data}), 200 except Exception as e: return jsonify({"error": f"{str(e)}"}), 500 if __name__ == '__main__': app.run(host='0.0.0.0')
docker-compose.yml
version: '3.9' services: web: build: context: . dockerfile: Dockerfile ports: - "5000:5000" depends_on: - mongodb - nginx nginx: image: nginx:latest ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro mongodb: image: mongo:latest ports: - "27017:27017" environment: - MONGO_INITDB_DATABASE=test - MONGO_INITDB_ROOT_USERNAME=admin - MONGO_INITDB_ROOT_PASSWORD=admin - MONGO_URI=mongodb://admin:admin@mongodb:27017/test volumes: - mongodb_data:/data/db volumes: mongodb_data:
用户疑问:日志显示请求已执行到连接代码行,但仍出现连接错误,该如何解决?
解决步骤
1. 修正MongoDB主机名
Docker容器间通信依赖服务名作为主机名,docker-compose中MongoDB服务的名称是mongodb,但app.py里的MONGO_URI用的是mongo,两者不匹配导致DNS解析失败。修改app.py中的MONGO_URI:
MONGO_URI = "mongodb://admin:admin@mongodb:27017/"
2. 修复连接日志的误导性
PyMongo的MongoClient初始化时不会立即建立连接,只有执行数据库操作(如find()、insert_one())时才会真正尝试连接,所以你看到的logger.info('Connected to MongoDB')并不代表连接成功。可以添加连接验证步骤,提前捕获错误:
client = MongoClient(MONGO_URI) # 主动验证连接 client.admin.command('ping') logger.info('Connected to MongoDB')
3. 确保MongoDB服务就绪后启动web服务
depends_on仅保证容器启动顺序,不保证MongoDB服务完全就绪。可以给mongodb服务添加健康检查,确保服务可用后再启动web服务:
在docker-compose的mongodb服务中添加:
healthcheck: test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] interval: 5s timeout: 5s retries: 5
同时修改web服务的depends_on配置:
depends_on: mongodb: condition: service_healthy nginx: condition: service_started
4. 统一环境变量(可选优化)
将MONGO_URI放到docker-compose的web服务环境变量中,避免代码硬编码:
在web服务下添加:
environment: - MONGO_URI=mongodb://admin:admin@mongodb:27017/
然后app.py中读取环境变量:
import os MONGO_URI = os.getenv("MONGO_URI", "mongodb://admin:admin@mongodb:27017/")
内容的提问来源于stack exchange,提问作者Louis

