承接上文深入理解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效率最高 扩展性最好 配置也是最复杂的
小结