需求背景
- 服务 A 部署在 K8S 中,集群外的服务 B 需要调用服务 A,同时调用服务 A 的端口是指定了的,必须是 5000,无法修改。
- K8S 集群是客户的,我们只能部署服务,不能修改集群。
- 服务 A 需要得到真实的客户端 IP。
解决方案一
通过 Nodeport 的方式暴漏服务 A。
5000 端口不在 Nodeport 默认端口范围内(30000-32767)。 修改 Nodeport 的端口范围,需要修改 kube-apiserver 配置,行不通。
解决方案二
服务 A 的 Pod 配置hostNetwork: true
。
服务 A 内部还有其他进程,监听了端口,容易和节点的其他进程冲突。同时还会暴漏服务 A 内部的其他服务。
解决方案三
新增一个 nginx Pod,并配置hostNetwork: true,dnsPolicy: ClusterFirstWithHostNet
,通过七层代理来转发流量到服务 A 的 service。
服务 B 调用服务 A 时,原本是使用服务 A 的 ssl 证书。但是在七层代理下,会使用这个 nginx 的证书。而证书是服务 A 生成的,不太好自动配置给 nginx。
解决方案四
新增一个 nginx Pod,并配置hostNetwork: true,dnsPolicy: ClusterFirstWithHostNet
,通过四层代理来转发流量到服务 A 的 service。nginx 启用 proxy protocol
,用来传递真实的客户端 IP。
proxy protocol 需要后端应用支持,nginx、apache 这些都是支持了的,此方案可行。
解决方案五
新增一个 ubuntu Pod,并配置hostNetwork: true
,通过 iptables
来转发流量。
- 如果客户的 K8S kube-proxy 是 IPVS 方案
- 将服务 A 通过 nodeport 暴漏到 30001,同时设置 iptables,将 5000 端口流量转发到 30001端口。
- 如果客户的 K8S kube-proxy 是 iptables 方案
- 由于在nat表里面对数据包进行dnat操作过后,数据包就不再执行nat表里面的其它规则,所以不能将流量转发到 service、nodeport,只能直接转发到服务 A 的 pod ip。
- 由于 pod ip 不固定,假如 pod 重新创建,就需要更新 iptables 规则里的 pod ip,所以需要当前服务去 watch pod。
针对方案四中,后端应用不支持 proxy protocol 协议的情况,可以用这个方案。实现较为复杂。