(十)深入理解Kubernetes网络
K8s四层网络之Pod网络
Pod网络概念模型
Pod相当于是K8s云平台中的虚拟机,它是K8s的基本调度单位。
同一节点的Pod网络
-
网络依次进入的顺序为主机网卡eth0,docker虚拟网桥,虚拟网卡veth0。pause容器是一个特殊的容器,这个容器运行的唯一目的是为Pod建立共享的veth0网络接口。docker ps命令可以查看到这个容器的状态
同样的docker0在同一个Pod下面分配了172.17.2 和 172.17.3 ,这两个网络是可以互通的
-
不同节点间的Pod网络
路由方案
通过路由设备为K8s集群的Pod网络单独划分网段,并配置路由器支持Pod网络的转发。这种方案依赖于底层的网络设备,但是不引入额外性能开销。注意公有云网络不支持路由方案
覆盖网络方案
覆盖网络,就是在现有网络之上再建立一个虚拟网络,实现技术有很多,例如flannel/weavenet等等,这些方案大都采用隧道封包技术。简单理解,Pod网络的数据包,在出节点之前,会先被封装成节点网络的数据包,当数据包到达目标节点,包内的Pod网络数据包会被解封出来,再转发给节点内部的Pod网络。这种方案对底层网络没有特别依赖,但是封包解包会引入额外性能开销。
K8s容器网络接入接口CNI
考虑到Pod网络实现技术众多,为了简化集成,K8s支持CNI(Container Network Interface)标准,不同的Pod网络技术可以通过CNI插件形式和K8s进行集成。
Service网络(集群内部网络)
Service网络概念模型
服务发现(Service Discovery): Client Pod如何发现定位Account-App集群中Pod的IP?况且Account-App集群中Pod的IP是有可能会变的(英文叫ephemeral),这种变化包括预期的,比如Account-App重新发布,或者非预期的,例如Account-App集群中有Pod挂了,K8s对Account-App进行重新调度部署。
负载均衡(Load Balancing):Client Pod如何以某种负载均衡策略去访问Account-App集群中的不同Pod实例?以实现负载分摊和HA高可用。
服务发现
DNS域名服务
DNS域名服务是一种较老且成熟的标准技术,实际上DNS可以认为是最早的一种服务发现技术。
缺点:
1. 不同DNS客户端实现功能有差异,有些客户端每次调用都会去查询DNS服务,造成不必要的开销,而有些客户端则会缓存DNS信息,默认超时时间较长,当目标PodIP发生变化时(在容器云环境中是常态),存在缓存刷新不及时,会导致访问Pod失效。
2. DNS客户端实现的负载均衡策略一般都比较简单,大都是RoundRobin,有些则不支持负载均衡调用。
Service Registry+Client
例如Netflix开源的Eureka + Ribbon,HashiCorp开源的Consul,还有阿里新开源Nacos等,都是这个方案的典型代表。
K8s的Service网络
在K8s平台的每个Worker节点上,都部署有两个组件,一个叫Kubelet,另外一个叫Kube-Proxy,这两个组件+Master是K8s实现服务注册和发现的关键。
服务注册发现流程
在服务Pod实例发布时(可以对应K8s发布中的Kind: Deployment),Kubelet会负责启动Pod实例,启动完成后,Kubelet会把服务的PodIP列表汇报注册到Master节点。
通过服务Service的发布(对应K8s发布中的Kind: Service),K8s会为服务分配ClusterIP,相关信息也记录在Master上。
在服务发现阶段,Kube-Proxy会监听Master并发现服务ClusterIP和PodIP列表映射关系,并且修改本地的linux iptables转发规则,指示iptables在接收到目标为某个ClusterIP请求时,进行负载均衡并转发到对应的PodIP上。
当有消费者Pod需要访问某个目标服务实例的时候,它通过ClusterIP发起调用,这个ClusterIP会被本地iptables机制截获,然后通过负载均衡,转发到目标服务Pod实例上。
区别
- 两者都是采用客户端代理(Proxy)机制。和Ribbon一样,K8s的代理转发和负载均衡也是在客户端实现的,但Ribbon是以Lib库的形式嵌入在客户应用中的,对客户应用有侵入性,而K8s的Kube-Proxy是独立的,每个Worker节点上有一个,它对客户应用无侵入。K8s的做法类似ServiceMesh中的边车(sidecar)做法。
- Ribbon的代理转发是穿透的,而K8s中的代理转发是iptables转发,虽然K8s中有Kube-Proxy,但它只是负责服务发现和修改iptables(或ipvs)规则,实际请求是不穿透Kube-Proxy的。注意早期K8s中的Kube-Proxy代理是穿透的,考虑到有性能损耗和单点问题,后续的版本就改成不穿透了。
- Ribbon实现服务名到服务实例IP地址的映射,它只有一层映射。而K8s中有两层映射,Kube-Proxy实现ClusterIP->PodIP的映射,Kube-DNS实现ServiceName->ClusterIP的映射。
外部接入网络
LoadBalancer
Ingress
Ingress落地方案:
传统的Nginx/Haproxy可以,现代的微服务网关Zuul/SpringCloudGateway/Kong/Envoy/Traefik等等都可以。当然,谷歌别出心裁给这个东东起名叫Ingress,它还是做了一些包装,以简化对Ingress的操作。如果你理解了原理,那么完全可以用Zuul或者SpringCloudGateway,或者自己定制开发一个反向代理,来替代这个Ingress。部署的时候以普通Service部署,将type设定为LoadBalancer即可
Ingress是一个7层反向代理,如果你要暴露的是4层服务,还是需要走独立LB+IP方式
Kubectl Proxy & Port Forward
在本地开发测试环境,需要对本地部署的K8s环境中的服务或者Pod进行快速调试或测试