1 Service 概述

1.1 为什么要使用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资源来解决此类问题。

img

1.2 Service实现原理

Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口调度代理请求至组内的Pod对象之上,如下图所示,它向客户端隐藏了真实的、处理用户请求的Pod资源,使得客户端的请求看上去就像是由Service直接处理并响应一样。

img

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对象会自动创建。

1.3 虚拟IP和服务代理

一个Service对象就是工作节点上的一些iptablesipvs规则,用于将到达Service对象IP地址的流量调度转发至相应的Endpoints对象指定的IP地址和端口之上。kube-proxy组件通过API Server持续监控着各Service及其关联的Pod对象,并将其创建或变动实时反映到当前工作节点上的iptables规则或ipvs规则上。

ipvs是借助于Netfilter实现的网络请求报文调度框架,支持rrwrrlcwlcshsednq等十余种调度算法,用户空间的命令行工具是ipvsadm,用于管理工作与ipvs之上的调度规则。

Service IP事实上是用于生成iptablesipvs规则时使用的IP地址,仅用于实现Kubernetes集群网络的内部通信,并且能够将规则中定义的转发服务的请求作为目标地址予以相应,这也是将其称为虚拟IP的原因之一。

kube-proxy将请求代理至相应端点的方式有三种:userspace(用户空间)iptablesipvs

1.3.1 userspace代理模式

userspaceLinux操作系统的用户空间。这种模式下,kube-proxy负责跟踪API ServerServiceEndpoints对象的变动(创建或移除),并据此调整Service资源的定义。对于每个Service对象,它会随机打开一个本地端口(运行于用户控件的kube-proxy进程负责监听),任何到达此端口的连接请求都将代理至当前Service资源后端的各Pod对象上,至于会挑选中哪个Pod对象则取决于当前Service资源的调度方式(通过ServiceSessionAffinity来确定),默认的调度算法是轮循(round-robin)。

其代理的过程是:请求到达service后,其被转发至内核空间,经由套接字送往用户空间的kube-proxy,而后再由它送回内核空间,并调度至后端Pod。其传输效率太低,在1.1版本前是默认的转发策略。

img

1.3.2 iptables代理模式

iptables代理模式中,kube-proxy负责跟踪API ServerServiceEndpoints对象的变动(创建或移除),并据此作出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对象之上。

相对userspace模式来说,iptables模式无须将流量在用户空间和内核空间来回切换,因而更加高效和可靠。其缺点是iptables代理模型不会在被挑中的Pod资源无响应时自动进行重定向;而userspace模式则可以。

img

1.3.3 ipvs代理模式

kube-proxy跟踪API ServerServiceEndpoints对象的变动,据此来调用netlink接口创建ipvs规则,并确保与API Server中的变动保持同步,其请求流量的调度功能由ipvs实现,其余的功能由iptables实现。ipvs支持众多调度算法,如rrlcdhshsednq等。

img

2 Service资源的基础应用

创建Service对象的常用方法有两种,一是直接使用命令“kubectl expose”命令,二是使用资源清单配置文件。定义Service资源清单文件时,spec的两个较为常用的内嵌字段分别是selectorport,分别用于定义使用的标签选择器和要暴露的端口。

一、命令方式定义

1)首先创建一组pod资源

1
2
3
4
5
6
7
8
9
[root@k8s-master ~]# kubectl run nginx --image=nginx:1.12 --replicas=3    #创建pod资源指定副本数量为3个
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-67685f79b5-688s7 1/1 Running 0 5s 10.244.2.61 k8s-node2 <none> <none>
nginx-67685f79b5-gpc2f 1/1 Running 0 5s 10.244.1.63 k8s-node1 <none> <none>
nginx-67685f79b5-grlrz 1/1 Running 0 5s 10.244.2.60 k8s-node2 <none> <none>
[root@k8s-master ~]# kubectl get deployment #查看deployment控制器资源
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 3/3 3 3 35s

2)为其创建对应的service资源

1
2
3
4
5
6
7
#下面这条命令表示为deployment控制器资源nginx创建一个service对象,并取名为nginx、端口为80、pod内暴露端口80、协议为TCP协议。
[root@k8s-master ~]# kubectl expose deployment nginx --name=nginx --port=80 --target-port=80 --protocol=TCP
service/nginx exposed
[root@k8s-master ~]# kubectl get service #查看创建的service资源
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
nginx ClusterIP 10.104.116.156 <none> 80/TCP 9s

