01 引言
至此,service的相关知识已经讲解完了,下面是相关文章的详情总结:
- 《k8s教程(service篇)-资源定义详解》
- 《k8s教程(service篇)-概念和原理》
- 《k8s教程(service篇)-DNS服务搭建和配置》
- 《k8s教程(service篇)-Node本地DNS缓存》
- 《k8s教程(service篇)-pod的dns域名》
- 《k8s教程(service篇)-ingress 7层路由机制》
02 内容整理
先贴上整理的脑图:
2.1 资源定义
详情参考: 《k8s教程(service篇)-资源定义详解》
Service是Kubernetes实现微服务架构的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上,下面对Service的资源定义进行详细说明。
Service的YAML格式的定义文件的完整内容如下:
apiVersion: v1 kind: Service metadata: name: string namespace: string labels: - name: string annotations: - name: string spec: selector:[] type: string clusterIP: string sessionAffinity:string ports: - name: string protocol: string port: int targetPort: int nodePort: int status: loadBalancer: ingress: ip: string hostname: string
属性说明:
属性名称 | 取值类型 | 必选 | 取值说明 |
version | String | 是 | V1 |
kind | String | 是 | Service |
metadata | Object | 是 | 元数据 |
metadata.name | String | 是 | Service名称,需符合RFC 1035规范 |
metadata.namespace | String | 是 | 命名空间,不指定系统时将使用名称为default的命名空间 |
metadata.labels[] | list | 自定义标签属性列表 | |
metadata.annotation[] | list | 自定义注解属性列表 | |
spec | Object | 是 | 详细描述 |
spec.selector[] | list | 是 | Label Selector配置,将选择具有指定Label标签的Pod作为管理范围 |
spec.type | String | 是 | Service的类型,指定Service的访问方式,默认值为ClusterIP。 ClusterIP:虚拟服务IP地址,该地址用于Kubernetes 集群内部的Pod访问,在Node上kube-proxy通过设置的 iptables规则进行转发. NodePort:使用宿主机的端口,使能够访问各Node的外 部客户端通过Node的P地址和端口号就能访问服务. LoadBalancer:使用外接负载均衡器完成到服务的负载分发,需要在spec.status.loadBalancer字段指定外部负载均 衡器的P地址,同时定义nodePort和clusterIP,用于公有 云环境 |
spec.clusterIP | String | 虚拟服务的P地址,当type=ClusterIP时,如果不指定,则系统进行自动分配,也可以手工指定;当type=LoadBalancer 时,需要指定 | |
spec.sessionAffinity | String | 是否支持Session,可选值为ClientIP,默认值为None。 ClientIP:表示将同一个客户端(根据客户端的IP地址决定) 的访问请求都转发到同一个后端Pod | |
spec.ports[] | list | Service端口列表 | |
spec.ports[].name | String | 端口名称 | |
spec.ports[].protocol | String | 端口协议,支持TCP和UDP,默认值为TCP | |
spec.ports[].port | int | 服务监听的端口号 | |
spec.ports[].targetPort | int | 需要转发到后端Pod的端口号 | |
spec.ports[].nodePort | int | 当spec.type=NodePort时,指定映射到宿主机的端口号 | |
Status | Object | 当spec.type=LoadBalancer时,设置外部负载均衡器的地址,用于公有云环境 | |
status.loadBalancer | Object | 外部负载均衡器 | |
status.loadBalancer.ingress | Object | 外部负载均衡器 | |
status.loadBalancer.ingress.ip | String | 外部负载均衡器的IP地址 | |
status.loadBalancer.ingress.hostname | String | 外部负载均衡器的主机名 |
2.2 概念和原理
Service实现的是微服务架构中的几个核心功能:全自动的服务注册、服务发现、 服务负载均衡等。
2.2.1 创建service的方式
① 使用kubectl expose命令创建:
kubectl expose deployment webapp service/webapp exposed
查看新创建的Service,可以看到系统为它分配了一个虚拟IP
地址(ClusterIP
地址),Service的端口号则从Pod中的containerPort复制而来:
通过curl 169.169.140.242:8080 也是可以访问的。访问时,会被自动负载分发到了后端两个Pod之一:10.0.95.22:8080或10.0.95.23:8080。
② 资源文件的方式创建:
除了使用命令,还可以使用yaml资源文件的方式来创建:
apiVersion: v1 kind: Service metadata: name: webapp spec: ports: - protocol: TCP port: 8080 targetPort: 8080 selector: app: webapp
Service定义中的关键字段是ports和selector:
- ports:定义部分指定了Service本身的端口号为8080;
- targetPort:指定后端Pod的容器端口号;
- selector:定义部分设置的是后端Pod所拥有的
label:app=webapp
。
使用kubectl create
命令创建后,能看到和使用kubectl expose
命令创建Service的效果一样。
2.2.2 endpoint
一个Service对应的 “后端” 由Pod的IP和容器端口号组成,这在k8s系统中称为Endpoint。
可以通过kubectl descirbe svc
命令查看Endpoint列表,如:
2.2.3 负载均衡机制
从服务IP到后端Pod的负载均衡机制,则是由每个Node上的kube-proxy负责实现的。
通过Service的负载均衡机制,Kubernetes实现了一种分布式应用的统一入口,免去了客户端应用获知后端服务实例列表和变化的复杂度。
2.2.3.1 kube-proxy的代理模式
目前kube-proxy提供了以下代理模式(通过启动参数--proxy-mode
设置):
模式 | 描述 |
userspace模式 | 用户空间模式,由kube-proxy完成代理的实现,效率最低,不再推荐使用 |
iptables模式 | kube-proxy通过设置Linux Kernel的iptablesi规则,实现从Service到后端Endpoint列表的负载分发规则,效率很高。 —————————— 但是,如果某个后端Endpoint在转发时不可用,此次客户端请求就会得到失败的响应,相对于 userspace模式来说更不可靠,此时应该通过为Pod设置readinessprobe(服务可用性健康检查)来保证只有达到ready状态的Endpoint才会被设置为Service的后端Endpoint。 |
ipvs模式 | 在Kubernetes1.11版本中达到Stable阶段,kube-proxy通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。 ipvs模式要求Linux Kernel启用IPVS模块,如果操作系统未启用IPVS内核模块,kube-proxy则会自动切换至iptables模式。同时ipvs模式支持更多的负载均衡策略,如下所述: —————————— rr(round-robin):轮询; lc(least connection):最小连接数; dh(destination hashing):目的地址哈希; sh(source hashing):源地址哈希; sed(shortest expected delay):最短期望延时; nq(never queue):永不排队。 |
kernelspace模式 | Windows Server上的代理模式 |
2.2.3.2 会话保持模式
Service支持通过设置sessionAffinity实现基于客户端IP的会话保持机制,即:首次将某个客户端来源IP发起的请求转发到后端的某个Pod上,之后从相同的客户端 IP发起的请求都将被转发到相同的后端Pod上。
配置参数为 service.spec.sessionAffinity
,也可以设置会话保持的最长时间(service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
),例如下面的服务将会话保持时间设置为10800s(3h):
apiVersion: v1 kind: Service metadata: name: webapp spec: sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSecondes: 10080 ports: - protocol: TCP port: 8080 targetPort: 8080 selector: app: webapp
2.2.4 多端口设置
在下面的例子中,Service设置了两个端口号来分别提供不同的服务,如web服务
和management服务
(下面为每个端口号都进行了命名,以便区分):
apiversion: v1 kind: Service metadata: name: webapp spec: ports: - port: 8080 targetPort: 8080 name: web - port: 8005 targetPort: 8005 name: management selector: app: webapp
2.2.5 外部服务定义为service
普通的Service通过Label Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint
不是由Pod副本集
提供的,则Service
还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务
定义为Kubernetes内的一个Service
, 供集群内的其他应用访问。
举例:(用户在创建Service
资源对象时不设置Label Selector
(后端Pod
也不存在),同时再定义一个与Service
关联的Endpoint
资源对象,在Endpoint
中设置外部服务的IP
地址和端口号):
apiVersion: v1 kind: Service metadata: name: my-service spec: ports: - protocol: TCP port: 80 targetPort: 80 ----------- apiversion: v1 kind: Endpoints metadata: name: my-service subsets: - addresses: - IP: 1.2.3.4 ports: - port: 80
2.2.6 service暴露给外部集群
可以通过Service资源对象的类型字段“type”进行设置。
目前Service的类型如下:
类型 | 描述 |
ClusterIP | Kubernetes默认会自动设置Service的虚拟IP地址,仅可被集群内部的客户端应用访问。当然,用户也可手工指定一个ClusterIP地址,不过需要确保该IP在Kubernetes集群设置的ClusterIP地址范围内(通过kube-apiserver 服务的启动参数-service-cluster–ip-range设置),并且没有被其他Service使用 |
NodePort | 将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为Service的访问入口地址,即NodeIP:NodePort |
LoadBalancer | 将Service映射到一个已存在的负载均衡器的IP地址上, 通常在公有云环境中使用 |
ExternalName | 将Service映射为一个外部域名地址,通过externalName字段进行设置 |
2.2.6.1 NodePort类型
apiVersion: v1 kind: Service metadata: name: webapp spec: type: NodePort ports: - port: 8080 targetPort: 8080 nodePort: 8081 selector: app: webapp
使用kubectl create
创建了Service之后,就可以通过任意一个Node的IP地址+ NodePort 8081端口号访问服务了。