Service原理:
1.概述:Service服务也是Kubernetes里的核心资源对象之一,Kubernetes里的
每个Service其实就是我们经常提起的微服务架构中的一个微服务。
下图显示了Pod,RC,service的逻辑关系
Kubernetes的Service定义了一个服务的访问 入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由 Pod副本组成的集群实例,Service与其后端Pod副本集群之间则是通过 Label Selector来实现无缝对接的
2.service模式
根据创建Service的type类型不同,可分成4种模式:
- ClusterIP: 默认方式。根据是否生成ClusterIP又可分为普通Service和Headless Service两类:普通Service:通过为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP),实现集群内的访问。为最常见的方式。
- Headless Service:该服务不会分配Cluster IP,也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的络ID来访问,DNS会将headless service的后端直接解析为podIP列表。主要供StatefulSet使用。
- NodePort:除了使用Cluster IP之外,还通过将service的port映射到集群内每个节点的相同一个端口,实现通过nodeIP:nodePort从集群外访问服务。
- LoadBalancer:和nodePort类似,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
-
ExternalName:是 Service 的特例。此模式主要面向运行在集群外部的服务,通过它可以将外部服务映射进k8s集群,且具备k8s内服务的一些特征(如具备namespace等属性),来为集群内部提供服务。此模式要求kube-dns的版本为1.7或以上。这种模式和前三种模式(除headless service)最大的不同是重定向依赖的是dns层次,而不是通过kube-proxy。
比如,在service定义中指定externalName的值"my.database.example.com":
此时k8s集群内的DNS服务会给集群内的服务名 SVC_NAME.NAMESPACE.svc.cluster.local 创建一个CNAME记录,其值为指定的"my.database.example.com"。
备注:
前3种模式,定义服务的时候通过selector指定服务对应的pods,根据pods的地址创建出endpoints作为服务后端;EndpointsController会watch Service以及pod的变化,维护对应的Endpoint信息。kube-proxy根据Service和Endpoint来维护本地的路由规则。当Endpoint发生变化,即Service以及关联的pod发生变化,kube-proxy都会在每个节点上更新iptables,实现一层负载均衡。
而ExternalName模式则不指定selector,相应的也就没有port和endpoints。
ExternalName和ClusterIP中的Headles Service同属于Headless Service的两种情况。Headless Service主要是指不分配Service IP,且不通过kube-proxy做反向代理和负载均衡的服务。
2.2. Port
service中主要涉及三种Port:
-
port 这里的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供给集群内部访问kubernetes服务的入口。
-
targetPort
containerPort,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。 -
nodePort
nodeIP:nodePort 是提供给从集群外部访问kubernetes服务的入口。
总的来说,port和nodePort都是service的端口,前者暴露给从集群内访问服务,后者暴露给从集群外访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端具体pod的targetPort,从而进入到pod上的容器内。
Note: A Service can map any incoming port to a targetPort. By default and for convenience, the targetPort is set to the same value as the port field.
2.3 IP
使用Service服务还会涉及到几种IP:
-
ClusterIP
Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但clusterIP就不一样了,没有网络设备承载这个地址。它是一个虚拟地址,由kube-proxy使用iptables规则重新定向到其本地端口,再均衡到后端Pod。当kube-proxy发现一个新的service后,它会在本地节点打开一个任意端口,创建相应的iptables规则,重定向服务的clusterIP和port到这个新建的端口,开始接受到达这个服务的连接。 -
Pod IP
Pod的IP,每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause的容器,Pod内部其他容器的网络模式使用container模式,并指定为pause容器的ID,即:network_mode: “container:pause容器ID”,使得Pod内所有容器共享pause容器的网络,与外部的通信经由此容器代理,pause容器的IP也可以称为Pod IP。 -
节点IP
Node-IP,service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。指定service的spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。