3)查看生成的endpoints对应关系

1
2
3
4
[root@k8s-master ~]# kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 192.168.1.31:6443 27d
nginx 10.244.1.63:80,10.244.2.60:80,10.244.2.61:80 29s

二、资源清单定义

1)编写资源清单文件(这里先定义一个Deployment控制器资源对象,然后定义Service进行关联)。注:同一个文件编写多个资源对象时,通过—进行分割。

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
27
28
29
30
31
32
33
34
35
36
37
38
[root@k8s-master ~]# vim manfests/service-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: service-deploy-demo
template:
metadata:
name: svc-deploy
labels:
app: service-deploy-demo
spec:
containers:
- name: svc-pod
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80

---
#定义service
apiVersion: v1
kind: Service
metadata:
name: service-demo #service名称
spec:
selector: #用于匹配后端的Pod资源对象,需和上面定义pod的标签一致
app: service-deploy-demo
ports:
- port: 80 #service端口号
targetPort: 80 #后端Pod端口号
protocol: TCP #使用的协议

2)创建并查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s-master ~]# kubectl apply -f manfests/service-demo.yaml    #创建资源对象
deployment.apps/service-deploy created
service/service-demo created
[root@k8s-master ~]# kubectl get svc #查看service资源对象,"kubectl get svc"等于"kubectl get service"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
nginx ClusterIP 10.104.116.156 <none> 80/TCP 80m
service-demo ClusterIP 10.98.31.157 <none> 80/TCP 7s
[root@k8s-master ~]# kubectl get pods -o wide -l app=service-deploy-demo #查看pod资源对象
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
service-deploy-66548cc57f-982cd 1/1 Running 0 15s 10.244.2.63 k8s-node2 <none> <none>
service-deploy-66548cc57f-blnvg 1/1 Running 0 15s 10.244.1.67 k8s-node1 <none> <none>
service-deploy-66548cc57f-vcmxb 1/1 Running 0 15s 10.244.2.62 k8s-node2 <none> <none>
[root@k8s-master ~]# kubectl get endpoints service-demo 查看生成的endpoints对应关系
NAME ENDPOINTS AGE
service-demo 10.244.1.67:80,10.244.2.62:80,10.244.2.63:80 43s

3)节点访问测试(这里使用创建一个新的pod资源模拟客户端进行访问)

Service资源的默认类型为ClusterIP,仅能接收kubernetes集群节点访问、或集群内部的pod对象中的客户端程序访问。

1
2
3
4
5
6
7
8
9
10
[root@k8s-master ~]# kubectl run busybox --image=busybox --rm -it -- /bin/sh    #使用busybox创建一个临时pod客户端
/ # wget -O - -q http://10.98.31.157/ #访问上面创建的service对象的Cluster IP
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # for i in 1 2 3 4; do wget -O - -q http://10.98.31.157/hostname.html; done #循环访问测试站点下的hostname.html页面,可以看出是轮循的分配给后端的pod资源。
service-deploy-66548cc57f-982cd
service-deploy-66548cc57f-blnvg
service-deploy-66548cc57f-982cd
service-deploy-66548cc57f-982cd

#说明:myapp容器中的“/hostname.html"页面能够输出当前容器的主机名。

2.1 Service会话粘性

Service资源支持Session affinity(粘性会话或会话粘性)机制,能够将来自同一个客户端的请求始终转发至同一个后端的Pod对象。这意味着会影响调度算法的流量分发功能,进而降低其负载均衡的效果。所以,当客户端访问pod中的应用程序时,如果有基于客户端身份保存某些私有信息,并基于这些私有信息追踪用户的活动等一类的需求时,就可以启用session affinity机制。

Session affinity的效果仅在一段时间期限内生效,默认值为10800秒,超出此时长之后,客户端的再次访问会被调度算法重新调度。Service资源的Session affinity机制仅能基于客户端的IP地址识别客户端身份,把经由同一个NAT服务器进行源地址转换的所有客户端识别为同一个客户端,便导致调度效果不佳,所以,这种方法并不常用。

