service-四层负载均衡
概念、原理解读
为什么要有 Service
在 kubernetes 中,Pod 是有生命周期的,如果 Pod 重启它的 IP 很有可能会发生变化。如果我们的服务都是将 Pod 的 IP 地址写死,Pod 挂掉或者重启,和刚才重启的 pod 相关联的其他服务将会找不到它所关联的 Pod,为了解决这个问题,在 kubernetes 中定义了 service 资源对象,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,service 是一组 Pod 的逻辑集合,这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector 实现的。
- pod ip 经常变化,service 是 pod 的代理,我们客户端访问,只需要访问 service,就会把请求代理到 Pod
- pod ip 在 k8s 集群之外无法访问,所以需要创建 service,这个 service 可以在 k8s 集群外访问的
概述
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 的实现方式。
工作原理
k8s 在创建 Service 时,会根据标签选择器 selector(lable selector)来查找 Pod,据此创建与Service同名的 endpoint 对象,当 Pod 地址发生变化时,endpoint 也会随之发生变化,service 接收前端 client 请求的时候,就会通过 endpoint,找到转发到哪个 Pod 进行访问的地址。(至于转发到哪个节点的 Pod,由负载均衡 kube-proxy 决定)
三类 IP 地址
-
Node Network(节点网络):物理节点或者虚拟节点的网络,如 ens33 接口上的网路地址
-
Pod network(pod 网络),创建的 Pod 具有的 IP 地址
[root@k8s01 controller]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-v1-75fb478d6c-4j2sx 1/1 Running 0 27m 10.244.236.165 k8s02 <none> <none> myapp-v1-75fb478d6c-4j8p6 1/1 Running 0 27m 10.244.236.164 k8s02 <none> <none>
-
Cluster Network(集群地址,也称为 service network),这个地址是虚拟的地址(virtualip),没有配置在某个接口上,只是出现在 service 的规则当中。
[root@k8s01 controller]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d21h
创建 Service 资源
#查看定义 Service 资源需要的字段有哪些
[root@k8s01 controller]# kubectl explain service
KIND: Service
VERSION: v1
DESCRIPTION:
Service is a named abstraction of software service (for example, mysql)
consisting of local port (for example 3306) that the proxy listens on, and
the selector that determines which pods will answer requests sent through
the proxy.
FIELDS:
apiVersion <string>
#service 资源使用的 api 组
kind <string>
#创建的资源类型
metadata <Object>
#定义元数据
spec <Object>
status <Object>
#查看 service 的 spec 字段如何定义
[root@k8s01 controller]# kubectl explain service.spec
KIND: Service
VERSION: v1
RESOURCE: spec <Object>
DESCRIPTION:
Spec defines the behavior of a service.
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
ServiceSpec describes the attributes that a user creates on a service.
FIELDS:
allocateLoadBalancerNodePorts <boolean>
clusterIP <string>
#动态分配的地址,也可以自己在创建的时候指定,创建之后就改不了了
clusterIPs <[]string>
externalIPs <[]string>
externalName <string>
externalTrafficPolicy <string>
healthCheckNodePort <integer>
ipFamilies <[]string>
ipFamilyPolicy <string>
loadBalancerIP <string>
loadBalancerSourceRanges <[]string>
ports <[]Object>
#定义 service 端口,用来和后端 pod 建立联系
publishNotReadyAddresses <boolean>
selector <map[string]string>
#通过标签选择器选择关联的 pod 有哪些
sessionAffinity <string>
#service 在实现负载均衡的时候还支持 sessionAffinity,sessionAffinity 什么意思?会话联系,默认是 none,随机调度的(基于 iptables 规则调度的);如果我们定义sessionAffinity 的 client ip,那就表示把来自同一客户端的 IP 请求调度到同一个 pod 上
sessionAffinityConfig <Object>
sessionAffinityConfig contains the configurations of session affinity.
topologyKeys <[]string>
type <string>
#定义 service 的类型
Service 的四种类型
#查看定义 Service.spec.type 需要的字段有哪些
[root@k8s01 controller]# kubectl explain service.spec.type
KIND: Service
VERSION: v1
FIELD: type <string>
DESCRIPTION:
type determines how the Service is exposed. Defaults to ClusterIP. Valid
options are ExternalName, ClusterIP, NodePort, and LoadBalancer.
"