我创建了一个docker-compose文件,它具有两个Go
和Mysql
服务。它为go和mysql创建容器。现在我正在运行尝试连接到作为docker容器运行的mysql数据库的代码。但是我出错了。
docker-compose.yml
version: "2"
services:
app:
container_name: golang
restart: always
build: .
ports:
- "49160:8800"
links:
- "mysql"
depends_on:
- "mysql"
mysql:
image: mysql
container_name: mysql
volumes:
- dbdata:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=testDB
- MYSQL_USER=root
- MYSQL_PASSWORD=root
ports:
- "3307:3306"
volumes:
dbdata:
连接到mysql数据库时出错
golang | 2019/02/28 11:33:05 dial tcp 127.0.0.1:3306: connect: connection refused
golang | 2019/02/28 11:33:05 http: panic serving 172.24.0.1:49066: dial tcp 127.0.0.1:3306: connect: connection refused
golang | goroutine 19 [running]:
与MySql数据库的连接
func DB() *gorm.DB {
db, err := gorm.Open("mysql", "root:root@tcp(mysql:3306)/testDB?charset=utf8&parseTime=True&loc=Local")
if err != nil {
log.Panic(err)
}
log.Println("Connection Established")
return db
}
编辑:更新的docker文件
FROM golang:latest
RUN go get -u github.com/gorilla/mux
RUN go get -u github.com/jinzhu/gorm
RUN go get -u github.com/go-sql-driver/mysql
COPY ./wait-for-it.sh .
RUN chmod +x /wait-for-it.sh
WORKDIR /go/src/app
ADD . src
EXPOSE 8800
CMD ["go", "run", "src/main.go"]
我正在使用gorm程序包,该程序包使我可以连接到数据库
答案 0 :(得分:7)
depends_on
不能证明MySQL实际上已经准备好接收连接。无论数据库容器是否准备好进行连接,无论数据库容器是否正在运行,它都会启动第二个容器,这可能会导致您的应用程序出现此问题,因为它期望数据库已准备就绪,而这可能不是真的。
depends_on在启动Web之前不会等待db和redis处于“就绪”状态-仅在它们启动之前。
有许多工具/脚本可用于解决此问题,例如sh
与Alpine
兼容,以防例如基于Dockerfile
的图像(您可以使用{{3 }}(如果图片中有bash)
您要做的就是通过docker-compose.yml
将脚本添加到图像中,然后在--
中将此命令用于您要使其等待数据库的服务。
version: "2"
services:
app:
container_name: golang
...
command: ["./wait-for", "mysql:3306", "--", "go", "run", "myapplication"]
links:
- "mysql"
depends_on:
- "mysql"
mysql:
image: mysql
...
之后是通常用于启动应用程序的命令
go run myapplication
为了便于阅读,我从docker-compose中删除了一些部分。
用golang图片的
CMD
修改这部分MYSQL_USER
。
有关此问题及其解决策略的更多信息,请参见wait-for。
使用root
值设置ERROR 1396 (HY000) at line 1: Operation CREATE USER failed for 'root'@'%'
会在MySQL中导致以下错误消息,从而导致失败:
MYSQL_ROOT_PASSWORD
这是因为该用户已经存在于数据库中,并且试图创建另一个用户。如果需要使用root用户本身,则只能使用此变量MYSQL_USER
或更改{{1}}的值,以便可以安全地在应用程序中使用它而不是root用户。
答案 1 :(得分:0)
首先,如果您使用的是最新版本的docker compose,则无需在应用服务中使用link参数。我引用了docker compose文档Warning: The --link flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it,
https://docs.docker.com/compose/compose-file/#links
我认为解决方案是使用networks
参数。这将创建一个docker网络并向其中添加每个服务。
尝试一下
version: "2"
services:
app:
container_name: golang
restart: always
build: .
ports:
- "49160:8800"
networks:
- my_network
depends_on:
- "mysql"
mysql:
image: mysql
container_name: mysql
volumes:
- dbdata:/var/lib/mysql
restart: always
networks:
- my_network
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=testDB
- MYSQL_USER=root
- MYSQL_PASSWORD=root
ports:
- "3307:3306"
volumes:
dbdata:
networks:
my_network:
driver: bridge
顺便说一句,如果您仅从应用程序服务连接到Mysql,则无需公开mysql端口。如果容器在同一网络中运行,则它们可以到达该网络内的所有端口。
如果我的示例不起作用,请尝试以下操作
运行docker compose,然后使用进入应用容器
docker container exec -it CONTAINER_NAME bash
安装ping
为了测试连接,然后运行ping mysql。