Docker+MySQL连接问题——只能通过ip连接而localhost无效
问题描述
今天在自己的ECS(Ubuntu18.04)上使用docker-compos
构建并生成两个容器,一个是jeecg-boot
后端,一个是MySQL
,构建成功启动后使用docker logs -f
命令查>看后端容器的日志,发现无法创建SQL连接,后来通过查看日志,查阅资料最终将问题定位在主机文件的缺失,并搞明白了mysql -h localhost
和mysql -h ipaddress
两种方式创建连接的区别。
问题解决过程
首先是查看后端容器的日志:
1 |
|
从这个报错来看,后端的容器是能够成功向 MySQL Server
发送数据包,但自身的driver
(驱动,连接器)并没有收到确认回传。
而MySQL
容器这边的日志是:
1 |
|
可以看到容器启动后内部的/usr/sbin/mysqld
准备好接收连接,并通过/var/run/mysqld/mysqld.sock
套接字监听3306端口。
特意检查了一下后端代码配置,我写的是
1 |
|
由于后端和MySQL
在同一台机器上,所以这里写localhost
应该没问题(事实证明就是这的问题)
看起来并没有什么问题,用Navicat
也能连接到数据库并取到数据:
我再使用命令行连接一下数据库?神奇的一幕出现了(其实是本人才疏学浅少见多怪,见笑了)
1 |
|
我靠?localhost
和127.0.0.1
还不一样,这么离谱的吗???
吃惊之余我赶紧将后端代码中的配置改成服务器公网地址,重新打包,果然发现后端正常运行了,真神奇。
事实上这种方式比较麻烦,一点小的改动就要
mvn clean
,mvn insrtall
,浪费我们不少时间,其实可以把这些容易变动的全局性的配置参数绑定到一个文件中,后续会整理更新docker
部署相关技巧
进一步原因分析与改进
如果你的机器上恰好也安装了docker
并且没有安装mysql-server
,你可以亲自复现一下这个问题,然后你就会发现这两种方式虽然都默认server
在本机,但有着本质的区别
localhost
的报错如下所示,可以看到是通过本地sock
文件创建连接1
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
而
127.0.0.1
的报错如下所示,可以看到只说了无法连接到目标主机1
ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1:3306' (111)
因此我可以大胆猜测,连接方式为localhost
时,通过本地机器上的sock
文件创建连接(但实际没有),而127.0.0.1
虽然也是本机但还是把它当做远程主机,创建连接的驱动文件从server
获取,那自然能成功
然后查找本机/var/run/mysqld
发现直接没有这个文件夹,我的猜想得到了验证。之前曾安装过MySQL后来又卸载了,因此相关文件也就移除了。
那为什么我一开始在后端程序中写的是127.0.0.1
也不行?
这个问题暂时没有找到答案,我猜测可能是docker
容器或jeecg-boot
配置了一些默认行为,当连接请求为127.0.0.1
时自动转为localhost
(前者要经过网卡传输,受到防火墙和网卡相关限制,而后者并不会解析成IP地址,也不通过网卡传输数据。这样做能够节省带宽资源)
总结
通过这次docker
容器的部署,锻炼了问题排查和问题分析能力,具体而言加深了对MySQL
服务的理解、计算机网络方面相关知识。