【问题标题】:MongoDB docker replica set connection error "Host not found"MongoDB docker副本集连接错误“找不到主机”
【发布时间】:2021-10-10 22:53:03
【问题描述】:

我在this SO answer 之后创建了一个本地 MongoDB 副本集。

docker-compose 文件:

services:
  mongo1:
    container_name: mongo1
    image: mongo:4.2
    ports:
      - 27017:27017
    restart: always
    command: ["--bind_ip_all", "--replSet", "rs" ]
  mongo2:
    container_name: mongo2
    image: mongo:4.2
    ports:
      - 27018:27017
    restart: always
    command: ["--bind_ip_all", "--replSet", "rs" ]
  mongo3:
    container_name: mongo3
    image: mongo:4.2
    ports:
      - 27019:27017
    restart: always
    command: ["--bind_ip_all", "--replSet", "rs" ]
  replica_set:
    image: mongo:4.2
    container_name: replica_set
    depends_on:
      - mongo1
      - mongo2
      - mongo3
    volume:
      - ./initiate_replica_set.sh:/initiate_replica_set.sh
    entrypoint: 
      - /initiate_replica_set.sh

initial_replica_set.sh 文件:

#!/bin/bash

echo "Starting replica set initialize"
until mongo --host mongo1 --eval "print(\"waited for connection\")"
do
    sleep 2
done
echo "Connection finished"
echo "Creating replica set"
mongo --host mongo1 <<EOF
rs.initiate(
  {
    _id : 'rs0',
    members: [
      { _id : 0, host : "mongo1:27017" },
      { _id : 1, host : "mongo2:27017" },
      { _id : 2, host : "mongo3:27017" }
    ]
  }
)
EOF
echo "replica set created"

副本集启动成功,运行正常,但尝试连接副本集时出错:

$ mongo "mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs"
MongoDB shell version v5.0.2
connecting to: mongodb://localhost:27017,localhost:27018,localhost:27019/?compressors=disabled&gssapiServiceName=mongodb&replicaSet=rs
{"t":{"$date":"2021-08-05T21:35:40.667Z"},"s":"I",  "c":"NETWORK",  "id":4333208, "ctx":"ReplicaSetMonitor-TaskExecutor","msg":"RSM host selection timeout","attr":{"replicaSet":"rs","error":"FailedToSatisfyReadPreference: Could not find host matching read preference { mode: \"nearest\" } for set rs"}}
Error: Could not find host matching read preference { mode: "nearest" } for set rs, rs/localhost:27017,localhost:27018,localhost:27019 :
connect@src/mongo/shell/mongo.js:372:17
@(connect):2:6
exception: connect failed
exiting with code 1

更详细的日志:

{
  "t": {
    "$date": "2021-08-05T21:35:54.531Z"
  },
  "s": "I",
  "c": "-",
  "id": 4333222,
  "ctx": "ReplicaSetMonitor-TaskExecutor",
  "msg": "RSM received error response",
  "attr": {
    "host": "mongo1:27017",
    "error": "HostUnreachable: Error connecting to mongo1:27017 :: caused by :: Could not find address for mongo1:27017: SocketException: Host not found (authoritative)",
    "replicaSet": "rs",
    "response": "{}"
  }
}

问题的原因是什么,我该如何解决?

【问题讨论】:

    标签: mongodb docker docker-compose replicaset


    【解决方案1】:

    我认为将replicaSet的名称“rs”更改为“rs0”就足够了,这是配置中给您的replicaSet的名称。

    你将拥有:

    $ mongo "mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0"
    

    【讨论】:

    • 副本集名称在撰写文件中显式设置为rs
    • 如果你不想改变composer文件中的replicaSet值,必须改变“initiate_replica_set.sh”文件中的_id,_id:'rs0'变成_id:'rs 'composer文件中的replicaSet值必须和rs.initiate()的'_id'值一致
    【解决方案2】:

    关于这个问题有一些来自不同地方的部分答案,这是我认为的完整答案。

    原因

    • Mongo clients use the hostnames listed in the replica set config, not the seed list

      虽然连接字符串是"mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs",但mongo客户端不会连接到种子地址为localhost:27017等的副本集的成员,而是连接到从种子主机返回的副本配置集中的成员,即rs.initiate 呼叫中的那些。这就是错误消息是 Error connecting to mongo1:27017 而不是 Error connecting to localhost:27017 的原因。

    • 容器主机名在容器网络之外是不可寻址的

      与 mongo 服务器容器位于同一容器网络中的 mongo 客户端可以通过mongo1:27017 等地址连接到服务器;但是,容器网络之外的主机上的客户端无法将mongo1 解析为IP。该问题的典型解决方案是代理,详见Access docker container from host using containers name

    修复

    因为问题涉及 docker 网络,并且 docker 网络在 Linux 和 Mac 之间有所不同。两个平台上的修复不同。

    Linux

    代理修复(通过第 3 方软件或修改 /etc/hosts 文件)工作正常,但有时不可行,例如,在远程 CI 主机上运行。一个简单的自包含可移植解决方案是更新 intiate_replia_set.sh 脚本以使用成员 IP 而不是主机名来启动副本集。

    intiate_replia_set.sh

    echo "Starting replica set initialization"
    until mongo --host mongo1 --eval "print(\"waited for connection\")"
    do
       sleep 2
    done
    echo "Connection finished"
    echo "Creating replica set"
    
    MONGO1IP=$(getent hosts mongo1 | awk '{ print $1 }')
    MONGO2IP=$(getent hosts mongo2 | awk '{ print $1 }')
    MONGO3IP=$(getent hosts mongo3 | awk '{ print $1 }')
    
    read -r -d '' CMD <<EOF
    rs.initiate(
      {
        _id : 'rs',
        members: [
          { _id : 0, host : '${MONGO1IP}:27017' },
          { _id : 1, host : '${MONGO2IP}:27017' },
          { _id : 2, host : '${MONGO3IP}:27017' }
        ]
      }
    )
    EOF
    
    echo $CMD | mongo --host mongo1
    echo "replica set created"
    

    这样,mongo 副本集成员的地址中有容器 IP 而不是主机名。并且容器 IP 可以从主机访问。

    或者,我们可以在 docker-compose 文件中为每个容器显式分配静态 IP,并在启动副本集时使用静态 IP。这是一个类似的修复,但需要更多的工作。

    Mac

    不幸的是,上述解决方案不适用于 Mac,因为 Mac 上的 docker 容器 IP 未暴露在主机网络接口上。 https://docs.docker.com/docker-for-mac/networking/#per-container-ip-addressing-is-not-possible

    使其工作的最简单方法是在/etc/hosts 文件中添加以下映射:

    127.0.0.1   mongo1 mongo2 mongo3
    

    【讨论】:

    • 你拯救了我的一天!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 2013-05-25
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多