技术复盘:解决 Docker 容器内 MySQL 拒绝外部连接的问题
0. 问题背景
在部署 KamaChat 微服务项目时,我通过 Docker 运行了一个包含 MySQL 8.0 的集成镜像。虽然在宿主机(M4 Mac mini)上已经做好了端口映射(3307:3306),且通过 docker exec 进入容器内部可以正常登录数据库,但使用 GoLand 的 Database 工具连接时,始终报错:
Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
1. 排查过程
第一阶段:用户权限校验
起初我认为是 root 用户默认禁止远程登录的问题。我进入容器执行了常规的权限修改:
1 | USE mysql; |
结果: 修改后报错依旧,说明问题不在 MySQL 的用户授权表,而是在更底层的网络监听阶段。
第二阶段:网络监听排查 (关键点)
在 Docker 环境下,MySQL 默认的配置文件往往为了安全,将监听地址绑定在 127.0.0.1。
- 原理: 容器内的
127.0.0.1仅代表容器自身的回环网卡。宿主机通过映射端口访问时,流量是从容器的虚拟网卡(通常是eth0)进入的。如果 MySQL 只监听127.0.0.1,它会直接丢弃来自虚拟网卡的外部请求。
2. 解决方案
通过修改 MySQL 的配置文件,将监听地址由本地改为全接口监听。
第一步:定位配置文件
进入容器终端:
1 | docker exec -it gochat-container bash |
查找 bind-address 所在位置:
1 | grep -r "bind-address" /etc/mysql/ |
这次位于 /etc/mysql/mysql.conf.d/mysqld.cnf。
第二步:修改配置
使用 vim 打开文件,找到如下行:
1 | bind-address = 127.0.0.1 |
修改为:
1 | bind-address = 0.0.0.0 |
第三步:重启服务
1 | service mysql restart |
3. 最终验证
回到 GoLand 的 Database 配置界面,重新点击 Test Connection。
- Host: 127.0.0.1
- Port: 3307
- User: root
- Password: (根据实际情况填写)
结果: 连接成功,显示 Ping: 10ms。
4. 总结
在处理 Docker 数据库连接问题时,应遵循以下排查优先级:
- 宿主机端口映射:确保
docker ps中显示的端口无误。 - MySQL 绑定地址:检查
bind-address是否为0.0.0.0。 - 用户授权:确保
user表中对应账号的host字段已改为%。
尤其在 M4 芯片通过模拟层运行 amd64 镜像时,网络响应可能会有延迟,建议适当调大 IDE 的连接超时时间(Timeout)。 通过这次复盘,我加深了对 Docker 网络模型和 MySQL 配置的理解,为今后类似问题的解决提供了宝贵经验。