k8s之Service
# 什么是service?
将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
为什么需要service?
pod的数量、IP都是动态变化的,service可以给该集合的Pod一个固定的IP,无论pod的集合如何改变,都可以通过service的固定IP来访问到应用。
可以给pod集合提供负载均衡的功能。
Service类型
- LoadBalance,使用云提供商的负载均衡器向外部暴露服务。
- ExternalName,将服务映射到指定的域名,这个域名可以集群内部也可以是外部的。
- NodePort,提供的服务既可对外部服务通过NodeIp:NodePort访问,也可以对集群内部通过ClusterIp访问
- ClusterIP,service提供的访问IP仅在集群内部可达
# 使用ClusterIP Service
我们定义service如下,其中selector是用来筛选需要代理的pod,targetPort是目标pod的端口,port是指该service的端口。
kind: Service
apiVersion: v1
metadata:
name: demoapp-svc
spec:
selector:
app: demoapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
2
3
4
5
6
7
8
9
10
11
12
使用上面定义的yaml创建service对象,并可以看到SELECTOR的值是app=demoapp,我们需要创建带有该标签的pod,才能够进行代理。
[root@k8s-worker1 zwf]# kubectl apply -f service.yaml -n zwf
service/demoapp-svc created
[root@k8s-worker1 zwf]# kubectl get svc -n zwf -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
demoapp-svc ClusterIP 10.0.0.74 <none> 80/TCP 18s app=demoapp
2
3
4
5
6
定义deployment,会创建带有app=demoapp的Pod
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: demoapp
name: demo-deploy
spec:
replicas: 2
selector:
matchLabels:
app: demoapp
template:
metadata:
labels:
app: demoapp
spec:
containers:
- image: mirrors.sangfor.com/ikubernetes/demoapp:v1.0
name: demoapp
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
创建Deployment对象,并且可以看到创建了2个Pod
[root@k8s-worker1 zwf]# kubectl apply -f deployments_service.yaml -n zwf
deployment.apps/demo-deploy created
[root@k8s-worker1 zwf]# kubectl get deploy -o wide -n zwf
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
demo-deploy 2/2 2 2 2m37s demoapp mirrors.sangfor.com/ikubernetes/demoapp:v1.0 app=demoapp
2
3
4
5
6
7
查看pod的详情,可以看到Labels有一个app=demoapp
的标签
[root@k8s-worker1 zwf]# kubectl get pods -o wide -n zwf
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo-deploy-6c6d588789-h9gmd 1/1 Running 0 32s 10.222.126.1 k8s-worker2 <none> <none>
demo-deploy-6c6d588789-nhzhl 1/1 Running 0 32s 10.222.194.104 k8s-worker1 <none> <none>
[root@k8s-worker1 zwf]# kubectl describe demo-deploy-6c6d588789-h9gmd -n zwf
Name: demo-deploy-6c6d588789-h9gmd
Namespace: zwf
Priority: 0
Node: k8s-worker2/10.64.2.153
Start Time: Tue, 30 Aug 2022 19:23:22 +0800
Labels: app=demoapp
pod-template-hash=6c6d588789
....
2
3
4
5
6
7
8
9
10
11
12
13
14
15
通过查看service的详情,我们可以看到Endpoints的值是上面创建的两个Pod的IP。
[root@k8s-worker1 zwf]# kubectl describe svc -n zwf
Name: demoapp-svc
Namespace: zwf
Labels: <none>
Annotations: <none>
Selector: app=demoapp
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.0.0.74
IPs: 10.0.0.74
Port: http 80/TCP
TargetPort: 80/TCP
Endpoints: 10.222.126.1:80,10.222.194.104:80
Session Affinity: None
Events: <none>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Endpoints也是一个资源对象,Service通过筛选标签到的Pod会添加到Endpints中保存
[root@k8s-worker1 zwf]# kubectl get endpoints -n zwf
NAME ENDPOINTS AGE
demoapp-svc 10.222.126.1:80,10.222.194.104:80 15m
2
3
这个时候,我们访问service的80端口,会访问到轮询访问到这两个pod中,我们就可以通过访问service来访问pod集合。
[root@k8s-worker1 zwf]# curl 10.0.0.74
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-nhzhl, ServerIP: 10.222.194.104!
[root@k8s-worker1 zwf]# curl 10.0.0.74
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-h9gmd, ServerIP: 10.222.126.1!
[root@k8s-worker1 zwf]# curl 10.0.0.74
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-nhzhl, ServerIP: 10.222.194.104!
[root@k8s-worker1 zwf]# curl 10.0.0.74
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-h9gmd, ServerIP: 10.222.126.1!
2
3
4
5
6
7
8
9
10
11
除了通过ClusterIP访问,在集群中也能通过域名进行访问,访问方式:<serviceName>.<namespace>.svc.cluster.local
[root@k8s-worker1 zwf]# kubectl exec -it demo-deploy-6c6d588789-h9gmd -n zwf -- nslookup demoapp-svc.zwf.svc.cluster.local
Server: 10.0.0.2
Address: 10.0.0.2#53
Name: demoapp-svc.zwf.svc.cluster.local
Address: 10.0.0.74
[root@k8s-worker1 zwf]# kubectl exec -it demo-deploy-6c6d588789-h9gmd -n zwf -- curl demoapp-svc.zwf.svc.cluster.local
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.153, ServerName: demo-deploy-6c6d588789-h9gmd, ServerIP: 10.222.126.1!
[root@k8s-worker1 zwf]# kubectl exec -it demo-deploy-6c6d588789-h9gmd -n zwf -- curl demoapp-svc.zwf.svc.cluster.local
iKubernetes demoapp v1.0 !! ClientIP: 10.222.126.1, ServerName: demo-deploy-6c6d588789-nhzhl, ServerIP: 10.222.194.104!
2
3
4
5
6
7
8
9
10
11
12
# 使用NodePort Service
定义NodePort Service如下,和ClusterIP Service比较,新增type: NodePort
代表该Service的类型是NodePort,然后nodePort是节点的端口,在每一台Node上都会创建这么一个端口给集群外调用。
kind: Service
apiVersion: v1
metadata:
name: demoapp-nodeport-svc
spec:
selector:
app: demoapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 31999
type: NodePort
2
3
4
5
6
7
8
9
10
11
12
13
14
创建该Service,可以看到TYPE是NodePort,PORT是80:31999代表着将80端口映射到节点的31999端口
[root@k8s-worker1 zwf]# kubectl apply -f service_nodeport.yaml -n zwf
service/demoapp-nodeport-svc created
[root@k8s-worker1 zwf]# kubectl get svc -n zwf -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
demoapp-nodeport-svc NodePort 10.0.0.144 <none> 80:31999/TCP 10s app=demoapp
demoapp-svc ClusterIP 10.0.0.74 <none> 80/TCP 47m app=demoapp
2
3
4
5
6
7
我们可以在集群外通过节点的IP:31999端口一样可以访问Pod服务。
C:\Users\User>curl 10.64.2.141:31999
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-nhzhl, ServerIP: 10.222.194.104!
C:\Users\User>curl 10.64.2.141:31999
iKubernetes demoapp v1.0 !! ClientIP: 10.64.2.141, ServerName: demo-deploy-6c6d588789-h9gmd, ServerIP: 10.222.126.1!
2
3
4
5
# 如何实现的代理?
每个Node都会有一个kube-proxy进程,该进程会监控Service的创建与EndPoints列表的添加与删除,配置iptables规则,当客户端请求Service的ClusterIP和端口时,会根据规则轮询转发到后端的Pod中。