【问题标题】:Mongo single node replicaset on Docker, MongooseServerSelectionError: connect ECONNREFUSEDDocker上的Mongo单节点replicaset,MongooseServerSelectionError: connect ECONNREFUSED
【发布时间】:2023-02-17 17:46:01
【问题描述】:

我正在尝试在 Docker 上设置单节点 MongoDB 复制集并在我的节点应用程序中连接到它,但连接被拒绝。如果我将 mongo 用作独立实例并且没有复制集,则连接工作正常。

这就是我在节点应用程序上连接到 mongo 的方式:

mongoose.connect("mongodb://admin:secretpass@app_mongodb:27017/dbname?authSource=admin&replicaSet=rs0")

这是我收到的错误:

/var/www/worker/node_modules/mongoose/lib/connection.js:824
const serverSelectionError = new ServerSelectionError();
                               ^
MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017

Mongo 日志显示该应用程序尝试连接:

{"t":{"$date":"2023-01-27T10:22:46.410+00:00"},"s":"I",  "c":"NETWORK",  "id":22943,   "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.18.0.10:41318","uuid":"2e1ccbc5-3162-4f64-80f3-8be580079ef6","connectionId":68,"connectionCount":11}}
{"t":{"$date":"2023-01-27T10:22:46.417+00:00"},"s":"I",  "c":"NETWORK",  "id":51800,   "ctx":"conn68","msg":"client metadata","attr":{"remote":"172.18.0.10:41318","client":"conn68","doc":{"driver":{"name":"nodejs|Mongoose","version":"4.11.0"},"os":{"type":"Linux","name":"linux","architecture":"x64","version":"5.10.0-12-amd64"},"platform":"Node.js v19.5.0, LE (unified)","version":"4.11.0|6.7.5"}}}
{"t":{"$date":"2023-01-27T10:22:46.425+00:00"},"s":"I",  "c":"NETWORK",  "id":22944,   "ctx":"conn68","msg":"Connection ended","attr":{"remote":"172.18.0.10:41318","uuid":"2e1ccbc5-3162-4f64-80f3-8be580079ef6","connectionId":68,"connectionCount":10}}

docker-compose.yml :

version: '3.8'

services:
    mongodb:
        container_name: app_mongodb
        build:
            dockerfile: ./Dockerfile
            x-bake:
                no-cache: true
        environment:
            - MONGO_INITDB_ROOT_USERNAME=admin
            - MONGO_INITDB_ROOT_PASSWORD=secretpass
        volumes:
            - ./db:/data/db
        networks:
            - proxy
        restart: unless-stopped
    worker:
        container_name: app_worker
        image: "node:latest"
        command: "npm run dev"
        user: "node"
        working_dir: /var/www/worker
        environment:
            WAIT_HOSTS: app_mongodb:27017
        volumes:
            - ./worker:/var/www/worker
        networks:
            - proxy
        links:
            - mongodb
        depends_on:
            - mongodb
        restart: unless-stopped
networks:
    proxy:
        external: true

文件:

FROM mongo

# Initiate replica set
RUN echo "secretpasswordkey" > "/tmp/replica.key"
RUN chmod 600 /tmp/replica.key
RUN chown 999:999 /tmp/replica.key

CMD ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/tmp/replica.key"]

我还在启动容器后用 mongosh 运行这个命令(顺便说一句,有没有办法将它添加到 Dockerfile 中?):

rs.initiate({_id: 'rs0', members: [{_id:1, 'host':'127.0.0.1:27017'}]})

快速检查显示副本集确实已初始化:

