使用go webservice在docker中连接到mysql时连接被拒绝
Posted
技术标签:
【中文标题】使用go webservice在docker中连接到mysql时连接被拒绝【英文标题】:Connection refused when connecting to mysql in docker, using a go webservice 【发布时间】:2021-12-18 21:43:15 【问题描述】:我无法在 docker 容器中运行我的 mysql 数据库。我用 go 构建了一个非常简单的 web 服务来尝试解决错误,但是无论我尝试什么,在启动 docker build 时,我都会不断收到“连接被拒绝错误”
所以我做了一个最简单的最小例子,目录树看起来像这样:
Example/
| ---- Dockerfile
| ---- main.go
| ---- docker-compose.yml
database/
| ---- Dockerfile
| ---- example.sql
我的 Example/Dockerfile 看起来像这样:
FROM golang:alpine
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
WORKDIR /build
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN go build -o main .
EXPOSE 8080
CMD ["/build/main"]
数据库dockerfile只有三行:
FROM mysql:8.0.24
COPY example.sql /docker-entrypoint-initdb.d/example.sql
EXPOSE 3306
main.go 小而简单:
package main
import "fmt"
import "net/http"
import _ "github.com/go-sql-driver/mysql"
import "database/sql"
import "log"
func main()
http.HandleFunc("/", handler)
db, err := sql.Open("mysql", "user:password@tcp(db:3307)/example") // -- this is the troublemaker!
if err != nil
log.Fatal(err)
pingErr := db.Ping()
if pingErr != nil
log.Fatal(pingErr)
fmt.Println("Connected to DB")
http.ListenAndServe(":8080", nil)
func handler(w http.ResponseWriter, r *http.Request)
fmt.Println("Calling handler")
fmt.Println(r.URL.Path)
docker-compose.yml 也没什么特别的
version: '3'
services:
db:
build:
context: ./database
volumes:
- database:/database/data
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: example
MYSQL_USER: user
MYSQL_PASSWORD: password
container_name: container_db
ports:
- "3307:3306"
networks:
- default
api:
build:
context: .
restart: on-failure
container_name: "container_api"
volumes:
- api:/usr/api
ports:
- "8080:8080"
networks:
- default
volumes:
database:
api:
而且数据库文件example.sql也很简单
CREATE DATABASE IF NOT EXISTS example;
CREATE USER IF NOT EXISTS 'user'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'user'@'%' WITH GRANT OPTION;
CREATE TABLE IF NOT EXISTS exampleTable (
id INT NOT NULL,
name VARCHAR(2048) NOT NULL,
lastName VARCHAR(2048)
PRIMARY KEY (`id`)
);
我尝试在连接中使用服务名称so db,以及容器名称container_db,但错误仍然存在。我还发现了一个帖子,建议配置mysql绑定值0.0.0.0,但这也没有帮助我。
有时我也只得到一个错误输出:“container_api exited with code 1”
【问题讨论】:
【参考方案1】:您应该从您的服务中删除networks
部分。这将导致两个容器在新网络中启动。同一网络中的容器无需暴露端口即可相互通信,因此您也可以从 db 服务中删除 ports
部分。现在将 DSN 更改为使用端口 3307 而不是 3307。
这里的主要问题是当你公开一个端口时,你将主机上的一个端口映射到容器上的一个端口。使用您当前的配置,您告诉主机将端口 3307 转发到 3306,但是您的 api 服务是容器,不能使用主机上的端口(3307),它需要使用 3306 端口。而默认网络中的容器只有拥有自己的网络才能相互通信
【讨论】:
我认为ports: 3307: 3306
表示该服务可以通过端口3307 提供给外界?在东部,这就是我在其他与此类问题相关的帖子中发现的。所以我从配置中删除了网络部分,从 db 服务中删除了端口,我更新了我的连接,比如db, err := sql.Open("mysql", "user:password@tcp(container_db:3306)/example")
,这样我得到了错误Error 1044: Access denied for user 'user'@'%' to database 'example'
@malajedala 是的,但是您的其他 docker 容器不是外部世界。您应该查看docs.docker.com/compose/networking/#specify-custom-networks 以获得更详细的说明。 Access denied for user
是进度,表示可以连接,只是你的用户名和密码错误。
container_api | 2021/11/04 17:27:43 Error 1044: Access denied for user 'user'@'%' to database 'example' container_api | 2021/11/04 17:28:42 dial tcp 172.19.0.2:3306: connect: connection refused
我不确定,我仍然收到此错误消息。我刚刚删除并读取了带有“密码”的“用户”到 mysql,就像在我最初的帖子中一样,我检查了前面评论中所写的连接,密码中没有拼写错误,也在撰写 docker 文件中的所有内容看起来很完美
我认为这是由于startup order。如果您查看日志,您首先会收到连接被拒绝错误。在api
重新启动后的一秒钟后,您会收到拒绝访问错误。您应该将depends_on
配置添加到您的api
服务中,这样它才会在db
服务已经运行时启动。至于身份验证错误,如果您尝试使用root
凭据会发生什么?因为该用户应该没有权限问题以上是关于使用go webservice在docker中连接到mysql时连接被拒绝的主要内容,如果未能解决你的问题,请参考以下文章