Service资源通过service.spec.sessionAffinityservice.spec.sessionAffinityConfig两个字段配置粘性会话。sessionAffinity字段用于定义要使用的粘性会话的类型,仅支持使用“None”“ClientIp”两种属性值。

  • None:不使用sessionAffinity,默认值。

  • ClientIP:基于客户端IP地址识别客户端身份,把来自同一个源IP地址的请求始终调度至同一个Pod对象。

示例

这里将上面创建的service-demo资源对象进行修改

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
27
28
[root@k8s-master ~]# vim manfests/service-demo.yaml
......
spec:
selector:
app: service-deploy-demo
ports:
- port: 80
targetPort: 80
protocol: TCP
sessionAffinity: ClientIP #指定使用ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10 #配置session超时时间,这里为了看效果设置的比较短
[root@k8s-master ~]# kubectl apply -f manfests/service-demo.yaml
deployment.apps/service-deploy unchanged

#同样使用pod客户端访问测试
/ # for i in 1 2 3 4; do wget -O - -q http://10.98.31.157/hostname.html; done
service-deploy-66548cc57f-blnvg
service-deploy-66548cc57f-blnvg
service-deploy-66548cc57f-blnvg
service-deploy-66548cc57f-blnvg
#等待10秒过后再次访问
/ # for i in 1 2 3 4; do wget -O - -q http://10.98.31.157/hostname.html; done
service-deploy-66548cc57f-vcmxb
service-deploy-66548cc57f-vcmxb
service-deploy-66548cc57f-vcmxb
service-deploy-66548cc57f-vcmxb

2.2 类型

1
Service`的`IP`地址只能够在集群内部可访问,对一些应用(如`frontend`)的某些部分,可能希望通过外部(`kubernetes`集群外部)`IP`地址暴露`Service`,这时候就需要使用到`NodePort`。`kubernetes 

ServiceTypes支持四种类型:ClusterIPNodePortLoadBalancerExternalName,其默认是Cluster IP类型。

  • ClusterIP:通过集群内部IP地址暴露服务,此地址仅在集群内部可进行通行,无法被集群外部的客户端访问。

  • NodePort:通过每个Node上的IP和静态端口(NodePort)暴露服务,会自动为Service分配集群IP地址,并将此作为NodePort的路有目标。通过请求<NodePort>:<NodePort> --> <ClusterIP>:<ClusterPort> --> <PodIP>:<ContainerPort>访问到一个NodePort服务。

  • LoadBalancer:构建在NodePort之上,并创建一个外部负载均衡器,路由到ClusterIP。因此LoadBalancer一样具有NodePortClusterIP

  • EXternalName:通过返回CNAME和它的值,可以将服务映射到externalName字段的内容。换言之,此种类型并非定义由Kubernetes集群提供的服务,而是把集群外部的某服务以DNS CNAME记录的方式映射到集群内,从而让集群内的Pod资源能够访问外部的Service的一种实现方式。这种类型的Service没有ClusterIPNodePort,也没有标签选择器用于选择Pod资源,因此也不会有Endpoints存在。

2.2.1 ClusterIP类型的Service示例

1)编写配置清单文件(这里使用redis作为示例);先创建一个deployment,启动redis pod;再使用service绑定这个deployment下的pod资源。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
[root@k8s-master ~]# vim manfests/redis-svc.yaml    #编写yaml格式的清单文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis-pod
image: redis
ports:
- name: redis
containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-svc #service对象名
spec:
type: ClusterIP #这里指定使用ClusterIP,默认也是ClusterIP,这里可有可无
selector:
app: redis #匹配上面定义的pod资源
ports:
- port: 6379 #service端口
targetPort: 6379 #后端pod端口
protocol: TCP #协议

[root@k8s-master ~]# kubectl apply -f manfests/redis-svc.yaml #创建资源对象
deployment.apps/redis-deploy created
service/redis-svc created

2)查看创建的资源对象

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
[root@k8s-master ~]# kubectl get svc    #查看service资源
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
nginx ClusterIP 10.104.116.156 <none> 80/TCP 17h
redis-svc ClusterIP 10.102.44.127 <none> 6379/TCP 8s
service-demo ClusterIP 10.98.31.157 <none> 80/TCP 16h