rs0 [direct: primary] admin> rs.status()
{
  set: 'rs0',
  date: ISODate("2023-01-27T10:35:44.062Z"),
  myState: 1,
  term: Long("1"),
  syncSourceHost: '',
  syncSourceId: -1,
  heartbeatIntervalMillis: Long("2000"),
  majorityVoteCount: 1,
  writeMajorityCount: 1,
  votingMembersCount: 1,
  writableVotingMembersCount: 1,
  optimes: {
    lastCommittedOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") },
    lastCommittedWallTime: ISODate("2023-01-27T10:35:39.161Z"),
    readConcernMajorityOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") },
    appliedOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") },
    durableOpTime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") },
    lastAppliedWallTime: ISODate("2023-01-27T10:35:39.161Z"),
    lastDurableWallTime: ISODate("2023-01-27T10:35:39.161Z")
  },
  lastStableRecoveryTimestamp: Timestamp({ t: 1674815679, i: 1 }),
  electionCandidateMetrics: {
    lastElectionReason: 'electionTimeout',
    lastElectionDate: ISODate("2023-01-27T10:25:49.015Z"),
    electionTerm: Long("1"),
    lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1674815148, i: 1 }), t: Long("-1") },
    lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1674815148, i: 1 }), t: Long("-1") },
    numVotesNeeded: 1,
    priorityAtElection: 1,
    electionTimeoutMillis: Long("10000"),
    newTermStartDate: ISODate("2023-01-27T10:25:49.082Z"),
    wMajorityWriteAvailabilityDate: ISODate("2023-01-27T10:25:49.111Z")
  },
  members: [
    {
      _id: 1,
      name: '127.0.0.1:27017',
      health: 1,
      state: 1,
      stateStr: 'PRIMARY',
      uptime: 643,
      optime: { ts: Timestamp({ t: 1674815739, i: 1 }), t: Long("1") },
      optimeDate: ISODate("2023-01-27T10:35:39.000Z"),
      lastAppliedWallTime: ISODate("2023-01-27T10:35:39.161Z"),
      lastDurableWallTime: ISODate("2023-01-27T10:35:39.161Z"),
      syncSourceHost: '',
      syncSourceId: -1,
      infoMessage: '',
      electionTime: Timestamp({ t: 1674815149, i: 1 }),
      electionDate: ISODate("2023-01-27T10:25:49.000Z"),
      configVersion: 1,
      configTerm: 1,
      self: true,
      lastHeartbeatMessage: ''
    }
  ],
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1674815739, i: 1 }),
    signature: {
      hash: Binary(Buffer.from("a211cfe3faa237bf8a30ccbc8ca929eea704f467", "hex"), 0),
      keyId: Long("7193276291800367109")
    }
  },
  operationTime: Timestamp({ t: 1674815739, i: 1 })
}

关于我做错了什么的想法?谢谢 !

【问题讨论】:

  • 你确定吗?连接字符串 mongodb://admin:secretpass@app_mongodb:27017 与错误消息 connect ECONNREFUSED 127.0.0.1:27017 不匹配 尝试使用 localhost 而不是 127.0.0.1
  • 创建一个的原因是什么单一成员MongoDB 副本集?
  • 请修剪您的代码,以便更容易找到您的问题。按照这些指南创建一个minimal reproducible example
  • @WernfriedDomscheit 感谢您的评论!它帮助了很多。起初我没有意识到initiate()指令中的连接url将在客户端连接期间使用。另外为了回答您的问题,我需要在我的应用程序中使用 Change Streams,并且该功能在独立模式下不可用。由于我只有一台服务器可供使用,并且在我的情况下性能比可用性更重要,所以我认为只需要一个实例。

标签: node.js mongodb docker-compose replicaset


【解决方案1】:

感谢@WernfriedDomscheit 的评论为我指明了正确的方向,我意识到在启动 replicaset 时我必须提供 mongodb 容器主机名而不是 127.0.0.1 :

rs.initiate({_id: 'rs0', members: [{_id: 1, 'host': 'mongodb:27017'}]})

通过向我的 docker-compose.yml 文件添加健康检查例程,我能够自动进行初始化。

整个 mongodb 容器描述现在是这样的:

    mongodb:
        build:
            dockerfile: ./Dockerfile
            x-bake:
                no-cache: true
        container_name: ${COMPOSE_PROJECT_NAME}_mongodb
        environment:
            - MONGO_INITDB_ROOT_USERNAME=${MONGODB_USER}
            - MONGO_INITDB_ROOT_PASSWORD=${MONGODB_PASS}
        volumes:
            - ./db:/data/db
        networks:
            - proxy
        restart: unless-stopped
        healthcheck:
            test: test $$(echo "rs.initiate({_id: 'rs0', members: [{_id: 1, 'host': 'mongodb:27017'}]}).ok || rs.status().ok" | mongosh -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
            interval: 10s
            start_period: 30s

initiate() 中设置主机并且不要将参数留空是很重要的,否则默认情况下它将使用容器 ID 设置副本集作为主机,如果容器被删除并重新启动,副本集将不再工作,因为新的容器 ID 将不同。

【讨论】:

  • 启动可能需要几秒钟。最好在rs.initiate()之后加上while (! db.hello().isWritablePrimary ) { sleep(1000) }
猜你喜欢
  • 2021-11-22
  • 2020-10-27
  • 2016-01-03
  • 1970-01-01
  • 2018-08-07
  • 2021-12-18
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多