点击上方“IT那活儿”公众号--专注于企业全栈运维技术分享,不管IT什么活儿,干就完了!!!
Service概念原理
1.1 为什么要有Service
在kubernetes中,Pod是有生命周期的,如果Pod重启它的IP很有可能会发生变化。如果我们的服务都是将Pod的IP地址写死,Pod挂掉或者重启,和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod.
为了解决这个问题,在kubernetes中定义了service资源对象,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,service是一组Pod的逻辑集合,这一组Pod能够被Service访问到,通常是通过Label Selector实现的。
1.2 Service概述
service是一个固定接入层,客户端可以通过访问service的ip和端口访问到service关联的后端pod。
这个service工作依赖于在kubernetes集群之上部署的一个附件,就是kubernetes的dns服务(不同kubernetes版本的dns默认使用的也是不一样的,1.11之前的版本使用的是kubeDNs,较新的版本使用的是coredns)。
service的名称解析是依赖于dns附件的,因此在部署完k8s之后需要再部署dns附件,kubernetes要想给客户端提供网络功能,需要依赖第三方的网络插件(flannel,calico等)。
每个K8s节点上都有一个组件叫做kube-proxy,kube-proxy这个组件将始终监视着apiserver中有关service资源的变动信息,需要跟master之上的apiserver交互,随时连接到apiserver上获取任何一个与service资源相关的资源变动状态。
这种是通过kubernetes中固有的一种请求方法watch(监视)来实现的,一旦有service资源的内容发生变动(如创建,删除),kube-proxy都会将它转化成当前节点之上的能够实现service资源调度,把我们请求调度到后端特定的pod资源之上的规则,这个规则可能是iptables,也可能是ipvs,取决于service的实现方式。
1.3 service作用
使用kubernetes集群运行工作负载时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务。
Kubernetes中使用了Service来解决这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化 ,只要有Label,就可以让Service能够联系上Pod,把PodIP地址添加到Service对应的端点列表(Endpoints)实现对Pod IP跟踪,进而实现通过Service访问Pod目的。
通过service为pod客户端提供访问pod方法,即可客户端访问pod入口(主要作用); 通过标签动态感知pod IP地址变化等; 防止pod失联; 定义访问pod访问策略; 通过label-selector相关联(service匹配pod 的label,然后相关联); 通过Service实现Pod的负载均衡(TCP/UDP 4层); 底层实现由kube-proxy通过userspace、iptables、ipvs三种代理模式。
service 的类型与实践
2.1 Service 的类型及其实践
Service 有四种类型,可通过 .spec.type 字段进行设置,分别为:
ClusterIP
NodePort
LoadBalancer
ExternalName
1)ClusterIP:只能在集群内部通过 clusterIP:port 访问
.spec.type 不设置时默认就是“ClusterIP”,clusterIP 不设置时系统会自动为其分配一个虚拟 IP,手动设置时需要确保该 IP 在 Kubernetes 集群设置的 ClusterIP 地址范围内。
Service 创建完成以后可以在集群内通过 clusterIP:port 进行访问,但集群外部无法访问到该 Service。


2)NodePort:可在集群外部通过 NodeIP:nodePort 访问
NodePort 类型将 Service 的端口号映射到每个 Node 的一个端口号上,这样集群中的任意 Node 都可以作为 Service 的访问入口。


默认情况下,系统还是为 Service 分配了一个虚拟 IP,可在集群内通过 clusterIP:port 访问服务,也可以在集群外通过任意 Node 进行访问:NodeIP:nodePort。
3)LoadBalancer:可在集群外通过负载均衡器的 IP 和 Service 的端口号访问
LoadBalancer 类型的 Service 通常在公有云环境中使用,可以将 Service 映射到某个负载均衡器的 IP 地址上,集群外的客户端可通过负载均衡器的 IP 和 Service 的端口号访问 Service,负载均衡器可以直接将流量转发到后端 Pod 上,而无须再通过 kube-proxy 进行转发,负载均衡机制也是依赖于公有云服务商的具体实现。

4)ExternalName:可将集群外服务定义为集群内服务,然后在集群内通过 Service 域名进行访问
ExternalName 类型用于将集群外的服务定义为 Kubernetes 集群内的 Service,并且通过 externalName 字段指定外部服务的地址,可以使用域名或 IP。
集群内的客户端应用访问 Service 的域名时,系统将自动指向 externalName 字段设置的集群外部的服务地址。


没有后端 Pod,所以没有设置 .spec.selector,所以也就不会生成 endpoints。
这里创建的 Service wjt-service-externalname,其 external name 指向另一个 Service wjt-service-clusterip 的域名,所以访问前者域名的时候相当于访问后者的服务:

也可将 external name 指向集群外服务域名。
注意:
ExternalName 的服务接受 IPv4 地址字符串,但将该字符串视为由数字组成的 DNS 名称, 而不是 IP 地址(然而,互联网不允许在 DNS 中使用此类名称)。 类似于 IPv4 地址的外部名称无法被 DNS 服务器解析。
2.2 将外部服务定义为 Service
除了创建 ExternalName 类型的 Service,还可以通过直接创建 endpoints 并将其指向集群外部服务地址来将外部服务定义为 Service。


这里不设置 .spec.selector,而是手动创建 endpoints,并指定外部服务的地址。
接下来可通过 Service ClusterIP 访问到外部服务:

与直接访问外部服务是一样的效果!

本文作者:何先明(上海新炬中北团队)
本文来源:“IT那活儿”公众号