[root@k8s-master ~]# kubectl get pods -l app=redis -o wide #查看标签app=redis的pod资源
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-deploy-6559cc4c4c-5v7kx 1/1 Running 0 33s 10.244.2.65 k8s-node2 <none> <none>
redis-deploy-6559cc4c4c-npdtf 1/1 Running 0 33s 10.244.1.69 k8s-node1 <none> <none>

[root@k8s-master ~]# kubectl describe svc redis-svc #查看redis-svc资源对象详细信息
Name: redis-svc
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis-svc","namespace":"default"},"spec":{"ports":[{"port":6379,"...
Selector: app=redis
Type: ClusterIP
IP: 10.102.44.127
Port: <unset> 6379/TCP
TargetPort: 6379/TCP
Endpoints: 10.244.1.69:6379,10.244.2.65:6379 #可以看出这里已经和上面的pod资源绑定
Session Affinity: None
Events: <none>

3)集群内部进行测试

1
2
3
4
5
6
7
8
9
10
#(1)集群内部的节点上面测试
[root@k8s-master ~]# redis-cli -h 10.102.44.127
10.102.44.127:6379> ping
PONG

#(2)在后端pod上面进行测试
[root@k8s-master ~]# kubectl exec redis-deploy-6559cc4c4c-5v7kx -it -- /bin/sh
# redis-cli -h 10.102.44.127
10.102.44.127:6379> ping
PONG

2.2.2 NodePort类型的Service示例

NodePort即节点Port,通常在安装部署Kubernetes集群系统时会预留一个端口范围用于NodePort,默认为30000~32767之间的端口。定义NodePort类型的Service资源时,需要使用.spec.type明确指定类型为NodePort

1)编写配置清单文件(这里使用nginx作为示例);先创建一个deployment,启动nginx pod;再使用service绑定这个deployment下的pod资源。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[root@k8s-master ~]# vim manfests/nginx-svc.yaml    #编写yaml格式的清单文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-pod
image: nginx:1.12
ports:
- name: nginx
containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc #service对象名
spec:
type: NodePort #这里指定使用ClusterIP,默认也是ClusterIP,这里可有可无
selector:
app: nginx #匹配上面定义的pod资源
ports:
- port: 80 #service端口
targetPort: 80 #后端pod端口
nodePort: 30080 #节点端口
protocol: TCP #协议

[root@k8s-master ~]# kubectl apply -f manfests/nginx-svc.yaml #创建资源对象
deployment.apps/nginx-deploy created
service/nginx-svc created

2)查看创建的资源对象

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
27
28
[root@k8s-master ~]# kubectl get svc    #查看service资源
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
nginx-svc NodePort 10.105.21.137 <none> 80:30080/TCP 4s
redis-svc ClusterIP 10.102.44.127 <none> 6379/TCP 55m
service-demo ClusterIP 10.98.31.157 <none> 80/TCP 16h

[root@k8s-master ~]# kubectl get pods -l app=nginx -o wide #查看标签app=nginx的pod资源
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-b6f876447-nlv6h 1/1 Running 0 33s 10.244.1.71 k8s-node1 <none> <none>
nginx-deploy-b6f876447-xmn2t 1/1 Running 0 33s 10.244.2.66 k8s-node2 <none> <none>

