一次客户需求引发的K8S网络探究
字数 2727 2025-08-12 11:34:16
Kubernetes网络深入解析:从ClusterIP访问到masqueradeAll参数
1. Kubernetes Service类型概述
Kubernetes Service是Kubernetes中用于暴露Pod服务的核心抽象,主要有以下几种类型:
1.1 ClusterIP类型
- 默认Service类型,创建时不指定类型则默认为ClusterIP
- 只能在集群内通过Cluster IP被Pod和Node访问
- 集群外部无法直接访问
- 适用于Kubernetes集群系统服务等不需要对外暴露的服务
1.2 NodePort类型
- 解决集群外部对Service的访问需求
- 将Service端口映射至集群每个节点的固定端口上
- 集群外通过节点IP和指定端口访问服务
- 缺点:多个节点时需要客户端处理多个节点IP地址
1.3 LoadBalancer类型
- 通常需要调用云厂商API创建负载均衡产品
- 底层仍使用NodePort机制
- 将节点设置为负载均衡后端
- 优点:
- 统一访问LB IP
- 节点无需绑定公网IP
- 利用LB健康检查实现高可用
2. 特殊需求场景分析
2.1 客户需求
- 在办公网环境直接访问K8S集群的ClusterIP类型Service和后端Pod
- 现有环境:
- 托管K8S集群产品部署的测试集群
- 上百个ClusterIP类型Service
- 改造为LB或NodePort类型工作量巨大
2.2 常规解决方案的限制
- LB类型:需创建大量LB实例和公网IP,不现实
- NodePort类型:改造工作量大,且节点无公网IP
- NAT主机跳转:需共享系统密码,运维管理不便
3. 网络打通方案设计与实施
3.1 网络架构分析
- 客户办公网:统一公网出口设备
- 云上K8S集群网络架构:
- Master节点对用户不可见
- 三个子网:
- Node子网:K8S节点通讯
- NAT与LB子网:NAT主机和LB实例
- Pod子网:Pod通讯
- Pod网络架构:
- 通过veth对与docker0设备连通
- docker0与节点网卡通过CNI插件连通
- 控制流量与数据流量分离
- 每个节点绑定弹性网卡专供Pod通讯
3.2 打通方案选择
- 专线产品:无法满足需求(路由只能指向VPC,不能指向具体节点)
- 自建VPN(IPSec隧道):
- 云上端点:与集群同VPC不同子网的云主机
- 办公网端点:有公网IP的设备
- 配置路由:
- 办公网到Service/Pod的路由指向集群节点
- 节点/Pod子网到客户端的路由指向VPN端点
3.3 测试环境搭建
- 模拟办公网:华东上海地域云主机
- 云上端点:华北北京地域K8S集群所在VPC的NAT/LB子网云主机
- 路由配置:
- NAT/LB子网:到Service网段路由指向集群节点
- Node子网和Pod子网:到上海云主机路由指向IPSec端点
4. 问题发现与分析
4.1 初步测试结果
- 部分Service可访问(如nginx),部分不可访问(如mysql)
- 直接访问Pod均可连通
4.2 关键发现
- 可访问的Service:后端Pod位于请求转发到的节点上
- 不可访问的Service:后端Pod不在请求转发到的节点上
4.3 深入分析
4.3.1 转发至Pod所在节点时的数据流
- 客户端请求Service IP
- Service做DNAT,将请求转发至后端Pod IP
- Pod回包给Service,再由Service转发给客户端
- 整个过程在节点内部虚拟网络中完成
- 数据通路:
- 客户端 → IPSec端点 → 节点 → Service → Pod
- Pod → Service → 节点 → IPSec端点 → 客户端
4.3.2 转发至Pod不在节点时的数据流
- 客户端请求转发节点上的Service
- Service做DNAT,将请求转发到Pod所在节点
- Pod回包时:
- 源IP为Pod IP,目的IP为客户端IP
- 受Pod子网路由控制,回包被"劫持"到IPSec端点
- 云平台网络机制丢弃"只有reply没有request"的包
- 导致客户端收不到回包
4.3.3 为什么可以ping通Service
- ICMP包由Service直接应答客户端
- Service代替后端Pod答复ping包
- 即使Service没有后端Pod也能ping通
5. 解决方案:masqueradeAll参数
5.1 kube-proxy工作模式
- userspace模式:1.2版本前使用,真实TCP/UDP代理
- iptables模式:默认模式,通过iptables规则转发
- IPVS模式:1.8+引入,高性能负载均衡,需配合iptables使用
5.2 masqueradeAll参数
- 功能:对所有通过Service的流量进行SNAT
- 效果:
- 客户端和Pod互相不知道彼此存在
- 所有交互通过Service转发
- Pod回包源IP被替换为Service IP
- 避免回包被丢弃
5.3 配置方法
- 编辑kube-proxy的ConfigMap:
apiVersion: v1 kind: ConfigMap metadata: name: kube-proxy-config namespace: kube-system data: config.conf: | masqueradeAll: true - 删除现有kube-proxy Pod(DaemonSet会自动重建)
5.4 启用后的数据流
- 客户端请求Service IP
- Service做SNAT:
- 请求:客户端IP → Service IP 转换为 Service IP → Pod IP
- 响应:Pod IP → Service IP 转换为 Service IP → 客户端IP
- 数据通路:
- 客户端 → IPSec端点 → 转发节点 → Pod所在节点 → Pod
- Pod → Pod所在节点 → 转发节点 → IPSec端点 → 客户端
6. 总结与最佳实践
6.1 关键知识点
- ClusterIP类型Service设计上不推荐直接从集群外访问
- 跨节点访问Service时的回包路由问题
- kube-proxy的masqueradeAll参数工作机制
- Service对ICMP请求的特殊处理
6.2 生产环境建议
- 尽量避免直接从集群外访问ClusterIP类型Service和Pod
- masqueradeAll参数对集群网络性能的影响需评估
- 优先考虑LB类型Service对外暴露服务
- 如需特殊访问,建议结合网络策略加强安全控制
6.3 问题排查方法论
- 明确问题现象和边界条件
- 分析网络架构和数据流向
- 使用tcpdump等工具抓包分析
- 研究相关组件工作机制和参数
- 小范围验证后再推广
通过这个案例,我们深入理解了Kubernetes Service的网络机制,特别是ClusterIP类型Service的访问原理和跨节点访问时的特殊问题,以及如何通过kube-proxy的masqueradeAll参数解决这些问题。