首发于:ciii's blog
概述
K8S官方文档集群网络描述了实现K8S网络的四个要点:
- 高度耦合的容器间通信
- Pod间通信
- Pod到Service的通信
- 外部到Service的通信
- Highly-coupled container-to-container communications
- Pod-to-Pod communications
- Pod-to-Service communications
- External-to-Service communications
解析
容器间通信
在这种情况下,一个Pod下的两个容器是共享存储、网络的,所以只需要通过localhost来进行互相访问。
Pod间通信
Pod间通信的基础是:
- 集群内的每一个Pod都拥有一个独立的IP
- 任意Pod可以通过IP互连
K8S是通过CNI(Container Network Interface)插件来实现这一扁平化的网络模型的,主要有以下几种:
- Flannel
- Calico
- Weave Net
具体的原理和实现暂时略过,后续会在CNI专题中详细展开。
Pod到Service的通信
访问方式:
- 集群内容器通过 <service>.<namspace>:<port> 访问跨namespace的service
- 集群内容器通过 <service>:<port> 访问同namespace的service
主要过程:
DNS解析:
在容器中,根据 /etc/resolve.conf 中的配置进行解析,nameserver为集群DNS服务的ClusterIP,search域则是域名匹配的顺序。
nameserver 10.254.25.10
search default.svc.cluster.local svc.cluster.local cluster.local
根据该search域,匹配步骤如下(target为访问域名):
- target.default.svc.cluster.local
- target.svc.cluster.local
- target.cluster.local
每一步拼接得到的域名,都会查询集群DNS服务,若记录存在,则直接返回对应Service的ClusterIP。
Service负载均衡(非Headless Service):
上一步DNS解析中得到了Service的ClusterIP,映射到每一个Pod的PodIP的工作则是由kube-proxy负责的。
集群中的每个Node都运行了kube-proxy服务,它订阅了API server中的Service和Endpoint对象,一旦发生变化,就会修改本机的iptables规则。
当容器内访问Service的ClusterIP时,会被宿主机的iptables修改为对应Pods中任一Pod的IP,从而实现Pod到Service的通信。
外部到Service的通信
NodePort:
通过监听每个Node上的固定端口来暴露Service
当有NodePort类型的Service被创建时,kube-proxy就会创建对应的iptables规则,使访问<NodeIP>:<NodePort>的流量转发到对应的<PodIP>:<ContainerPort>上。
这种方式一般需要结合外部的LB来使用。
LoadBalancer:
通过Cloud Provider创建外部LB来暴露Service
LoadBalancer类型的Service绑定的外部LB把流量转发到<NodeIP>:<NodePort>上,本质上与NodePort类型的Service没有区别,只是自动创建并配置了外部LB。
Ingress:
通过Ingress Controller来路由暴露Service
上述两种暴露方式都只能暴露单一Service,如果一个集群中有若干Service需要对外暴露,Ingress的暴露方式会更合适。
不同于上述两种方式,只需要指定Service的类型,这里引入了Ingress资源:
- 同时集群内还部署了一个Ingress Controller服务,并订阅了API server中的Ingress和Endpoint对象;
- 当一个Ingress创建时,Ingress Controller会根据Ingress配置添加路由规则;
- Ingress这种模式通过配置不同的路由把集群内多个Service通过一个Service来暴露出去。
总结
网络是K8S的核心,里面的每个部分都值得深入剖析,本文仅仅概述了其中个关键点,今后还会对CNI、kube-proxy、CoreDNS等组件详细分析。
网友评论