无法使用外部IP:端口连接到本地数据库。

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

cant connect to local database using external IP:Port

问题

我有两台服务器,AB

它们都运行着相同的复制服务器应用程序(rest-API),使用go语言编写。在服务器B上,我还运行着一个数据库。服务器和数据库都在docker容器中。

docker-compose.yml

...

userDB:
  image: mysql:oracle
  restart: always
  container_name: userDB
  environment:
    MYSQL_DATABASE: 'mydb'
    MYSQL_USER: 'user'
    MYSQL_PASSWORD: 'mypw'
    MYSQL_ROOT_PASSWORD: 'myrootpw'
  cap_add:
    - SYS_NICE
  ports:
    - '3307:3306'
  networks:
    - dbnet
...

go_rest:
  build:
    context: .
    dockerfile: ./goREST/Dockerfile
  container_name: go_rest
  command: ["./goREST"]
  restart: always
  ports:
    - 8081:8081
  networks:
    - dbnet

在服务器内部,我这样连接到数据库:

db, err := sql.Open("mysql", "root:myrootpw@tcp(bbb.bbb.bbb.bbb:3307)/mydb")

var usr DBUser
stmt, _ := db.Prepare(`SELECT * from user;`)
_ = stmt.QueryRow().Scan(&usr.SteamId)
log.Println(*usr.SteamId)

注意,bbb.bbb....是我的服务器B的公共IP。

现在的问题是:

服务器A上运行服务器应用程序(没有数据库)正常工作。我还可以使用以下命令从我的开发机连接到数据库:

ssh -L 3307:127.0.0.1:3307 usr@bbb.bbb.bbb.bbb

但是当在持有数据库的机器上使用docker化版本时,我无法连接到数据库?只有在docker内部运行时才会出现这个问题,当我在服务器B上运行可执行文件./goRest时,也可以正常工作。我真的很困惑。

如果我的解释令人困惑:

A -----> B(docker)正常工作
B -----> B(本地)正常工作
B -----> B(docker)无法工作

(docker)指的是服务器应用程序。数据库始终在docker中。

操作系统:Ubuntu 20.04LTS

编辑

发生的错误如下所示:

rest | 2022/08/29 22:54:00 http: panic serving ......6:45264: runtime error: invalid memory address or nil pointer dereference
rest | goroutine 9 [running]:
rest | net/http.(*conn).serve.func1(0xc0000eefa0)
rest |     /usr/local/go/src/net/http/server.go:1805 +0x153
rest | panic(0x7d9900, 0xbb2e50)
rest |     /usr/local/go/src/runtime/panic.go:971 +0x499
rest | database/sql.(*Stmt).QueryContext(0x0, 0x9b5b10, 0xc00001a088, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
rest |     /usr/local/go/src/database/sql/sql.go:2630 +0x63
rest | database/sql.(*Stmt).QueryRowContext(0x0, 0x9b5b10, 0xc00001a088, 0x0, 0x0, 0x0, 0x9af7a0)
rest |     /usr/local/go/src/database/sql/sql.go:2705 +0x6d

英文:

I have 2 Servers, A and B.

They both run the same replicated server-application (rest-API) written in go. On Server B, I also have a database running. Both server and database in docker-containers.

docker-compose.yml

...

 userDB:
      image: mysql:oracle
      restart: always
      container_name: userDB
      environment:
        MYSQL_DATABASE: 'mydb'
        MYSQL_USER: 'user'
        MYSQL_PASSWORD: 'mypw
        MYSQL_ROOT_PASSWORD: 'myrootpw'
      cap_add:
        - SYS_NICE
      ports:
        - '3307:3306'
      networks:
        - dbnet
...


go_rest:
    build:
      context: .
      dockerfile: ./goREST/Dockerfile
    container_name: go_rest
    command: ["./goREST"]
    restart: always
    ports:
      - 8081:8081
    networks:
      - dbnet

Inside the Server, I connect to the database like so:

	db, err := sql.Open("mysql", "root:myrootpw@tcp(bbb.bbb.bbb.bbb:3307)/mydb")


	var usr DBUser
	stmt, _ := db.Prepare(`SELECT * from user;`)
	_ = stmt.QueryRow().Scan(&usr.SteamId)
	log.Println(*usr.SteamId)

note, that the bbb.bbb.... is the public IP of my Server B.

Now the problem:

Running th server-application on Server A (which doesn't have the database), works fine. I can also connect to the database from my development machine using this command:

ssh -L 3307:127.0.0.1:3307 usr@bbb.bbb.bbb.bbb

But when using dockerized version on the machine which holds the database, I can't connect to the database? This only happens, when running inside docker, when I just run the executable like ./goRest on Server B, it also works fine. I am really confused.

In case my explanation was confusing:

A -----> B(docker) works
B -----> B(local) works
B -----> B(docker) doesn not work

(docker) referes to the server-application. The database is always dockerized.

OS: Ubuntu 20.04LTS

EDIT

The error that occurs looks like this:

rest  | 2022/08/29 22:54:00 http: panic serving ......6:45264: runtime error: invalid memory address or nil pointer dereference
rest  | goroutine 9 [running]:
rest  | net/http.(*conn).serve.func1(0xc0000eefa0)
rest  | 	/usr/local/go/src/net/http/server.go:1805 +0x153
rest  | panic(0x7d9900, 0xbb2e50)
rest  | 	/usr/local/go/src/runtime/panic.go:971 +0x499
rest  | database/sql.(*Stmt).QueryContext(0x0, 0x9b5b10, 0xc00001a088, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
rest  | 	/usr/local/go/src/database/sql/sql.go:2630 +0x63
rest  | database/sql.(*Stmt).QueryRowContext(0x0, 0x9b5b10, 0xc00001a088, 0x0, 0x0, 0x0, 0x9af7a0)
rest  | 	/usr/local/go/src/database/sql/sql.go:2705 +0x6d

答案1

得分: 0

当在Docker内部运行时,您需要将bbb.bbb.bbb.bbb:3307替换为userDB:3306。尝试将其作为运行时传递的参数,这样您在使用或不使用Docker时就不需要更改代码。

此外,除非您想使用某些外部工具连接到数据库,否则您不需要映射端口3306。您的Docker化应用程序不需要它。

英文:

You need to replace bbb.bbb.bbb.bbb:3307 with userDB:3306 when running inside Docker. Try to make that a parameter that you pass at runtime, this way you don't have to change the code when you run with or without Docker.

Also you don't have to map port 3306 unless you want to connect to the database with some external tool. Your dockerized application doesn't need it.

答案2

得分: 0

我现在找到了一个解决方案。

问题出在ufw上。我有以下规则:

3307                       允许       aaa.aaa.aaa.aaa
3307                       允许       prod.local.ip.notebook
3307                       允许       bbb.bbb.bbb.bbb

这就是为什么我本地开发计算机(也称为prod.local.ip.notebook)和服务器A(也称为aaa.aaa.aaa.aaa)的访问是正常的。

问题出在bbb.bbb.bbb.bbb上,因为访问数据库的REST API容器在ufw中没有被允许。为了允许这个IP,我需要获取容器的IP

所以我运行了:docker exec -it xyz /bin/sh,然后在容器内部运行了ifconfig命令,返回了eth0172.22.0.5

这个IP需要添加到ufw中。所以我的新的ufw配置如下:

3307                       允许       aaa.aaa.aaa.aaa <- 远程服务器
3307                       允许       prod.local.ip.notebook <- 开发
3307                       允许       bbb.bbb.bbb.bbb
3307                       允许       172.22.0.5 <- 容器IP
英文:

I now found a solution.

So the problem was with ufw. I had rules like this:

3307                       ALLOW       aaa.aaa.aaa.aaa
3307                       ALLOW       prod.local.ip.notebook
3307                       ALLOW       bbb.bbb.bbb.bbb

That's why the acces from my local development computer (aka. prod.local.ip.notebook) and the access from server A (aka aaa.aaa.aaa.aaa) works

The problem was bbb.bbb.bbb.bbb, because the container with the rest-API accessing the database was not allowed in ufw. To allow this IP, I had to get the container's IP.

So I ran: docker exec -it xyz /bin/sh, then inside the container: ifconfig which returned 172.22.0.5 for eth0.

This is the IP which had to be added to ufw. So my new ufw configuration looks like this:

3307                       ALLOW       aaa.aaa.aaa.aaa &lt;- remote server
3307                       ALLOW       prod.local.ip.notebook &lt;- development
3307                       ALLOW       bbb.bbb.bbb.bbb
3307                       ALLOW       172.22.0.5 &lt;- container ip

huangapple
  • 本文由 发表于 2022年8月30日 07:35:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/73535656.html
匿名

发表评论

匿名网友

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

确定