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

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

为什么会发生这种情况?

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

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

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


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

在 Kubernetes 集群中,通常不建议 在 Node 节点上直接运行 firewalld 或 ufw。网络隔离和安全控制应该交由 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
相关推荐
AKA__Zas32 分钟前
TCP 与 IP 浅显皮毛
服务器·网络·tcp/ip
程序员清风9 小时前
Docker、Nginx 与 Kubernetes 部署 AI 后端服务
nginx·docker·kubernetes
Zhu75810 小时前
离线二进制部署-Kubernetes-v1.36.4
容器·贪心算法·kubernetes
Lancker10 小时前
chnroute-linux — 中国大陆 IP 段每日自动更新 + 「仅允许国内访问」落地
linux·运维·tcp/ip
天衍四九-11 小时前
Docker容器实战系列(八):Docker生产最佳实践与避坑指南,系列终章
运维·docker·容器
Zelman13 小时前
协议栈数据流全景分析
网络协议·tcp/ip·https
别动我齐刘海13 小时前
简历技术栈全面复习——UDP / TCP / CAN / ZMQ / Protobuf 通信工程
网络·c++·python·tcp/ip·机器学习·udp·github
Zhou14113613 小时前
Docker_03_DockerCompose多容器编排
运维·docker·容器
程序猿阿越13 小时前
containerd如何拉取镜像
后端·kubernetes·源码阅读
Elastic 中国社区官方博客14 小时前
Kubernetes attributes processor v1:它对 EDOT Collector 意味着什么
java·大数据·elasticsearch·搜索引擎·贪心算法·kubernetes·全文检索