Docker Swarm Overlay网络:服务可Ping通但TCP连接失败
问题
我运行着一个包含两个节点的Docker Swarm集群:管理节点(10.1.109.70)、工作节点(10.1.109.60)。创建了overlay网络(my-swarm-net),并在两个节点上部署了MySQL和Nginx服务。容器之间可互相Ping通,但telnet、nc、MySQL、HTTP等TCP连接均失败,例如从mysql1可Ping通mysql2,但无法通过telnet连接mysql2的3306端口,从nginx1也无法telnet连接nginx2的80端口。
在管理节点执行docker network inspect my-swarm-net仅能看到mysql1和nginx1,运行在工作节点的mysql2和nginx2未显示;在工作节点执行该命令,发现工作节点并未接入该网络。
已检查MySQL和Nginx端口监听正常、防火墙已开放所需端口(2377、7946、4789、3306、80),尝试重建网络并强制更新服务后问题仍存在。现咨询:
- 为何容器可Ping通但无法建立TCP连接?
- 如何确保所有服务正确加入overlay网络并实现TCP通信?
环境与配置
Swarm状态(docker info简化输出)
Swarm: active Nodes: 2 Managers: 1 Overlay network: my-swarm-net
docker-compose.yml
version: "3.9" services: mysql1: image: mysql:8.0.41-debian networks: - my-swarm-net deploy: placement: constraints: - "node.role == manager" mysql2: image: mysql:8.0.41-debian networks: - my-swarm-net deploy: placement: constraints: - "node.role == worker" nginx1: image: nginx:latest networks: - my-swarm-net deploy: placement: constraints: - "node.role == manager" nginx2: image: nginx:latest networks: - my-swarm-net deploy: placement: constraints: - "node.role == worker" networks: my-swarm-net: driver: overlay attachable: true
已检查内容
- 在mysql2容器内执行
ss -tulnp | grep 3306,输出:
tcp LISTEN 0 151 *:3306 *:*
- CentOS Stream 9防火墙规则:
sudo firewall-cmd --list-ports显示所有所需端口已开放。
尝试过的操作
docker network rm my-swarm-net docker network create --driver=overlay --attachable my-swarm-net docker service update --force mysql2
- 工作节点执行
docker ps显示mysql2和nginx2正在运行。
问题解答
1. 为何容器可Ping通但无法建立TCP连接?
Ping基于ICMP协议,容器能Ping通说明节点间的基础网络连通性没问题,但TCP连接失败且工作节点未接入overlay网络,核心原因是工作节点的overlay网络未正确初始化或同步:
- 虽然容器在工作节点运行,但它们实际并未加入
my-swarm-net,而是使用了默认的bridge网络(或临时网络),所以只能通过节点间的基础网络进行ICMP通信,无法通过overlay网络的TCP路由访问容器端口。 - Swarm集群中,overlay网络需要跨节点同步配置,工作节点可能因Swarm agent通信异常、网络驱动加载失败,导致未成功加入集群的overlay网络,进而容器无法获取overlay网络的TCP转发规则。
2. 如何确保所有服务正确加入overlay网络并实现TCP通信?
按以下步骤排查修复:
步骤1:验证Swarm节点状态与通信
在管理节点执行:
docker node ls
确保工作节点状态为Ready,如果显示Down或Unreachable,先修复节点间的Swarm通信:
- 检查工作节点的Docker daemon是否正常运行:
systemctl status docker - 在工作节点重新加入Swarm集群:先执行
docker swarm leave --force,再从管理节点获取加入命令(docker swarm join-token worker)重新加入。
步骤2:通过栈部署同步网络配置
不要手动创建网络后更新服务,直接通过docker stack deploy重新部署整个栈,确保网络配置自动同步到所有节点:
- 删除现有服务:
docker stack rm <你的栈名>
- 重新部署:
docker stack deploy -c docker-compose.yml <你的栈名>
步骤3:检查工作节点的overlay网络状态
在工作节点执行:
docker network ls
确认my-swarm-net存在。如果不存在,检查Docker的overlay驱动是否正常加载:
docker info | grep -A5 "Overlay"
确保输出中包含Overlay: true,如果驱动异常,重启Docker daemon:
systemctl restart docker
重启后重新加入Swarm并部署服务。
步骤4:验证容器的网络归属
在工作节点执行:
docker inspect <mysql2容器ID> | grep -A10 "Networks"
确认容器的Networks列表中包含my-swarm-net,而非默认的bridge网络。如果仍未加入,删除该服务并重新部署:
docker service rm mysql2 nginx2 docker stack deploy -c docker-compose.yml <你的栈名>
步骤5:补充防火墙规则
CentOS Stream 9的firewalld可能需要允许Docker的overlay子网流量,除了开放端口,添加富规则允许容器子网通信:
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" accept' --permanent sudo firewall-cmd --reload
注:10.0.0.0/8是Docker默认的overlay子网段,可通过
docker network inspect my-swarm-net查看实际子网后调整。
内容的提问来源于stack exchange,提问作者mohamedyahya messaoud

