Pod的讲解终于告一段落了,现在我们来一起学习Service。
Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。本章对Service的使用进行详细说明,包括Service的负载均衡机制、如何访问Service、Headless Service、DNS服务的机制和实践、Ingress 7层路由机制等。
Service的yaml定义文件完整内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 1apiVersion: v1 // Required
2kind: Service // Required
3metadata: // Required
4 name: string // Required
5 namespace: string // Required
6 labels:
7 - name: string
8 annotations:
9 - name: string
10spec: // Required
11 selector: [] // Required
12 type: string // Required
13 clusterIP: string
14 sessionAffinity: string
15 ports:
16 - name: string
17 protocol: string
18 port: int
19 targetPort: int
20 nodePort: int
21 status:
22 loadBalancer:
23 ingress:
24 ip: string
25 hostname: string
26
apiVersion
string
是
v1
kind
string
是
Service
metadata
object
是
元数据
metadata.name
string
是
Service名称
metadata.namespace
string
是
命名空间,不指定默认为default
metadata.labels[] metadata.annotation[]
list list
自定义标签属性列表 自定义注释属性列表
spec
object
是
详细描述
spec.selector[]
list
是
label selector配置,将选择具有指定label标签的Pod 作为管理范围
spec.type
string
是
Service的类型,指定Service的访问方式,默认值为ClusterIP。 1.Cluster IP:虚拟的服务IP地址,该地址用于K8s集群内部的Pod访问,在Node上kube-prox通过设置的optables规则进行转发。 2.NodePort: 使用宿主机的端口,使能够访问各Node的外部客户端通过Node的IP地址和端口号就能访问服务。 3. LoadBalancer: 使用外接负载均衡器完成到服务的负载分发,需要在spec.status.loadBalancer字段指定外部负载均衡器的IP地址,并同时定义nodePort和clusterIP,用于公有云环境。
spec.clusterIP
string
虚拟服务IP地址,当type=clusterIP时,如果不指定。这系统进行自动分配,也可以手工指定:当type=loadBalancer时,这需要指定
spec.sessionAffinity
string
是否支持Session,可选值为ClusterIP,默认值为空。 clusterIP: 表示同一个客户端的访问请求都转发到同一个后端Pod
spec.ports[]
list
Service需要暴露的端口列表
spec.ports[].name
string
端口名称
spec.ports[].protocol
string
端口协议,支持TCP和UDP。默认为TCP
spec.ports[].port
init
服务监听的端口号
spec.ports[].targePort
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
外部负载均衡器的主机名
Service 的基本用法
一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最简便的方式就是通过TCP/IP机制及监听IP和端口号来实现。例如,定义一个提供Web服务的RC,由两个Tomcat容器副组成,每个容器都通过containerPort设置提供服务的端口号为8080:
webapp-rc.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1apiVersion: v1
2kind: ReplicationController
3metadata:
4 name: webapp
5spec:
6 replicas: 2
7 template:
8 metadata:
9 name: webapp
10 labels:
11 app: webapp
12 spec:
13 containers:
14 - name: webapp
15 image: tomcat
16 ports:
17 - containerPort: 8080
18
创建该RC之后获取该Pod的IP地址
1
2 1kubectl get pod -l app=webapp -o yaml | grep podIP
2
可以直接通过这两个Pod的IP地址和端口号访问Tomcat服务:
直接通过Pod的IP地址和端口号可以访问到容器应用内的服务,但是Pod的IP地址是不可靠的,例如当Pod所在的Node发生故障时,Pod将被Kubernetes重新调度到另一个Node,Pod的IP地址将发生变化。更重要的是,如果容器应用本身是分布式的部署方式,通过多个实例共同提供服务,就需要在这些实例的前端设置一个负载均衡器来实现请求的分发。Kubernetes中的Service就是用于解决这些问题的核心组件。
以前面创建的webapp应用为例,为了让客户端应用访问到两个Tomcat Pod实例,需要创建一个Service来提供服务。Kubernetes提供了一种快速的方法,即通过kubectl expose命令来创建Service:
1
2 1kubectl expose rc webapp
2
查看新创建的Service,可以看到系统为它分配了一个虚拟的IP地址(ClusterIP),Service所需的端口号则从Pod中的containerPort复制而来:
接下来就可以通过Service的IP地址和Service的端口号访问该Service了:
这里,对Service地址10.111.79.254:8080的访问被自动负载分发到了后端两个Pod之一。
除了使用kubectl expose命令创建Service,我们也可以通过配置文件定义Service,再通过kubectl create命令进行创建。例如对于前面的webapp应用,我们可以设置一个Service,代码如下:
1
2
3
4
5
6
7
8
9
10
11 1apiVersion: v1
2kind: Service
3metadata:
4 name: webapp1
5spec:
6 ports:
7 - port: 8081
8 targetPort: 8080
9 selector:
10 app: webapp
11
Service定义中的关键字段是ports和selector。本例中ports定义部分指定了Service所需的虚拟端口号为8081,由于与Pod容器端口号8080不一样,所以需要再通过targetPort来指定后端Pod的端口号。selector定义部分设置的是后端Pod所拥有的label:app=webapp。
目前Kubernetes提供了两种负载分发策略:RoundRobin和SessionAffinity,具体说明如下:
◎ RoundRobin:轮询模式,即轮询将请求转发到后端的各个Pod上。
◎ SessionAffinity:基于客户端IP地址进行会话保持的模式,即第1次将某个客户端发起的请求转发到后端的某个Pod上,之后从相同的客户端发起的请求都将被转发到后端相同的Pod上。
在默认情况下,Kubernetes采用RoundRobin模式对客户端请求进行负载分发,但我们也可以通过设置service.spec.sessionAffinity=ClientIP来启用SessionAffinity策略。这样,同一个客户端IP发来的请求就会被转发到后端固定的某个Pod上了。
通过Service的定义,Kubernetes实现了一种分布式应用统一入口的定义和负载均衡机制。Service还可以进行其他类型的设置,例如设置多个端口号、直接设置为集群外部服务,或实现为Headless Service(无头服务)模式。
多端口Service
有时一个容器应用也可能提供多个端口的服务,那么在Service的定义中也可以相应地设置为将多个端口对应到多个应用服务。在下面的例子中,Service设置了两个端口号,并且为每个端口号都进行了命名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1apiVersion: v1
2kind: Service
3metadata:
4 name: webapp2
5spec:
6 ports:
7 - port: 8080
8 targetPort: 8080
9 name: web
10 - port: 8005
11 targetPort: 8005
12 name: management
13 selector:
14 app: webapp
15
另一个例子是两个端口号使用了不同的4层协议—TCP和UDP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1apiVersion: v1
2kind: Service
3metadata:
4 name: webapp3
5spec:
6 ports:
7 - port: 8080
8 protocol: UDP
9 name: tdp
10 - port: 8080
11 protocol: TCP
12 name: tcp
13 selector:
14 app: webapp
15
外部服务Service
在某些环境中,应用系统需要将一个外部数据库作为后端服务进行连接,或将另一个集群或Namespace中的服务作为服务的后端,这时可以通过创建一个无Label Selector的Service来实现:
1
2
3
4
5
6
7
8
9
10 1kind: Service
2apiVersion: v1
3metadata:
4 name: my-service
5spec:
6 ports:
7 - protocol: TCP
8 port: 80
9 targetPort: 80
10
通过该定义创建的是一个不带标签选择器的Service,即无法选择后端的Pod,系统不会自动创建Endpoint,因此需要手动创建一个和该Service同名的Endpoint,用于指向实际的后端访问地址。创建Endpoint的配置文件内容如下:
1
2
3
4
5
6
7
8
9
10
11 1kind: Endpoints
2apiVersion: v1
3metadata:
4 name: my-service
5subsets:
6- addresses:
7 - ip: 1.2.3.4
8 ports:
9 - port: 8080
10
11
访问没有标签选择器的Service和带有标签选择器的Service一样,请求将会被路由到由用户手动定义的后端Endpoint上。
小结:
本节内容到此结束,是不是觉得很简单呢?
觉得简单,说明我们已经入k8s的门了,继续加油!
多多点关注哦~