centos7 docker中的 redis不能访问

CentOS Docker Redis 端口映射外部无法访问问题排查与解决

1. 问题背景

在 CentOS 虚拟机中通过 Docker 启动 Redis 容器,并进行端口映射:

docker run -d \
  --name redis \
  -p 6379:6379 \
  redis/redis-stack:latest

虚拟机 IP 为:

192.168.1.11

Windows 宿主机 IP 为:

192.168.1.5

目标是让 Windows 宿主机访问虚拟机中的 Redis:

192.168.1.11:6379

2. 问题现象

2.1 容器运行正常

执行:

docker ps

可以看到 Redis 容器正常运行,且 6379 端口已映射。

2.2 虚拟机本机访问正常

在 CentOS 虚拟机中执行:

redis-cli -h 127.0.0.1 -p 6379
redis-cli -h 192.168.1.11 -p 6379

可以正常连接。

说明:

  • Redis 服务正常
  • Docker 端口映射对本机访问有效

2.3 Windows 宿主机访问失败

在 Windows 上执行:

Test-NetConnection 192.168.1.11 -Port 6379

测试失败,连接超时。

说明:

  • 外部无法访问 Redis 的映射端口

3. 排查过程

3.1 检查 Docker 端口映射是否正常

执行:

docker port redis
docker inspect redis

确认 Redis 容器端口映射存在,6379 已映射到宿主机。

另外确认容器 IP:

docker inspect -f '{{ .NetworkSettings.IPAddress }}' redis

输出:

172.17.0.2

说明容器实际运行在 Docker 默认网桥网络中。

3.2 抓取宿主机物理网卡流量

在 CentOS 上执行:

tcpdump -nn -i ens33 host 192.168.1.5 and port 6379

抓包结果显示 Windows 发来的 SYN 报文可以到达宿主机网卡。

说明:

  • Windows 到 CentOS 宿主机网络是通的
  • VMware 网络本身没有问题

3.3 抓取 docker0 网桥流量

执行:

tcpdump -nn -i docker0 port 6379

没有看到任何流量。

说明:

  • 数据包到达了宿主机
  • 但没有继续进入 Docker 网桥
  • 问题在宿主机内核转发、NAT 或防火墙链路

3.4 检查 NAT 规则是否命中

执行:

iptables -t nat -L -n -v | grep 6379

输出类似:

0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:6379
65  3420 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:6379 to:172.17.0.2:6379

说明:

  • Docker 的 DNAT 规则已经生效
  • 外部访问 6379 时,目标地址已经转换为容器地址 172.17.0.2:6379

3.5 检查转发链

执行:

iptables -L FORWARD -n -v
iptables -S DOCKER-USER
iptables -S DOCKER

关键输出如下:

Chain FORWARD (policy DROP)
...
ACCEPT all -- * docker0  ctstate RELATED,ESTABLISHED
DOCKER all -- * docker0
ACCEPT all -- docker0 !docker0

以及:

-A DOCKER-USER -j RETURN

和:

-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 6379 -j ACCEPT

说明:

  • DOCKER-USER 没有额外拦截
  • Docker 的 FORWARD 规则正常
  • 6379 到容器的 ACCEPT 规则存在

因此,问题不在 iptables 放行规则本身。

3.6 检查内核 IP 转发开关

执行:

sysctl net.ipv4.ip_forward

输出:

net.ipv4.ip_forward = 0

这就是根因。


4. 根因分析

Linux 内核参数:

net.ipv4.ip_forward

控制系统是否允许 IPv4 转发。

当其值为 0 时:

  • 主机只处理发给自己的数据包
  • 不会将收到的数据包转发到其他网络接口
  • Docker 即使完成了 DNAT,也无法把流量继续转发到 docker0 和容器网络

因此出现如下现象:

  • ens33 能看到外部 SYN
  • nat PREROUTING 已命中 DNAT
  • docker0 上看不到流量
  • 外部访问 Redis 超时

5. 解决方案

5.1 临时生效

执行:

sysctl -w net.ipv4.ip_forward=1

验证:

sysctl net.ipv4.ip_forward

期望输出:

net.ipv4.ip_forward = 1

之后重新从 Windows 测试:

Test-NetConnection 192.168.1.11 -Port 6379

通常即可恢复正常。


6. 建议同时调整的参数

为了避免 Docker、多网桥、虚拟化场景下出现反向路径校验导致的丢包,建议同时设置:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

参数说明:

  • net.ipv4.ip_forward = 1
    开启 IPv4 转发,允许宿主机把外部流量转发到容器网络

  • net.ipv4.conf.all.rp_filter = 0
    关闭所有网卡的反向路径过滤,避免复杂网络场景下误丢包

  • net.ipv4.conf.default.rp_filter = 0
    关闭新建网卡的默认反向路径过滤,避免后续 Docker bridge 默认启用严格检查


7. 持久化配置

7.1 推荐方式:写入 /etc/sysctl.d/

创建配置文件:

cat > /etc/sysctl.d/99-docker-network.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
EOF

加载配置:

sysctl --system

7.2 也可写入 /etc/sysctl.conf

编辑:

vi /etc/sysctl.conf

加入:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

执行:

sysctl -p

8. 验证配置

执行:

sysctl net.ipv4.ip_forward
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter

期望输出:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

9. 最终结论

本次问题的根因不是:

  • Redis 服务异常
  • Docker 端口映射错误
  • Windows 防火墙问题
  • VMware 网络不通

真正根因是:

net.ipv4.ip_forward = 0

导致外部访问到达 CentOS 宿主机后,无法继续转发到 Docker 容器网络。

将其修改为:

net.ipv4.ip_forward = 1

后,外部访问恢复正常。


10. 可直接执行的命令

10.1 临时生效

sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.default.rp_filter=0

10.2 永久生效

cat > /etc/sysctl.d/99-docker-network.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
EOF

sysctl --system

10.3 验证

sysctl net.ipv4.ip_forward
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter

11. 故障定位关键证据汇总

11.1 容器 IP

docker inspect -f '{{ .NetworkSettings.IPAddress }}' redis

输出:

172.17.0.2

11.2 NAT 命中

iptables -t nat -L -n -v | grep 6379

输出:

0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:6379
65  3420 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:6379 to:172.17.0.2:6379

11.3 内核转发关闭

sysctl net.ipv4.ip_forward

输出:

net.ipv4.ip_forward = 0

12. 一句话总结

外部流量已经到达宿主机并完成 DNAT,但由于 CentOS 未开启 net.ipv4.ip_forward,数据包无法继续转发到 Docker 容器,导致 Redis 映射端口外部访问失败。

posted @ 2026-04-10 14:00  白开水233  阅读(1)  评论(0)    收藏  举报