K8S之Service
Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:1.普通的Service通过Label已部署的一个集群外服务,例如数据库服务、缓存服务等;2.其他 ubern
1.Service定义
官方文档:https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
Service是用于一组提供服务的pod抽象一个稳定的网络访问地址,是Kubernetes实现微服务的核心概念,可以为一组具有相同功能的pod提供一个统一的入口地址,并将请求负载分发到后端的各个容器上面。
#service的完整yaml文件如下
apiVersion: v1 // Required
kind: Service // Required
metadata: // Required
name: string // Required
namespace: string // Required
labels:
- name: string
annotations:
- name: string
spec: // Required
selector: [] // Required
type: string // Required
clusterIP: string
sessionAffinity: string
ports:
- name: string
protocol: string
port: int
targetPort: int
nodePort: int
status:
loadBalancer:
ingress:
ip: string
hostname: string
属性名称 | 取值类型 | 是否必选 | 取值说明 |
version | string | Required | v1 |
kind | string | Required | Service |
metadata | object | Required | 元数据 |
metadata.name | string | Required | service名称 |
metadata.namespace | string | Required | 命名空间,不指定默认用default的命名空间 |
metadata.labels[] | list | 自定义标签属性列表 | |
metadata.annotations[] | list | 自定义注解属性列表 | |
spec | object | Required | 详细描述 |
spec.selector[] | list | Required | Label Selector配置,将选择具有指定Label标签的Pod作为管理范围 |
spec.type | string | Required | Service的类型,指定Service的访问方式,默认值为 ClusterIP.(1)ClusterIP : 虚拟服务 IP 地址,该地址用于 Kubernetes集群内部的 Pod 访问 , 在 Node 上 kubc-proxy 通过设置的iptables 规则进行转发 . (2) NodePort: 使用宿主机的端口,使能够访问各 Node 的外部客户端通过 Node 的了地址和端口号就能访问服务. (3) LoadBalancer, 使用外接负载均衡器完成到服务的负载分发,需要在spec.starus.loadbalancer 字段指定外部负载均衡器的 IP 地址,同时定义 nodePort 和 clusterlP, 用于 公有云环境 |
spec.clusterIP | string | 虚拟服务的IP地址,当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 | 当spectype=NodePort时,指定映射到宿主机的端口号 | |
Status | object | 当spec.typc=LoadBalancer时,设置外部负载均衡器的地址,用千公有云环境 | |
status.loadBalancer | object | 外部负载均衡器 | |
status.loadBalancer.ingress | object | 外部负载均衡器 | |
status.loadBalancer.ingress.ip | string | 外部负载均衡器的IP地址 | |
status.loadBalancer.ingress.hostname | string | 外部负载均衡器的主机名 |
2.Service的概念和原理
Service主要提供网络服务,通过Service的定义,能够为客户端应用提供稳定的访问地址(域名或者IP地址)和负载均衡功能,以及屏蔽后端Endpoint的变化,是Kubernetes实现微服务的核心资源。
2.1 概念
我们以一个提供web服务的Pod集合,由两个tomcat容器副本组成为例子来说明,每个容器提供的服务端口号都为8080
#1.创建webapp-deployment.yaml文件
[root@k8s-master k8s-yaml]# cat webapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 2
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: tomcat
ports:
- containerPort: 8080
#2.运行webapp-deployment.yaml文件
[root@k8s-master k8s-yaml]# kubectl apply -f webapp-deployment.yaml
deployment.apps/webapp created
#3.查看pod
[root@k8s-master k8s-yaml]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-f7599d4c-95nr8 1/1 Running 0 4h17m
nginx-deployment-f7599d4c-z8vf9 1/1 Running 0 4h17m
webapp-886db8b9-kc2dc 1/1 Running 0 2m24s
webapp-886db8b9-lm4rp 1/1 Running 0 2m24s
#4.查看pod访问地址
[root@k8s-master k8s-yaml]# kubectl get po -l app=webapp -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
webapp-886db8b9-kc2dc 1/1 Running 0 3m19s 172.18.85.205 k8s-node01 <none> <none>
webapp-886db8b9-lm4rp 1/1 Running 0 3m19s 172.18.85.206 k8s-node01 <none> <none>
因为本机资源有限,所以只有一个master节点和两个node节点,其中有一个node节点是关闭的,未打开
我们在node节点上分别curl 172.18.85.205:8080 和curl 172.18.85.206:8080 均有响应,我们在来创建service
#1.创建service
[root@k8s-master k8s-yaml]# kubectl expose deployment webapp
service/webapp exposed
#2.查看service
[root@k8s-master k8s-yaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
webapp ClusterIP 10.106.80.230 <none> 8080/TCP 6s
此时我们在用curl 10.106.80.230:8080也有响应,此时是我们对10.106.80.230自动负载到后端两个pod之一:172.18.85.295或者206了
我们除了用kubectl expose来创建service以外,还能以yaml的方式来创建(实际生产中基本都用 这个,方便管理),如下
#1.创建webapp-service.yaml文件
[root@k8s-master k8s-yaml]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: webapp
#2.创建service
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
webapp ClusterIP 10.103.127.8 <none> 8080/TCP 41s
一个service对应的后端由Pod的IP和容器端口号组成,即一个完整的“IP:Port”访问地址,这个在kubernetes系统中叫做Endpoint,我们可以用kubectl describe svc webapp或者kubectl get endpoints来查看
[root@k8s-master k8s-yaml]# kubectl describe svc webapp
Name: webapp
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=webapp
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.127.8
IPs: 10.103.127.8
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
Endpoints: 172.18.85.205:8080,172.18.85.206:8080
Session Affinity: None
Events: <none>
[root@k8s-master k8s-yaml]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 11.0.1.12:6443 8d
webapp 172.18.85.205:8080,172.18.85.206:8080 5m43s
2.2 Service的负载均衡机制
从clusterIP到后端Pod IP的负载均衡机制是由每个Node上的kube-proxy负责实现
2.2.1 kube-proxy的代理模式
1.userspace模式
用户空间模式,由kube-proxy完成代理的实现,效率最低,不再推荐使用
2.iptables模式
kube-proxy通过设置Linux Kernel的iptables规则,实现从Service到后端的Endpoint列表的负载分发规则,效率很高。但是如果某个后端的Endpoint在转发时不可用,此次客户端请求会以失败告终,相对于userspace模式更不可靠。此时应该通过将Pod设置readinessprobe(服务可用性健康检查)来保证只有达到ready状态的Endpoint才会设置为Service的后端Endpoint
3.ipvs模式
通过设置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 永不排队)
4.kernelspace模式
Windows Server上的代理模式
2.2.2 会话保持机制
Service支待通过设置sessionAffinity 实现基于客户端IP的会话保持机制,即首次将某个客户端来源IP发起的请求转发到后端的某个Pod上,之后从相同的客户端 P发起的请求都将被转发到相同的后端Pod上,配置参数为 service.spec.sessionAffinity,例如
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
sessionAffinity: ClientIP
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: webapp
同时,用户可以设置会话保持的最长时间,在此时间之后重置客户端来源IP的保持规则,配置参数为service.spec.sessionAffinityConfig.clientIP.timeoutseconds。例如下面的服务将会话保持时间设置为10800s(3h):
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
ports:
- protocol: TCP
port: 8080
targetPort: 8080
selector:
app: webapp
通过Service的负载均衡机制,Kubernetes实现了一种分布式应用的统一入口,免去了客户端应用获知后端服务实例列表和变化的复杂度
2.2.3 Service的多端口设置
一个容器应用可以提供多个端口的服务,在Service的定义中也可以相应地设置多个端口号,例如
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 8080
name: web
- procotol: TCP
port: 8005
targetPort: 8005
name: management
selector:
app: webapp
2.2.4 将外部服务定义成Service
Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:
1.普通的Service通过Label已部署的一个集群外服务,例如数据库服务、缓存服务等;
2.其他 ubernetes集群的某个服务;
3.迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证。
[root@k8s-master k8s-yaml]# cat my-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
[root@k8s-master k8s-yaml]# cat my-endpoints.yml
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- IP: 1.2.3.4
ports:
- port: 80
2.2.5 将Service暴露到集群外部
Kubernetes提供了多种机制将Service暴露出去,供集群外部的客户端访问。这可以通过Service资源对象的类型字段"type" 进行设置
目前Service的类型如下:
1.ClusterIP:Kubernetes会默认自动设置Service的虚拟IP地址,仅可被集群内部客户端应用访问。当然,用户也可以手动指定一个ClusterIP地址,不过需要确保该IP在Kubernetes集群设置的 ClusterIP 地址范围内(通过 kube-apiserver 服务的启动参数--service-cluster-ip-range 设置),并且没有被其他 Service 使用。
2.NodePort:将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为 Service 的访问入口地址,即 NodeIP:NodePort。
3.LoadBalancer:将Service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。
4.ExternalName:将Service映射为 一个外部域名地址 ,通过externalName字段进行
设置。
举例说明:
NodePort 类型:
#1.创建webapp-service.yaml
[root@k8s-master k8s-yaml]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30081
selector:
app: webapp
#2.创建svc
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d <none>
webapp NodePort 10.102.137.65 <none> 8080:30081/TCP 16s app=webapp
然后用curl 11.0.1.13:30081和curl 11.0.1.14:30081得到响应,其中IP为两个nodeIP
LoadBalancer类型 :
通常在公有云环境中设置Service的类型为 “LoadBalancer", 可以将 Service 映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IP和Service的端口号就可以访问到具体的服务,无须再通过kube-proxy提供的负载均衡机制进行流量转发。公有云提供的LoadBalancer可以直接将流量转发到后端Pod上,而负载分发机制依赖于公有云服务商的具体实现。
#1.创建webapp-service.yaml
[root@k8s-master k8s-yaml]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 9376
protocol: TCP
selector:
app: webapp
#2.创建svc
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d <none>
webapp LoadBalancer 10.110.189.28 <pending> 80:31010/TCP 5s app=webapp
ExternalName 类型:
ExternalName类型的服务用于将集群外的服务定义为Kubernetes的集群的Service,并且通过 externalName字段指定外部服务的地址,可以使用域名或IP格式。集群内的客户端应用通过访问这个Service就能访问外部服务了。这种类型的Service没有后端Pod,所以无须设置Label Selector
这个例子后续会在ingress中列出
更多推荐
所有评论(0)