使用Docker连接Golang与MySQL的实践指南
使用Docker连接Golang与MySQL的实践指南 我正在尝试使用Docker将Go与MySQL连接,对于本地的MySQL实例,它可以完美工作,但当我尝试访问Docker容器中的MySQL实例时,总是收到连接被拒绝的错误。
有人能帮我解决这个问题吗?
.env
MYSQL_IDS_USERNAME=root
MYSQL_IDS_PASSWORD=12345678
MYSQL_IDS_HOST=localhost
MYSQL_IDS_PORT=3306
MYSQL_IDS_SCHEMA=ids_db
MYSQL_ROOT_PASSWORD=12345678
docker-compose.yml
version: '3.7'
services:
mysql:
image: mysql:latest
volumes:
- "./db_data:/var/lib/mysql"
env_file:
- ".env"
ports:
- "3307:3306"
networks:
- appmysql
id_service:
container_name: id_service
build:
context: .
dockerfile: Dockerfile
image: rezwanulhaque/id-service:latest
volumes:
- "./logs:/app/lib/logs"
ports:
- "7001:7001"
depends_on:
- mysql
networks:
- appmysql
networks:
appmysql:
driver: bridge
Dockerfile
# Start from golang base image
FROM golang:1.14-alpine3.11 AS builder
#ENV GO111MODULE=on
# Add Maintainer info
LABEL maintainer="Rezwanul Haque <rezwanul.cse@gmail.com>"
# Install git.
# Git is required for fetching the dependencies.
RUN apk update && apk add --no-cache git
# Configure the repo url
ENV REPO_URL=github.com/Rezwanul-Haque/ID-Service
# Setup our $GOPATH
ENV GOPATH=/app
# Set the current working directory inside the container
ENV APP_PATH=$GOPATH/src/$REPO_URL
ENV WORKPATH=$APP_PATH/src/
COPY src $WORKPATH
WORKDIR $WORKPATH
# Copy go mod and sum files
#COPY go.mod .
#COPY go.sum .
# Download all dependencies. Dependencies will be cached if the go.mod and the go.sum files are not changed
RUN go mod download
# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -o id-service .
# Start a new stage from scratch
#FROM alpine:latest
#
#RUN ls bin/
## Copy the Pre-built binary file from the previous stage. Observe we also copied the .env file
#COPY --from=builder /app/id-service .
#COPY --from=builder /app/.env .
#
# Expose port 7001 to the outside world
EXPOSE 7001
# Command to run the executable
ENTRYPOINT ["./id-service"]
db.go
var (
Client *sql.DB
username = os.Getenv("MYSQL_IDS_USERNAME")
password = os.Getenv("MYSQL_IDS_PASSWORD")
host = os.Getenv("MYSQL_IDS_HOST")
port = os.Getenv("MYSQL_IDS_PORT")
schema = os.Getenv("MYSQL_IDS_SCHEMA")
)
func init() {
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8",
username, password, host, port, schema,
)
var err error
Client, err = sql.Open("mysql", dataSourceName)
if err != nil {
logger.Error("connecting to database failed: ", err)
panic(err)
}
if err = Client.Ping(); err != nil {
panic(err)
}
logger.Info("database successfully configured")
}
更多关于使用Docker连接Golang与MySQL的实践指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你是在宿主机上运行,还是在应用程序容器内运行?
更多关于使用Docker连接Golang与MySQL的实践指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Docker Compose 使你的 mysql 在 DNS 中可通过该名称访问,而从应用程序容器的视角来看,本地主机上并没有数据库在运行。
但是使用以下命令,我可以访问我的Docker容器中的MySQL实例。
mysql -h localhost -P 3307 --protocol=tcp -u root --password='12345678
由于我的Docker容器包含mysql和Id_service两个服务,并且有一个名为“appmysql”的桥接网络,因此为了让id_service访问mysql,我需要使用appmysql网络的IP从app服务访问mysql,这样对吗?
每个Docker容器都是隔离的,你可以将其视为独立的计算机以简化理解。因此,你的应用程序容器中的“localhost”与主机计算机是不同的。
你的主机计算机已配置了将其自身端口映射到MySQL容器端口的设置。
正如我之前提到的,在Compose网络内部,数据库可以通过DNS以名称mysql访问。
你有两个容器。每个服务一个。
每个服务都可以通过其服务名称在DNS下访问。只需在你的Go应用程序中使用 mysql 作为数据库的主机。
必须在
my.cnf文件中允许远程连接
这已经完成了,否则从主机到容器MySQL的连接将无法实现。
我是Docker的新手,所以我运行了 docker-compose up -d 命令,然后检查Docker的应用程序服务(在我的例子中是ID_service)时,它显示连接被拒绝。接着我检查了MySQL服务,发现它正在运行,于是我尝试使用以下命令来检查MySQL是否正常运行:
mysql -h localhost -P 3307 --protocol=tcp -u root --password='12345678
我可以通过主机电脑访问MySQL的3307(公共)端口,该端口已从容器中公开为公共端口。
您必须在 my.cnf 文件中允许远程连接(参见 bind-address 选项),并在您的情况下授予远程用户 ‘root’@’%’ 的访问权限。
如何启用对 MySQL 数据库服务器的远程访问? - nixCraft
出于安全原因,默认情况下禁止远程访问 MySQL 数据库服务器。但是,有时您需要从家庭或 Web 服务器提供对数据库服务器的远程访问。本文将解释如何设置用户帐户并访问…
问题出在Go应用连接MySQL时使用了localhost作为主机地址。在Docker容器网络中,localhost指向容器自身,而不是MySQL容器。需要将主机地址改为Docker Compose网络中的服务名称。
修改.env文件中的MYSQL_IDS_HOST:
MYSQL_IDS_HOST=mysql
MYSQL_IDS_PORT=3306
在Docker Compose网络中,服务名称mysql会自动解析为MySQL容器的内部IP地址。同时确保端口使用容器内部的3306而不是映射的3307。
另外,确保Go应用的Dockerfile正确复制了.env文件。当前Dockerfile中注释掉了复制.env的步骤,需要取消注释:
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/src/id-service .
COPY --from=builder /app/src/.env .
EXPOSE 7001
ENTRYPOINT ["./id-service"]
还需要确认MySQL容器允许root用户从网络连接。在MySQL初始化时可能需要设置环境变量:
services:
mysql:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: 12345678
MYSQL_DATABASE: ids_db
volumes:
- "./db_data:/var/lib/mysql"
ports:
- "3307:3306"
networks:
- appmysql
在Go代码中,可以添加连接重试逻辑来处理MySQL容器启动延迟:
func init() {
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8",
username, password, host, port, schema,
)
var err error
for i := 0; i < 5; i++ {
Client, err = sql.Open("mysql", dataSourceName)
if err != nil {
time.Sleep(2 * time.Second)
continue
}
err = Client.Ping()
if err == nil {
break
}
time.Sleep(2 * time.Second)
}
if err != nil {
logger.Error("connecting to database failed: ", err)
panic(err)
}
logger.Info("database successfully configured")
}
确保Go应用使用了正确的MySQL驱动。在go.mod中需要包含:
require github.com/go-sql-driver/mysql v1.6.0
连接字符串也可以添加额外的参数:
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local&timeout=30s",
username, password, host, port, schema,
)

