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

Docker容器内无法连接主机本地MongoDB的问题求助

问题背景
  • 环境:Ubuntu 22.04,Docker容器内的Python脚本需连接主机localhost上的MongoDB实例
  • 主机配置:NGINX将27020端口流量转发至MongoDB默认的27017端口
  • 异常现象:
    • 本地运行脚本(用localhost)可正常连接MongoDB
    • Docker Compose指定27020端口能正常连接
    • 容器内用host.docker.internal:27020时,nc命令能连通端口、请求NGINX能获取正常响应,但无法连接MongoDB
    • 仅host网络模式可行,需非host模式的解决方案

相关文件

Dockerfile

FROM ubuntu
RUN apt-get update
RUN apt-get install curl pip micro netcat -y
COPY requirements.txt app/requirements.txt

WORKDIR /app

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

COPY . /app

requirements.txt

fastapi==0.85.1
uvicorn==0.19.0
motor==3.1.0dev
black==22.10.0
python-dotenv==0.21.0 
orjson==3.8.0
requests==2.28.1

mongodb.py

import asyncio
import requests
from motor.motor_asyncio import (
    AsyncIOMotorClient,
    AsyncIOMotorCollection,
)

from bson.codec_options import DEFAULT_CODEC_OPTIONS

def get_collection(
) -> AsyncIOMotorCollection:
    # 设置时区感知的日期返回选项
    options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True)

    motor_client = AsyncIOMotorClient(
        "mongodb://usr:pwd@host.docker.internal:27020/?authSource=admin&replicaSet=Replica1"
    )
    database = motor_client["DBNAME"]
    # 应用时区感知选项
    return database.get_collection(collName, codec_options=options)

async def main():
    coll = get_collection()
    response=requests.get('http://host.docker.internal')
    print(response.text)
    async for doc in coll.find({}).limit(10):
        print(doc)

if __name__ == "__main__":
    try:
        asyncio.run(
            main()
        )
    except KeyboardInterrupt:
        pass

容器构建与运行命令

docker build -t test_motor .    
docker run -it --add-host host.docker.internal:host-gateway test_motor  bash

解决方案

1. 修复NGINX的TCP转发配置

MongoDB基于TCP协议通信,不能用HTTP的proxy_pass配置转发。需改用NGINX的stream模块:

stream {
    server {
        listen 27020;
        proxy_pass localhost:27017;
        proxy_timeout 30s;
        proxy_connect_timeout 5s;
    }
}
  • 验证NGINX是否启用stream模块:执行nginx -V,查看输出是否包含--with-stream
  • 重启NGINX生效:sudo systemctl restart nginx

2. 修改MongoDB监听地址

主机MongoDB默认仅监听localhost,容器通过host.docker.internal访问时会被拒绝。修改/etc/mongod.conf:

net:
  bindIp: 127.0.0.1,172.17.0.1  # 172.17.0.1是Docker默认网桥的网关IP

测试环境可临时设置为0.0.0.0(生产环境不推荐),然后重启MongoDB:

sudo systemctl restart mongod

3. 调整MongoDB副本集配置

连接字符串指定了replicaSet=Replica1,若副本集节点配置的是localhost,容器内会解析为自身的localhost导致连接失败。需将副本集节点地址改为主机局域网IP:

  1. 进入MongoDB Shell:mongosh
  2. 切换到admin库并认证:
    use admin
    db.auth("usr", "pwd")
    
  3. 修改副本集配置:
    var cfg = rs.conf();
    cfg.members[0].host = "192.168.x.x:27017";  // 替换为主机实际局域网IP
    rs.reconfig(cfg);
    

4. 直接映射MongoDB端口替代NGINX转发

跳过NGINX,直接将主机27017端口映射给容器,脚本连接地址改为host.docker.internal:27017:

docker run -it --add-host host.docker.internal:host-gateway -p 27017:27017 test_motor bash

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:31:07