MongoDB通过Docker运行的服务器无法相互访问(名称解析临时失败)。

huangapple go评论111阅读模式
英文:

MongoDB servers running via docker can't see each other (Temporary failure in name resolution)

问题

好的,以下是翻译的内容:

好的,我在一台M1 Mac上运行着一个多通行证虚拟机,它托管着一个Ubuntu服务器。
在这个Ubuntu服务器上,我安装了Go、Gin和一堆其他相关技术。
然后我开始处理Mongo。

首先,我使用sudo docker network create mongoCluster命令创建了复制集。

然后我启动了三个节点:

  1. sudo docker run -d -p 27017:27017 --name mongo1 --network mongoCluster -e MONGODB_INITDB_ROOT_USERNAME=myuser -e MONGODB_INITDB_ROOT_PASSWORD=mypassword -e MONGO_INITDB_DATABASE=task mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo1
  2. sudo docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo2
  3. sudo docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo3

然后,我使用以下命令初始化了复制集:

  1. sudo docker exec -it mongo1 mongosh --eval "rs.initiate({
  2. _id: \"myReplicaSet\",
  3. members: [
  4. {_id: 0, host: \"mongo1\"},
  5. {_id: 1, host: \"mongo2\"},
  6. {_id: 2, host: \"mongo3\"}
  7. ]
  8. })"

运行sudo docker exec -it mongo2 mongosh --eval "rs.status()"命令显示一切都设置正确了,mongo1是主节点。

到目前为止一切顺利!

然后我启动我的应用程序,并使用以下URI进行连接:mongodb://myuser:mypassword@localhost:27017/?retryWrites=true&w=majority
Mongo抛出一个错误Failed to ping cluster,但它随后报告连接成功。
然后它抛出了这个错误:

  1. Could not create Task: server selection error: context deadline exceeded, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: mongo1:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo1: Temporary failure in name resolution }, { Addr: mongo2:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo2: Temporary failure in name resolution }, { Addr: mongo3:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo3: Temporary failure in name resolution }, ] }

所以看起来各个节点无法相互通信。
我已经在谷歌上搜索了一段时间,但似乎没有解决我的具体问题的方法。

我甚至花了钱参加培训课程来解决这个问题,但还没有找到解决方法。请帮帮我!

英文:

OK so, I have a multipass vm running on an M1 mac. It's hosting an ubuntu server.
On this ubuntu server I've installed go, gin, and a bunch of other related technologies.
I then get to mongo.

I first create the replication set with sudo docker network create mongoCluster

Then I spin up three nodes:

  1. sudo docker run -d -p 27017:27017 --name mongo1 --network mongoCluster -e MONGODB_INITDB_ROOT_USERNAME=myuser -e MONGODB_INITDB_ROOT_PASSWORD=mypassword -e MONGO_INITDB_DATABASE=task mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo1
  2. sudo docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo2
  3. sudo docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip localhost,mongo3

Then I initialize the replication set with

  1. sudo docker exec -it mongo1 mongosh --eval "rs.initiate({
  2. _id: \"myReplicaSet\",
  3. members: [
  4. {_id: 0, host: \"mongo1\"},
  5. {_id: 1, host: \"mongo2\"},
  6. {_id: 2, host: \"mongo3\"}
  7. ]
  8. })"

running sudo docker exec -it mongo2 mongosh --eval "rs.status()" shows me it's all set up correctly with mongo1 as the PRIMARY

So far so good!

Then I fire up my app and make the connection with the uri: mongodb://myuser:mypassword@localhost:27017/?retryWrites=true&w=majority
Mongo throws an error Failed to ping cluster, but it then reports that it connected
Then it throws this:

  1. Could not create Task: server selection error: context deadline exceeded, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: mongo1:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo1: Temporary failure in name resolution }, { Addr: mongo2:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo2: Temporary failure in name resolution }, { Addr: mongo3:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo3: Temporary failure in name resolution }, ] }

So it looks like the various nodes can't see each other
I've been searching the googs for a while, but nothing seems to address my specific issue

I even put the money down on a training course to figure this out, but haven't. Please help!

答案1

得分: 1

这里有几个问题。

