首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >踩坑案例:容器方式部署的MySQL无法访问?

踩坑案例:容器方式部署的MySQL无法访问?

作者头像
俊才
发布2026-04-21 12:37:32
发布2026-04-21 12:37:32
1620
举报
文章被收录于专栏:数据库干货铺数据库干货铺

在容器化应用部署过程中,网络连通性问题是最常见也最令人头疼的故障之一。典型的场景是:宿主机网络一切正常,但容器内部却无法访问外网,或者外部无法连接容器提供的服务。而MySQL数据库如果部署在容器里出现无法访问时,该如何排查和解决呢?

本文根据真实案例的排坑过程来复现,包含容器方式部署MySQL数据库服务、异常复现及抓包等排查过程。

一、 MySQL容器部署

为了复现问题,先部署一个MySQL方式部署的数据库实例(各版本均可),不影响本次问题的复现。

1. 拉取镜像

代码语言:javascript
复制
[root@c7 ~]# docker pull swr.cn-south-1.myhuaweicloud.com/library/mysql:8.0

完成后如下:

2. 重命名镜像

将镜像改回标准名字,方便后续部署

代码语言:javascript
复制
docker tag swr.cn-south-1.myhuaweicloud.com/library/mysql:8.0 mysql:8.0

3. 查看镜像

4. 部署镜像

进行镜像部署及启动

代码语言:javascript
复制
docker run -d \
  --name mysql8 \
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

完成后进入容器,并测试是否可以登录:

代码语言:javascript
复制
[root@c7 ~]# docker exec -it mysql8  bash 
root@01b28da68a54:/# mysql -uroot -p123456

以上可以看到已完成MySQL容器的部署。

二、 问题复现

1. 正常情况

正常情况下,在同网段其他服务器上访问端口如下:

代码语言:javascript
复制
[root@vbox ~]# telnet  192.168.56.106 3306 
Trying 192.168.56.106...
Connected to 192.168.56.106.
Escape character is '^]'.
J
8.0.13	nN;*a}ÿ	z.>hcaching_sha2_passwordConnection closed by foreign host.

可以看到端口能正常访问

2. 复现操作

Linux中清理swap及调整vm.swappiness内核参数是比较常见的操作(并非实际原因,只是模拟异常),本次也进行此操作,即在 /etc/sysctl.conf文件中添加:

代码语言:javascript
复制
vm.swappiness = 1

完成后执行sysctl -p生效。

3. 异常现象

3.1 同网段机器访问

上述操作完毕后,发现其他节点无法访问容器里的数据库,在刚才同网段的机器探测端口如下:

此时发现端口已无法访问。

3.2 数据库的本机访问

在数据库本机上查看端口及探测端口现象如下:

可见,本机是可以正常访问的。

进入数据库也正常。

三、 问题排查

1. 检查防火墙及安全策略等

通常本机能访问,其他机器不能访问时,最先想到的便是防火墙是否正常(因为上面已经确认数据库端口及服务在本机能正常访问),于是检查如下:

代码语言:javascript
复制
[root@c7 ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)
[root@c7 ~]# getenforce 
Disabled

可见,以上情况均正常,不会影响访问。

注意: 如果是云服务器还需要检查安全组和白名单等配置。

2. 抓包检查

最直观的判断请求是否进入数据库服务器主机可以用抓包的方式进行,例如本次用tcpdump方式抓包。

代码语言:javascript
复制
# 如果没有安装的先执行安装tcpdump
yum install -y tcpdump

在数据库机器上抓包:

代码语言:javascript
复制
 tcpdump -i any -nn -s 0 -A 'host 192.168.56.106 and port 3306'

再在其他机器上进行访问(登录数据库或者telnet探测均可)

此时发现数据库机器上的抓包有接受到对应的请求,只是没有回应。

从以上的情况来看,可以确定的是:数据库服务正常;外部请求到数据库主机能通(只是对应的数据库端口无反应)。

3. 重启容器

以上的种种情况表明,数据库机器到容器端口的请求有异常,因此进行容器重启。 逐步重启如下:

3.1 重启MySQL容器

代码语言:javascript
复制
[root@c7 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
01b28da68a54        mysql:8.0           "docker-entrypoint..."   3 hours ago         Up 3 hours          0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8
[root@c7 ~]# docker  restart mysql8  
mysql8
[root@c7 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
01b28da68a54        mysql:8.0           "docker-entrypoint..."   3 hours ago         Up 3 seconds        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8

重启完毕后,其他机器再次探测(涛声依旧)。

3.2 重启容器服务

代码语言:javascript
复制
[root@c7 ~]# docker  start mysql8  
mysql8
[root@c7 ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
01b28da68a54        mysql:8.0           "docker-entrypoint..."   3 hours ago         Up 3 seconds        0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8

此时再在其他机器再次探测,居然好了。

4. 问题复现

由于只处理过内核参数调整,执行sysctl -p操作,因此,我们再次做此操作。

完成后,mysql容器正常,但是其他节点的访问确定又异常了:

此时已经可以确定就是此操作导致的。

5. 确认问题

以上的sysctl -p操作中有个不被注意的参数:

代码语言:javascript
复制
net.ipv4.ip_forward = 0

这个参数控制Linux内核是否允许转发网络数据包。为什么影响Docker呢? 经查,原因如下:

  • Docker的容器网络(默认是Bridge模式)依赖于宿主机的网络转发功能
  • 当外部请求到达宿主机(例如访问3306端口)时,宿主机需要把这个数据包转发给容器(例如172.17.0.*的3306端口)
  • 如果net.ipv4.ip_forward=0,宿主机就像一个“死胡同”,收到数据包后发现自己不是最终目的地(因为IP是容器的),就会直接丢弃,导致外部无法连接

我们当前的容器的网络确实也就是默认的:

代码语言:javascript
复制
[root@c7 ~]# docker inspect -f '{{.HostConfig.NetworkMode}}' mysql8
default

6. 恢复

我们再手动将net.ipv4.ip_forward设置为1,例如:

代码语言:javascript
复制
[root@c7 ~]# sysctl  -p 
net.ipv4.ip_forward = 1
net.ipv4.tcp_keepalive_time = 120
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_retries2 = 5
vm.swappiness = 1

此时,其他节点也能正常访问了,说明确实是此参数引起的。

7. 为何重启容器能恢复

我们之前在重启容器服务时也能恢复,是什么原因呢?经过查询,发现了容器重启后该参数也自动调整为1了。

代码语言:javascript
复制
#   先手动调整net.ipv4.ip_forward为0 
[root@c7 ~]# sysctl -w net.ipv4.ip_forward=0 
net.ipv4.ip_forward = 0
#  重启容器
[root@c7 ~]# systemctl restart docker 
# 再次查看net.ipv4.ip_forward
[root@c7 ~]# sysctl   net.ipv4.ip_forward
net.ipv4.ip_forward = 1

四、 总结

Docker网络问题虽然复杂,但大多有迹可循。通过分层排查方式进行,从底层连通性到应用层配置,逐步缩小范围。 另外,熟练掌握抓包的方式来分析,可以更准确、高效地解决问题。同时,也提醒大家用容器方式部署MySQL(或应用)需要掌握更多的知识,对于问题分析的难度也更大。

欢迎大家在留言区分享相关的数据库问题及排查过程,让更多的小伙伴避坑。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据库干货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档