Docker 容器连不上 MySQL?90% 是这几个问题
Docker 容器连不上 MySQL?90% 是这几个问题
说实话,Docker 容器连不上数据库这个问题,我至少帮同事解决了十几次。每次都是那几个坑,写篇文章记录一下,下次直接甩链接。
背景
上周五下午,同事跑过来问我:“项目在本机跑得好好的,用 Docker 启动后连不上数据库,什么情况?”
我一看日志,Communications link failure,熟悉的味道。排查了十分钟,发现又是 localhost 的问题。
这类问题占了容器网络问题的 90%以上,今天一次性说清楚。
问题一:连接地址用了 localhost
这是最常见的坑。
在本地开发时,数据库配置通常这样写:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: 123456
本地没问题,但容器里 localhost 指代的是容器自己,不是宿主机。
正确做法:
spring:
datasource:
url: jdbc:mysql://host.docker.internal:3306/mydb
username: root
password: 123456
host.docker.internal 是 Docker 提供的特殊 DNS,指向宿主机地址。Windows 和 Mac 都支持,Linux 需要加 --add-host 参数。
如果是在 Docker Compose 里,更简单:
services:
app:
build: .
extra_hosts:
- "host.docker.internal:host-gateway"
问题二:3306 端口没映射
有些同学会这样启动 MySQL 容器:
docker run -d --name mysql mysql:8.0
然后配置连接 localhost:3306,结果连不上。
问题在哪? 没做端口映射啊!
容器的端口默认是隔离的,不做映射外部访问不了。
正确做法:
docker run -d --name mysql -p 3306:3306 mysql:8.0
-p 3306:3306 的意思是,把容器的 3306 端口映射到宿主的 3306 端口。
也可以指定宿主机端口:
docker run -d --name mysql -p 3307:3306 mysql:8.0
这样就连 localhost:3307。
问题三:防火墙和安全组
这个坑我踩过,印象深刻。
在云服务器上部署,端口映射也做了,本地就是连不上。查了两小时,最后发现是安全组没开放 3306 端口。
排查思路:
-
本地测试端口是否通
telnet <服务器IP> 3306 -
在服务器上测试
curl <服务器IP>:3306 -
检查防火墙
# CentOS firewall-cmd --list-ports # Ubuntu ufw status -
云服务器检查安全组
去云平台控制台,确认入方向规则里开放了 3306 端口。
问题四:容器网络不通
如果你的应用和数据库在不同的容器里,需要确保它们在同一个网络。
# 创建网络
docker network create my-network
# 启动 MySQL 并加入网络
docker run -d --name mysql \
--network my-network \
-p 3306:3306 \
mysql:8.0
# 启动应用并加入同一网络
docker run -d --name app \
--network my-network \
myapp:latest
在同一个网络里,容器可以通过容器名互相访问:
spring:
datasource:
url: jdbc:mysql://mysql:3306/mydb
这里 mysql 是容器的名称,Docker 自带 DNS 会解析到对应的容器 IP。
问题五:认证插件不兼容
MySQL 8.0 默认用了 caching_sha2_password 插件,有些老版本的客户端不支持。
错误信息类似:
Authentication plugin 'caching_sha2_password' cannot be loaded
解决方案一:
启动容器时指定认证插件:
docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0 \
--default-authentication-plugin=mysql_native_password
解决方案二:
进入容器修改用户认证方式:
docker exec -it mysql mysql
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH PRIVILEGES;
写在最后
Docker 网络问题看起来复杂,其实套路很固定。
排查顺序:
- 先用
telnet或nc测试端口通不通 - 检查连接地址是否正确
- 确认容器网络配置
- 最后查防火墙和安全组
记住这几点,90% 的容器连不上数据库的问题都能快速定位。
有问题评论区交流。
更多推荐
所有评论(0)