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
相关推荐
MrSYJ14 小时前
TCP协议理解
后端·tcp/ip
运维开发故事1 天前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Patrick_Wilson3 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生3 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭4 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美5 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵5 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
武子康8 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
treesforest11 天前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全