k8s 开启防火墙,容器内部无法访问外部 ip

在 Kubernetes 环境中,节点(宿主机)开启防火墙后导致容器内部无法访问外部/内网 IP,这是一个非常典型的问题。

为什么会发生这种情况?

Kubernetes 的网络插件(从 ip a 输出中可以看到 cali*tunl0,说明使用的是 Calico )和容器运行时(Docker/Containerd)严重依赖 Linux 的 iptablesipvs 来进行流量转发(Forwarding)、路由和源地址转换(SNAT/Masquerade)。

当手动开启系统的防火墙(如 firewalldufw)时,防火墙会清空或覆盖 Kubernetes 和 Calico 原本精心配置的 iptables 规则,并且默认的防火墙策略通常会拒绝转发(FORWARD)流量。导致容器发出的数据包无法被正确 NAT(伪装)并转发到宿主机的物理网卡(enp125s0f0)。

这里为提供两种解决方案:


方案一:关闭宿主机防火墙(K8s 官方及业界强烈推荐)

在 Kubernetes 集群中,通常不建议 在 Node 节点上直接运行 firewalldufw。网络隔离和安全控制应该交由 Kubernetes 的 NetworkPolicy 和云提供商的安全组(或物理防火墙)来实现。

如果环境允许,最彻底且无副作用的方法是关闭并禁用它:

如果是 CentOS/RHEL (firewalld):

bash 复制代码
systemctl stop firewalld
systemctl disable firewalld

如果是 Ubuntu/Debian (ufw):

bash 复制代码
ufw disable

关键的一步:重建 K8s 网络规则

关闭防火墙后,必须让 CNI 重新写入 iptables 规则:

  1. 重启容器运行时(根据环境选择):
bash 复制代码
systemctl restart containerd
# 或者
systemctl restart docker
  1. 重启 Calico 和 Kube-proxy 从而重建规则:
bash 复制代码
   kubectl delete pod -n kube-system -l k8s-app=calico-node
   kubectl delete pod -n kube-system -l k8s-app=kube-proxy

方案二:必须开启防火墙的解决办法(配置放行规则)

如果因为公司合规或安全要求,宿主机必须开启防火墙,需要手动对防火墙进行配置,放行 Kubernetes 的网络流量并开启 IP 伪装。

使用的是 firewalld(CentOS/RHEL 等主流环境):

1. 开启 IP 伪装 (Masquerade)

容器访问内网 10.110.151.44 必须经过 SNAT(源地址转换),否则目标服务器无法将回包路由回容器的内网 IP(如 10.244.x.x)。

bash 复制代码
firewall-cmd --permanent --add-masquerade
2. 将 Calico 和容器网卡加入信任区

ip a 可以看到有很多 caliXXX 虚拟网卡以及 tunl0 隧道网卡,必须放行这些网卡的流量:

bash 复制代码
# 信任 Calico 的虚拟网卡
firewall-cmd --permanent --zone=trusted --add-interface=cali+
# 信任 IPIP 隧道网卡
firewall-cmd --permanent --zone=trusted --add-interface=tunl0
# 如果有 docker0 或 cni0 也一并加入
firewall-cmd --permanent --zone=trusted --add-interface=docker0
3. 允许网卡之间的转发 (FORWARD)

防火墙可能默认 drop 了 forward 链的包:

bash 复制代码
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 1 -j ACCEPT
4. 重载防火墙并重启网络组件

让防火墙配置生效:

bash 复制代码
firewall-cmd --reload

防火墙重启后,K8s 之前的 iptables 规则又会被冲刷掉,因此必须重新触发 Calico 写入规则

bash 复制代码
# 重启 Calico 节点组件
kubectl delete pod -n kube-system -l k8s-app=calico-node

验证修复结果

完成上述任意一种方案后,进入一个容器内部测试连通性:

bash 复制代码
kubectl exec -it <Pod名称> -n <对应Namespace> -- sh
# 在容器内 ping 目标内网 IP
ping 10.110.151.44
相关推荐
发光小北1 小时前
Profinet 从站转 EtherNet/IP 从站网关如何应用?
网络·网络协议·tcp/ip
wangl_921 小时前
Modbus RTU 与 Modbus TCP 深入指南-Wireshark抓包分析实战
网络协议·tcp/ip·wireshark·tcp·modbus·rtu
叶帆2 小时前
【YFIOs】Docker方式部署
运维·docker·容器
小猿姐2 小时前
Clickhouse Kubernetes Operator 实测:哪种方案更适合生产?
运维·数据库·kubernetes
岳来3 小时前
Docker 的 --privileged 特权模式学习
docker·容器·--privileged
源远流长jerry3 小时前
Linux 网络发送机制深度解析:从应用到网线
linux·服务器·网络·网络协议·tcp/ip
怀旧,5 小时前
【Linux网络编程】8. 网络层协议 IP
linux·网络·tcp/ip
cen__y5 小时前
Linux11(网络编程)
linux·运维·服务器·c语言·网络·网络协议·tcp/ip
脑子加油站5 小时前
k8s-持久化存储
云原生·容器·kubernetes·k8s-持久化存储