[root@k8s-master ~]# kubectl describe svc nginx-svc #查看nginx-svc资源对象详细信息
Name: nginx-svc
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"nginx-svc","namespace":"default"},"spec":{"ports":[{"nodePort":30...
Selector: app=nginx
Type: NodePort
IP: 10.105.21.137
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30080/TCP #这里可以看到多了NodePort且端口为30080
Endpoints: 10.244.1.71:80,10.244.2.66:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

3)集群外部进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@courtoap ~]# curl 192.168.1.31:30080    #访问集群master节点的30080端口
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
[root@courtoap ~]# curl 192.168.1.32:30080 #访问集群node节点的30080端口
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>

通过上面的测试可以看到通过NodePort的方式实现了从集群外部端口进行访问,实践中并不建议自定义使用的节点端口,因为容易产生冲突。建议让其自动生成即可。

2.3 Headless类型的Service资源

Service对象隐藏了各Pod资源,并负责将客户端请求流量调度至该组Pod对象之上,但也可能存在客户端直接访问Service资源后端的所有Pod资源,这时就应该向客户端暴露每个Pod资源的IP地址,而不是中间层Service对象的ClusterIP,这种类型的Service资源便称为Headless Service(无头服务)。

Headless Service对象没有ClusterIP,因此便没有相关负载均衡或代理问题,其如何为此类Service配置IP地址,其取决于标签选择器的定义。

  • 具有标签选择器:端点控制器(Endpoints Controller)会在API中为其创建Endpoints记录,并将ClusterDNS服务中的A记录直接解析到此Service后端的各Pod对象的IP地址上。

  • 没有标签选择器:端点控制器(Endpoints Controller)不会再API中为其创建Endpoints记录,ClusterDNS的配置分为两种情形,对ExternalName类型的服务创建CNAME记录,对其他三种类型来说,为那些与当前Service共享名称的所有Endpoints对象创建一条记录。

2.3.1 Headless类型的Service示例

配置Service资源配置清单时,只需要将ClusterIP字段的值设置为“None”即为其定义为Headless类型。

1)编写配置清单文件(这里使用apache作为示例);先创建一个deployment,启动apache pod;再使用service绑定这个deployment下的pod资源。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
[root@k8s-master ~]# vim manfests/httpd-svc-headless.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd-pod
image: httpd
ports:
- name: httpd
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpd-svc #service对象名
spec:
clusterIP: None #将ClusterIP字段设置为None即表示为headless类型的service资源对象
selector:
app: httpd #匹配上面定义的pod资源
ports:
- port: 80 #service端口
targetPort: 80 #后端pod端口
protocol: TCP #协议

[root@k8s-master ~]# kubectl apply -f manfests/httpd-svc-headless.yaml
deployment.apps/httpd-deploy created
service/httpd-svc created

2)查看创建的资源对象

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
27
28
[root@k8s-master ~]# kubectl get svc    #查看service资源
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP None <none> 80/TCP 4s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
nginx-svc NodePort 10.105.21.137 <none> 80:30080/TCP 112m
redis-svc ClusterIP 10.102.44.127 <none> 6379/TCP 168m
service-demo ClusterIP 10.98.31.157 <none> 80/TCP 18h

[root@k8s-master ~]# kubectl get pods -l app=httpd -o wide #查看标签app=httpd的pod资源
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-deploy-5494485b74-4vx64 1/1 Running 0 27s 10.244.2.72 k8s-node2 <none> <none>
httpd-deploy-5494485b74-j6hwm 1/1 Running 0 27s 10.244.2.71 k8s-node2 <none> <none>
httpd-deploy-5494485b74-jn48q 1/1 Running 0 27s 10.244.1.74 k8s-node1 <none> <none>

[root@k8s-master ~]# kubectl describe svc/httpd-svc #查看httpd-svc资源对象详细信息
Name: httpd-svc
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"httpd-svc","namespace":"default"},"spec":{"clusterIP":"None","por...
Selector: app=httpd
Type: ClusterIP
IP: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.74:80,10.244.2.71:80,10.244.2.72:80
Session Affinity: None
Events: <none>

3)测试资源发现

Headless Service工作特性可知,它记录于ClusterDNSA记录的相关解析结果是后端Pod资源的IP地址。意味着客户端通过Service资源的名称发现的是各Pod资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#(1)通过创建一个专用的测试Pod资源对象,而后通过其交互式接口进行测试
[root@k8s-master ~]# kubectl run cirror-$RANDOM --rm -it --image=cirros -- /bin/sh
/ # nslookup httpd-svc
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name: httpd-svc
Address 1: 10.244.2.71 10-244-2-71.httpd-svc.default.svc.cluster.local
Address 2: 10.244.1.74 10-244-1-74.httpd-svc.default.svc.cluster.local
Address 3: 10.244.2.72 10-244-2-72.httpd-svc.default.svc.cluster.local

#(2)直接在kubernetes集群上解析
[root@k8s-master ~]# dig -t A httpd-svc.default.svc.cluster.local. @10.96.0.10
......
;; ANSWER SECTION:
httpd-svc.default.svc.cluster.local. 26 IN A 10.244.2.72
httpd-svc.default.svc.cluster.local. 26 IN A 10.244.2.71
httpd-svc.default.svc.cluster.local. 26 IN A 10.244.1.74
......

本站由 卡卡龙 使用 Stellar 1.29.1主题创建

本站访问量 次. 本文阅读量 次.