8.1 Service存在的意义
- 防止Pod失联(服务发现)
- 定义一组Pod的访问策略(负载均衡)
8.2 为什么要使用Service
Kubernetes Pod`是平凡的,由`Deployment`等控制器管理的`Pod`对象都是有生命周期的,它们会被创建,也会意外挂掉。虽然它们可以由控制器自动重建或者滚动更新,但是重建或更新之后的`Pod`对象的IP地址等都会发生新的变化。这样就会导致一个问题,如果一组`Pod`(称为`backend`)为其它`Pod`(称为 `frontend`)提供服务,那么那些`frontend`该如何发现,并连接到这组`Pod`中的哪些`backend`呢? 这时候就用到了:`Service
示例说明为什么要使用Service
如下图所示,当Nginx Pod
作为客户端访问Tomcat Pod
中的应用时,IP
的变动或应用规模的缩减会导致客户端访问错误。而Pod
规模的扩容又会使得客户端无法有效的使用新增的Pod
对象,从而影响达成规模扩展之目的。为此,Kubernetes
特地设计了Service
资源来解决此类问题。
8.3 Service实现原理
Service
资源基于标签选择器将一组Pod
定义成一个逻辑组合,并通过自己的IP
地址和端口调度代理请求至组内的Pod
对象之上,如下图所示,它向客户端隐藏了真实的、处理用户请求的Pod
资源,使得客户端的请求看上去就像是由Service
直接处理并响应一样。
Service对象的IP地址也称为Cluster IP,它位于Kubernetes集群配置指定专用IP地址的范围之内,是一种虚拟IP地址,它在Service对象创建后既保持不变,并且能够被同一集群中的Pod资源所访问。Service端口用于接收客户端请求并将其转发至其后端的Pod中的相应端口之上,因此,这种代理机构也称为“端口代理”(port proxy)或四层代理,工作于TCP/IP协议栈的传输层。
Service资源会通过API Server持续监视着(watch)标签选择器匹配到的后端Pod对象,并实时跟踪各对象的变动,例如,IP地址变动、对象增加或减少等。Service并不直接链接至Pod对象,它们之间还有一个中间层——Endpoints资源对象,它是一个由IP地址和端口组成的列表,这些IP地址和端口则来自由Service的标签选择器匹配到的Pod资源。当创建service对象时,其关联的Endpoints对象会自动创建。
8.4 虚拟IP和服务代理
一个Service对象就是工作节点上的一些iptables或ipvs规则,用于将到达Service对象IP地址的流量调度转发至相应的Endpoints对象指定的IP地址和端口之上。kube-proxy组件通过API Server持续监控着各Service及其关联的Pod对象,并将其创建或变动实时反映到当前工作节点上的iptables规则或ipvs规则上。
ipvs是借助于Netfilter实现的网络请求报文调度框架,支持rr、wrr、lc、wlc、sh、sed和nq等十余种调度算法,用户空间的命令行工具是ipvsadm,用于管理工作与ipvs之上的调度规则。
Service IP事实上是用于生成iptables或ipvs规则时使用的IP地址,仅用于实现Kubernetes集群网络的内部通信,并且能够将规则中定义的转发服务的请求作为目标地址予以相应,这也是将其称为虚拟IP的原因之一。
kube-proxy
将请求代理至相应端点的方式有三种:userspace(用户空间)、iptables和ipvs。因userspace传输效率太低,不推荐使用,在1.1版本之前是默认转发策略,现在默认是iptables。
8.5 iptables代理模式
iptables代理模式中,kube-proxy负责跟踪API Server上Service和Endpoints对象的变动(创建或移除),并据此作出Service资源定义的变动。同时,对于每个Service对象,它都会创建iptables规则直接捕获到达Cluster IP(虚拟IP)和Port的流量,并将其重定向至当前Service的后端。对于每个Endpoints对象,Service资源会为其创建iptables规则并关联至挑选的后端Pod资源,默认的调度算法是随机调度(random)。实现基于客户端IP的会话亲和性(来自同一个用户的请求始终调度到后端固定的一个Pod),可将service.spec.sessionAffinity的值设置为“ClientIP”(默认值为“None”)。
其代理过程是:请求到达service
后,其请求被相关service
上的iptables
规则进行调度和目标地址转换(DNAT
)后再转发至集群内的Pod
对象之上。
Iptables:
- 灵活,功能强大
- 规则遍历匹配和更新,呈线性时延
8.6 ipvs代理模式
kube-proxy
跟踪API Server
上Service
的Endpoints
对象的变动,据此来调用netlink
接口创建ipvs
规则,并确保与API Server
中的变动保持同步,其请求流量的调度功能由ipvs
实现,其余的功能由iptables
实现。ipvs
支持众多调度算法,如rr
、lc
、dh
、sh
、sed
和nq
等。
IPVS:
- 工作在内核态,有更好的性能
- 调度算法丰富:rr,wrr,lc,wlc,ip hash...
8.7 Pod与Service的关系
- 通过label-selector相关联
- 通过Service实现Pod的负载均衡( TCP/UDP 4层)
8.8 Service三种类型
Service的IP地址只能够在集群内部可访问,对一些应用(如frontend)的某些部分,可能希望通过外部(kubernetes集群外部)IP地址暴露Service,这时候就需要使用到NodePort。kubernetes ServiceTypes支持四种类型:ClusterIP、NodePort、LoadBalancer、其默认是Cluster IP类型。
- ClusterIP:默认策略,分配一个稳定的IP地址,即VIP,只能在集群内部访问(同Namespace内的Pod)。
pod ---> ClusterIP:ServicePort --> (iptables、ipvs)DNAT --> PodIP:containePort
- NodePort:在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群IP地址。
访问地址:<NodeIP>:<NodePort>clietn --> <NodeIp>:<NodePort> --> (iptables、ipvs)DNAT --> <PodIP>:<ContainerPort>
- 。
- LoadBalancer:与NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
8.9 将service代理模式改为IPVS
8.10 Service DNS名称
DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local
示例:my-svc.my-namespace.svc.cluster.local
8.11 小结
- 采用NodePort对外暴露应用,前面加一个LB实现统一访问入口
- 优先使用IPVS代理模式
- 集群内应用采用DNS名称访问
- service只支持四层负载均衡 四层:OSI中的传输层,TCP/UDP,四元组,只负责IP数据包转发。 七层:OSI中的应用层,HTTP、FTP、SNMP协议,可以拿到这些协议头部信息,那就可以实现基于协议层面的处理。
- NodePort访问流程
user -> 域名(公网IP)-> node ip:port -> iptables/ipvs -> pod
一般生产环境 node 都是部署在内网,那30008这个端口怎么让互联网用户访问呢 (1) 找一台有公网IP的服务器,装一个nginx,反向代理 -> node ip:port (2) 只用你们外部负载均衡器 (Nginx、LVS、HAProxy) -> node ip:port - LoadBalancer 访问流程 user -> 域名(公网IP) -> 公有云上的负载均衡器(自动配置,控制器去完成) -> node ip:port
- kube-proxy工作 (1) 实现pod数据包转发 (2) 将service相关路由规则落地实现