深入理解K8S网络原理下

承接上文深入理解K8S网络原理上

Service 应用是K8s集群内部可见的
而我们发布的应用需要外网甚至公网可以访问
K8s如何将内部服务暴露出去?
复制代码

四层网络只有Node节点网络可以对外通讯
现在问题是第2层的Service网络如何通过第0层Node节点网络暴露出去呢?
复制代码

需要再思考一个问题 在k8s服务发现原理图中 哪个组件既知道
service网络的所有信息又可以和pod网络互通互联同时又可以与节点网络打通呢?
那就是Kube-Proxy 对外暴露服务也是通过这个组件实现的

只需要让Kube-Proxy在节点上暴露一个监听端口就可以了 
所以NodePort就闪亮登场了
复制代码

NodePort

将service type设置为NodePort 端口范围在30000~32767之间
k8s发布以后 会在每个节点上都会开通NodePort端口 这个端口的背后就是Kube-Proxy

当外部流量想要访问k8s服务的时候
先访问NodePort端口 然后通过Kube-Proxy转发到内部的Service抽象层
然后再转发到目标Pod上去
复制代码

LoadBalancer 负载均衡器

如果在阿里云上有一套k8s环境
将service type设置为LoadBalancer
阿里云K8s会自动创建NodePort进行端口转发 同时也会
申请一个SLB 有独立的公网IP 并且也会自动映射K8s集群的NodePort上
以上是生产环境 就可以通过SLB暴露出去的公网IP访问到K8s集群内部的NodePort
但在开发测试环境可以直接通过NodePort访问

这种方式的劣势:

如果暴露一个服务就需要购买一个LB+IP
如果暴露10个服务就需要购买10个LB+IP
所以成本比较高
那有没有办法购买一个LB+IP能不能将更多的服务暴露出去呢?
那么Ingress就闪亮登场了
也就是在K8s内部部署一个独立的反向代理服务 让它做代理转发
复制代码

Ingress

Ingress是一个特殊的service 通过节点80/443暴露出去
Ingress可以通过path或者域名转发到Service抽象层然后转发到Pod
只需要设置好转发的路由表即可
本质上和Nginx没有差别
service kind设置为ingress
ingress提供的主要功能是七层反向代理 如果暴露的是四层服务还是需要走LB+IP方式
还可以做安全认证、监控、限流、证书等高级功能
有了Ingress就可以购买一个LB+IP就可以将k8s集群中的多个service暴露出来
复制代码

本地环境想要快速的开发调试方法

kubectl proxy

通过kubectl proxy在本机创建一个代理服务 
通过这个代理服务可以访问k8s集群内任意的http服务
通过master上的api server间接的去访问k8s集群内的服务
因为master是知道集群内所有服务的信息
这种方式仅限于七层的http转发
复制代码

kubectl Port-Forwarding

在本机上开启一个转发端口间接转发到k8s内部某个pod端口上去
这种方式支持http转发和tcp转发
复制代码

kubectl exec

通过该命令直接连接到pod上去执行命令
复制代码

小结

深入理解Kube-Proxy

Kube-Proxy主要实现服务发现和负载均衡以及ClusterIP到PodIP的转换

Kube-Proxy通过linux内核提供的2个机制间接实现

"Netfilter"和"iptables"

通过这2个机制的配合来实现IP地址的转换以及流量的路由

Netfilter是linux内核支持的一种钩子方法 允许内核的其他模块注册回调方法

这些回调方法可以截获网络包 可以改变它们的目的地路由

iptables是一组用户空间程序 

通过它可以设置Netfilter中的路由规则 

iptables程序可以检查、转发、修改、重定向或者丢弃ip网络包

iptables是Netfilter用户空间接口 可以间接操作Netfilter中的路由规则
复制代码

Kube-Proxy可以通过iptabels程序可以去操作内核空间的Netfilter里面的路由规则
而Netfilter可以截获底层的IP网络包就可以修改它们的路由
复制代码

Kube-Proxy的工作模式

  • 用户空间代理模式
大部分的网络功能 包括设置包路由规则、负载均衡都是由运行在用户空间的Kube-Proxy直接完成的
它监听请求 执行路由和负载均衡 将请求转发到目标pod
在该模式下 kube-proxy还需要频繁在用户空间和内核空间切换
因为它需要和iptables交互来实现负载均衡
复制代码

1、kube-proxy 监听 master 服务创建、更新、删除事件
   也监听这些服务对应的端点的地址
   如果pod ip发生了变化 kube-proxy也会同步这种变化
   
2、当有一个类型为ClusterIp的新服务被创建 Kube-Proxy会在节点上创建一个随机的端口 比如在10.100.0.2上开启一个随机端口10400
通过这个端口可以将目标请求转发到对应的端点上即pod上面

3、通过iptables设置转发规则 比如请求ip是10.104.14.67:80这个请求转发到10.100.0.2:10400这个地址上去

4、当节点上面有客户端对10.104.14.67:80这个service ip以及对应的podip10.100.0.2:10400发起调用的话  

5、这个请求会被netfilter截获到并且转发到10.100.0.2:10400这个上面 也就是kube-proxy正在监听的端口

6、kube-proxy接受这个请求 通过负载均衡 转发到pod上面

上面1-3步是服务发现阶段

4-6部是运行阶段

将请求转发到10400端口 kube-proxy先切换到内核接受这个请求包

然后切换到用户空间进行负载均衡调用

由于频繁的上下文切换 这种模式的性能并不理想

所以又引入了iptabels模式
复制代码

iptables模式

1、kube-proxy会监听master上面的服务创建或者删除
也会监听服务背后所对应的pod ip地址
2、当有一个类型为clusterip的新服务被创建 kube-proxy通过iptables直接设置转发规则 并直接负载均衡转发到目标pod上面

不穿透kube-proxy 性能高
但iptables不支持高级的负载均衡策略也不支持失效自动重试机制
一般需要就绪探针进行配合

这种模式仅适用于中小模式的k8s集群 不适用大规模的k8s集群

假设有5000个节点的集群 集群有2000个服务 每个服务有10个pod 就需要在每个节点同步大约2万条记录 同时在云环境中 后端pod ip可能会随时变化 会给linux内核带来巨大的开销 

为了支持更大规模的k8s集群 引入了IPVS Proxy模式
复制代码

IPVS Proxy模式

该模式是linux内核支持的虚拟化构建技术 是建立在netfilter基础之上的 是为了内核传输层高性能的负载均衡设计的技术
也是LVS主要的组成技术 

不仅支持缺省的Round Robbon(加权轮询)还支持最小连接、目标源hash 负载均衡算法 

使用高效的hash算法来存储网络路由规则 可以显著减少iptables的同步开销  大大提升集群的扩展规模 

Kube-Proxy通过调用Netfilter接口来创建和同步IPVS规则的
实际的路由转发和负载均衡由IPVS负责

IPVS效率最高 扩展性最好 配置也是最复杂的
复制代码

小结

  • 用户空间代理模式 已淘汰
  • Iptables模式 生产适用 中小规模k8s集群
  • IPVS模式 生产使用 大规模K8s集群 配置复杂

猜你喜欢

转载自juejin.im/post/7018200407935549453