承接上文深入理解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集群 配置复杂