问题描述
在使用Docker时遇到了一个问题,他在一个MySQL数据库容器和一个Golang REST API容器之间建立数据库连接时遇到了连接被拒绝的错误。
以下是用户的具体情况:
– 用户有一个运行MySQL数据库的Docker容器,使用了以下的docker-compose.yml配置:
version: '3.3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: 'demo'
MYSQL_USER: 'user'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- '3306:3306'
expose:
- '3306'
volumes:
- my-db:/var/lib/mysql
networks:
- backend
networks:
backend:
driver: bridge
volumes:
my-db:
- 用户还有一个基本的Golang REST API,使用了以下的Dockerfile配置:
# Start from golang:1.12-alpine base image
FROM golang:1.12-alpine
# Adding git, bash and openssh to the image
RUN apk update && apk upgrade && \
apk add --no-cache bash git openssh
# Set the Current Working Directory inside the container
WORKDIR /app
# Copy the source from the current directory to the Working Directory inside the container
COPY . .
RUN go get -d github.com/gorilla/mux
RUN go get -d github.com/go-sql-driver/mysql
RUN go get -d github.com/golang-migrate/migrate
RUN go get -d github.com/golang-migrate/migrate/database/mysql
RUN go get -d github.com/golang-migrate/migrate/source/file
# Build the Go app
RUN go build -o main .
# Expose port 8080 to the outside world
EXPOSE 8080
# Run the executable
CMD ["./main"]
- 用户在Golang代码中调用了以下函数来建立数据库连接:
func CreateDatabase() (*sql.DB, error) {
serverName := "localhost:3306"
user := "user"
password := "password"
dbName := "demo"
connectionString := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=true&multiStatements=true", user, password, serverName, dbName)
db, err := sql.Open("mysql", connectionString)
if err != nil {
return nil, err
}
if err := migrateDatabase(db); err != nil {
return db, err
}
return db, nil
}
- 用户尝试运行Golang API容器时,使用了以下命令:
$ docker run -p 80:8080 --network=<appname>-mysql_backend <imageid>
- 用户遇到了以下错误信息:
$ Database connection failed: dial tcp 127.0.0.1:3306: connect: connection refused
用户希望能够解决这个问题,使Golang API容器能够成功连接到MySQL数据库容器。
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
首先,确保Golang API容器和MySQL数据库容器在同一个网络中。根据用户提供的docker-compose.yml文件,我们可以看到两个容器都在名为backend
的网络中。因此,我们需要将Golang API容器添加到相同的网络中。
以下是解决问题的步骤:
1. 在docker-compose.yml文件中添加Golang API服务的定义,并将其添加到backend
网络中。
2. 使用docker-compose build
命令构建镜像。
3. 使用docker-compose up
命令启动容器。
下面是一个示例的docker-compose.yml文件:
version: '3.3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: 'demo'
MYSQL_USER: 'user'
MYSQL_PASSWORD: 'password'
MYSQL_ROOT_PASSWORD: 'password'
ports:
- '3306:3306'
expose:
- '3306'
volumes:
- my-db:/var/lib/mysql
networks:
- backend
api:
build: .
ports:
- '80:8080'
networks:
- backend
networks:
backend:
driver: bridge
volumes:
my-db:
在上面的示例中,我们添加了一个名为api
的服务,并将其构建为当前目录中的Dockerfile。我们还将api
服务添加到了backend
网络中。
方案2
除了将Golang API容器添加到相同的backend
网络中之外,还需要修复连接字符串中的MySQL主机参数。
根据用户提供的代码,我们可以看到MySQL主机被设置为localhost
:
serverName := "localhost:3306"
然而,MySQL并不在Golang API容器的localhost
上监听,所以我们需要将其更改为docker-compose.yml文件中MySQL服务的名称,即db
。
以下是修复连接字符串的步骤:
1. 在Golang代码中将MySQL主机更改为db
。
2. 重新构建Golang API容器。
下面是修复后的代码示例:
func CreateDatabase() (*sql.DB, error) {
serverName := "db:3306"
user := "user"
password := "password"
dbName := "demo"
connectionString := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=true&multiStatements=true", user, password, serverName, dbName)
db, err := sql.Open("mysql", connectionString)
if err != nil {
return nil, err
}
if err := migrateDatabase(db); err != nil {
return db, err
}
return db, nil
}
在上面的示例中,我们将MySQL主机从localhost
更改为db
。
请注意,如果MySQL容器需要一些额外的时间来启动并变为可连接状态,您可能需要在连接之前等待适当的时间。
总结
在本文中,我们讨论了如何解决在Docker容器之间建立数据库连接时连接被拒绝的问题。我们提供了两种解决方案,包括将Golang API容器添加到相同的网络中,并修复连接字符串中的MySQL主机参数。根据您的具体情况,您可以选择适合您的解决方案。希望本文对您有所帮助!