Docker容器间无法通信求助:Nginx、PHP-FPM、MariaDB经典服务栈故障排查
Docker容器间端口连通性故障排查方案
看起来你遇到了挺棘手的Docker服务栈问题:容器能ping通但端口连不上,还没法访问外网。结合你给出的所有配置和测试信息,我整理了几个优先级从高到低的排查方向和解决方案:
1. 先排查宿主机的防火墙与SELinux配置
CentOS 8自带的firewalld和SELinux是Docker网络故障的高频诱因,咱们先从这里入手:
- 临时关闭firewalld测试:执行
systemctl stop firewalld,然后重新在容器内测试nc连通性和外网ping。如果问题解决,说明防火墙规则拦截了容器间的端口流量。 - 检查SELinux状态:执行
sestatus,如果输出是SELinux status: enabled且模式为Enforcing,临时切换为宽容模式:setenforce 0,再测试网络。 - 永久修复(如果临时关闭有效):
- 对于firewalld:可以添加规则允许Docker容器子网(你的是
172.22.0.0/16)的流量,或者直接启用Docker的firewalld集成(Docker 20.10+支持自动配置,但可能需要重启服务)。 - 对于SELinux:如果是测试环境,可以编辑
/etc/selinux/config,将SELINUX=enforcing改为SELINUX=disabled,重启服务器生效;生产环境则需要调整SELinux策略,允许Docker容器的网络行为。
- 对于firewalld:可以添加规则允许Docker容器子网(你的是
2. 验证Docker的iptables规则是否正常
Docker的bridge网络依赖iptables进行流量转发,规则被重置或损坏会导致端口不通:
- 执行
iptables -t nat -L -n,查看是否存在DOCKER链,以及是否有针对容器子网的转发规则(比如DNAT规则指向容器IP和端口)。 - 如果规则异常,尝试重置Docker网络配置:
- 停止Docker服务:
systemctl stop docker - 删除Docker网络存储文件:
rm -f /var/lib/docker/network/files/local-kv.db - 重启Docker:
systemctl start docker,然后重新启动你的服务栈:docker-compose up -d
注意:这会清空所有自定义Docker网络,需要重新创建服务栈的网络。
- 停止Docker服务:
3. 确认容器内端口是否监听正确
虽然docker-compose ps显示端口处于开放状态,但要确保进程真的在监听所有接口(而不是仅127.0.0.1):
- 进入web-php容器,执行
ss -tulpn | grep 9000,检查输出是否包含0.0.0.0:9000。如果是127.0.0.1:9000,说明php-fpm仅监听本地回环,容器外无法访问,需要修改php-fpm的www.conf配置文件(通常在/usr/local/etc/php-fpm.d/www.conf),将listen = 127.0.0.1:9000改为listen = 0.0.0.0:9000,然后重启容器。 - 进入web-mariadb容器,执行
ss -tulpn | grep 3306,确认mariadb监听的是0.0.0.0:3306(默认应该是,但如果有自定义配置可能被修改)。
4. 检查Nginx配置的路径匹配问题(额外注意点)
你的Nginx配置里fastcgi_param SCRIPT_FILENAME /script$fastcgi_script_name;这个路径可能有问题:如果你的PHP代码在web-php容器的/var/www/html目录下,这里应该改成/var/www/html$fastcgi_script_name,否则即使端口连通,php-fpm也找不到脚本文件,会返回502错误。
5. 测试宿主机到容器端口的连通性
在宿主机上直接测试容器端口:
nc -v 172.22.0.3 9000(连接web-php的9000端口)nc -v 172.22.0.4 3306(连接web-mariadb的3306端口)
如果宿主机也连不上,说明问题出在宿主机网络层面(防火墙/SELinux/iptables);如果宿主机能连上,那可能是容器内的网络配置问题,但结合你能ping通的情况,这种概率较低。
按照这个顺序排查,应该能快速定位到问题根源,优先处理防火墙和SELinux,这在CentOS 8上是最常见的Docker网络坑点。
内容的提问来源于stack exchange,提问作者nabbo