首先,MONGODB_INITDB_ROOT_USERNAMEMONGODB_INITDB_ROOT_PASSWORD是错误的。它们应该是MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_USERNAME

然后问题是,mongo1在启动后不久会崩溃,因为它需要一个secret.key。检查日志,你会看到错误。修复这个问题是另一个问题。

我建议先尝试不使用身份验证。这是一个可行的方法:

你遗漏的步骤:

  1. echo 127.0.0.1 mongo1 >> /etc/hosts

数据库启动脚本:

  1. #!/bin/bash
  2. docker container rm -f mongo1 mongo2 mongo3
  3. docker run -d -p 27017:27017 --name mongo1 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  4. docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  5. docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  6. docker exec -it mongo1 mongosh --eval "rs.initiate({
  7. _id: \"myReplicaSet\",
  8. members: [
  9. {_id: 0, host: \"mongo1\"},
  10. {_id: 1, host: \"mongo2\"},
  11. {_id: 2, host: \"mongo3\"}
  12. ]
  13. })"

Go语言的测试程序:

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go.mongodb.org/mongo-driver/mongo"
  7. "go.mongodb.org/mongo-driver/mongo/options"
  8. "go.mongodb.org/mongo-driver/mongo/readpref"
  9. )
  10. const uri = "mongodb://mongo1:27017/task?replicaSet=myReplicaSet&retryWrites=true&w=majority"
  11. func main() {
  12. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  13. defer cancel()
  14. client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
  15. if err != nil {
  16. panic(err)
  17. }
  18. defer func() {
  19. if err = client.Disconnect(ctx); err != nil {
  20. panic(err)
  21. }
  22. }()
  23. if err := client.Ping(ctx, readpref.Primary()); err != nil {
  24. panic(err)
  25. }
  26. fmt.Println("Successfully connected and pinged")
  27. }

运行这个程序,你应该会得到一个成功的响应:

  1. > go run ./main.go
  2. Successfully connected and pinged

另外,我认为你不需要将所有副本的端口映射到主机上。这样可以使事情更清晰。

英文:

There are a few problems here.

First of all MONGODB_INITDB_ROOT_USERNAME and MONGODB_INITDB_ROOT_PASSWORD are wrong. They should be MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_USERNAME.

The problem is then that mongo1 will crash shortly after startup because it requires a secret.key. Check the logs and you will see the error. Fixing that is another issue.

I recommend to try first without authentication. Here is something that works:

The step that you are missing:

  1. echo 127.0.0.1 mongo1 >> /etc/hosts

database startup script:

  1. #!/bin/bash
  2. docker container rm -f mongo1 mongo2 mongo3
  3. docker run -d -p 27017:27017 --name mongo1 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  4. docker run -d -p 27018:27017 --name mongo2 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  5. docker run -d -p 27019:27017 --name mongo3 --network mongoCluster mongo:latest mongod --replSet myReplicaSet --bind_ip_all
  6. docker exec -it mongo1 mongosh --eval "rs.initiate({
  7. _id: \"myReplicaSet\",
  8. members: [
  9. {_id: 0, host: \"mongo1\"},
  10. {_id: 1, host: \"mongo2\"},
  11. {_id: 2, host: \"mongo3\"}
  12. ]
  13. })"

Test program in go:

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go.mongodb.org/mongo-driver/mongo"
  7. "go.mongodb.org/mongo-driver/mongo/options"
  8. "go.mongodb.org/mongo-driver/mongo/readpref"
  9. )
  10. const uri = "mongodb://mongo1:27017/task?replicaSet=myReplicaSet&retryWrites=true&w=majority"
  11. func main() {
  12. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  13. defer cancel()
  14. client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
  15. if err != nil {
  16. panic(err)
  17. }
  18. defer func() {
  19. if err = client.Disconnect(ctx); err != nil {
  20. panic(err)
  21. }
  22. }()
  23. if err := client.Ping(ctx, readpref.Primary()); err != nil {
  24. panic(err)
  25. }
  26. fmt.Println("Successfully connected and pinged")
  27. }

Run this and you should get a successful response:

  1. > go run ./main.go
  2. Successfully connected and pinged

Also I don't think you need to map all the replicas ports on the host. This should make things cleaner.

huangapple
  • 本文由 发表于 2022年9月21日 06:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/73793257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定