You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署Flask+MongoDB POST报ServerSelectionTimeoutError

问题描述

开发了对接MongoDB的Flask Web服务,计划将Web服务与MongoDB分别部署在独立Docker容器中。本地直接运行Flask服务连接MongoDB容器时所有功能运行正常,但双容器部署后出现异常:GET请求可正常响应,POST请求执行数据库插入、修改等写操作时会卡顿数秒,最终抛出pymongo.errors.ServerSelectionTimeoutError超时错误。

涉及的代码与配置如下:

Flask服务核心代码

from flask import Flask, request, Response, jsonify
import json
from pymongo import MongoClient
from datetime import date

client = MongoClient("mongodb://localhost:27017")

db=client["DigitalNotes"]
users=db["Users"]
admins=db["Admins"]
notes=db["Notes"]

app=Flask(__name__)


@app.route("/sign_up",methods=["POST"])
def sign_up():
    try:
        data=json.loads(request.data)
    except Exception as e:
        return Response("Bad json content",status=500,mimetype='application/json')
    if data==None:
        return Response("Bad request",status=500,mimetype='application/json')
    if not "email" in data or not "username" in data or not "name" in data or not "password" in data:
        return Response("Information incompleted",status=500,mimetype='application/json')
    
    if users.count_documents({"email":data["email"]})==0 or users.count_documents({"username":data["username"]})==0:
        user = {"email":data["email"],"username":data["username"],"name":data["name"],"password":data["password"]}
        users.insert_one(user)
        return Response(data["username"]+" was added to the DataBase",status=200,mimetype='application/json')
    else:
        return Response("A user with the given username or password already exists",status=200,mimetype='application/json')

Flask服务Dockerfile

FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip3 install flask pymongo
RUN pip3 install datetime
RUN mkdir /app
COPY app.py /app/app.py
EXPOSE 5000
WORKDIR /app
ENTRYPOINT ["python3","-u","app.py"]

docker-compose配置

version: '2'
services:
  mongodb:
    image: mongo
    restart: always
    container_name: mongodb
    ports:
    - 27017:27027
    volumes:
    - ./mongodb/data:/data/db
  flask-service:
    build:
      context: ./flask-service
    restart: always
    container_name: flask
    depends_on:
      - mongodb
    ports:
      - 5000:5000
    environment:
      - "MONGO_HOSTNAME=mongodb"
根因分析
  • 核心错误是数据库连接地址硬编码:Flask代码中写死MongoDB连接地址为localhost:27017,在Docker容器网络环境下,localhost指向Flask容器自身,无法访问同网络下的MongoDB容器。虽然compose中配置了MONGO_HOSTNAME=mongodb的环境变量,但代码未读取该变量。
  • PyMongo的MongoClient是懒连接机制:初始化客户端时不会实际建立数据库连接,只有第一次执行真实IO操作时才会发起连接。如果GET接口未触发实际数据库交互,就不会抛出连接错误,只有执行写操作的POST请求触发真实连接时才会报超时,这就是GET看似正常、POST报错的原因。
  • 配置笔误:MongoDB服务的端口映射写为27017:27027,但MongoDB默认在容器内监听27017端口,该配置会导致宿主机无法通过27017端口访问容器内MongoDB(容器间内部通信不受该配置影响,但属于错误配置需要修正)。
  • depends_on配置仅保证容器启动顺序,不保证MongoDB服务本身处于可连接的就绪状态,可能存在服务启动时序问题,但不是本次超时的核心原因。
修复方案
  1. 修改Flask数据库连接逻辑,读取环境变量中的MongoDB地址,移除硬编码的localhost:
    在代码开头导入os模块,将连接初始化部分修改为:
    import os
    # 优先读取环境变量中的MongoDB地址,本地调试时默认用localhost
    mongo_host = os.getenv("MONGO_HOSTNAME", "localhost")
    client = MongoClient(f"mongodb://{mongo_host}:27017", serverSelectionTimeoutMS=5000)
    
  2. 修正docker-compose.yml中MongoDB的端口映射配置,将错误的- 27017:27027修改为- 27017:27017,保证宿主机可正常访问MongoDB服务。
  3. (可选优化)增加服务就绪检测,避免启动时序问题:
    给mongodb服务增加健康检查配置,同时调整depends_on规则,保证Flask服务在MongoDB可连接后再启动:
    services:
      mongodb:
        # 原有配置保留,新增下面的健康检查
        healthcheck:
          test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')"]
          interval: 5s
          timeout: 3s
          retries: 10
      flask-service:
        # 原有配置保留,修改depends_on规则
        depends_on:
          mongodb:
            condition: service_healthy
    
  4. 重新构建Flask镜像并启动服务,在docker-compose.yml所在目录执行以下命令即可:
    docker-compose down
    docker-compose up -d --build
    

内容的提问来源于stack exchange,提问作者pankal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 06:27:14