Docker&Kubernetes ❀ Kubernetes集群Service资源配置清单
Posted 无糖可乐没有灵魂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker&Kubernetes ❀ Kubernetes集群Service资源配置清单相关的知识,希望对你有一定的参考价值。
文章目录
1、基本概念
在Kubernetes中,Pod是应用程序的载体,我们可以通过Pod的IP来访问应用程序,但是Pod的IP地址不是固定的,这也就意味这不方便直接采用Pod的IP对服务进行访问;
为了解决这一问题,Kubernetes提供了Service资源,Service会对提供同一个服务的多个Pod进行聚合,并且提供一个统一的入口地址,通过访问Service的入口就能访问到Pod对应的服务;
Service在很多情况下只是一个概念,真正起作用的是Kube-proxy服务进程,每个Node节点上都运行着Kube-proxy服务进程,当创建Service的时候会通过Api-server向Etcd写入创建的Service信息,而Kube-proxy会基于监听的机制发现这种Service的变动,然后它就会将最新的Service信息转换成对应的访问规则;目前Kube-proxy支持三种模式:Userspace模式、Iptables模式、Ipvs模式;
1.1 Userspace模式
Userspace模式下,Kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到Kube-proxy监听端口上,Kube-proxy根据负载均衡( LB - Load Balance)算法选择一个提供服务的Pod并和其建立连接,以将请求转发到Pod上;
该模式下,Kube-proxy充当了一个四层负载均衡器的角色,由于Kube-proxy运行在Userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝;
- 优点:比较稳定;
- 缺点:效率低下;
1.2 Iptables模式
Iptables模式下,Kube-proxy为Service后端的每个Pod创建相应的Iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP;
该模式下Kube-proxy不承担四层负载均衡器的角色,只负责创建Iptables规则;
- 优点:较Userspace模式效率更高;
- 缺点:不能提供灵活的负载均衡策略,当Pod不可用时无法进行重试;
1.3 Ipvs模式(推荐使用)
Ipvs模式和Iptables类似,Kube-proxy监控Pod的变化并创建相应的Ipvs规则;
- 优点:较Iptables模式效率更高;支持更多的负载均衡算法;
- 缺点:需要额外安装服务支持此模式(若未安装Ipvs服务,则自动降级使用Iptables模式);
Ipvs服务安装与启用:
#安装ipvsadm服务
[root@master ~]# yum install -y ipvsadm
[root@master ~]# rpm -qa ipvsadm
ipvsadm-1.31-1.el8.x86_64
#资源配置开启ipvs功能
[root@master ~]# kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited
[root@master ~]# kubectl describe cm kube-proxy -n kube-system | grep -w mode
mode: "ipvs"
#将模式修改为ipvs即可
#删除标签为k8s-app=kube-proxy的Pod(生产环境谨慎操作!)
[root@master ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
pod "kube-proxy-l2gbh" deleted
pod "kube-proxy-lmpb9" deleted
pod "kube-proxy-w98l4" deleted
#查看ipvs规则
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
#协议 本地地址:端口 调度器标识
# -> 映射地址:端口 转发;权重;活跃的连接;正在活跃的连接
TCP 172.17.0.1:30340 rr
#rr指轮询算法、wrr加权轮询、sh(source hash)原地址hash
TCP 192.168.122.1:30340 rr
TCP 10.81.20.170:30340 rr
TCP 10.96.0.1:443 rr
-> 10.81.20.170:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.125.130:53 Masq 1 0 0
-> 10.244.125.131:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.125.130:9153 Masq 1 0 0
-> 10.244.125.131:9153 Masq 1 0 0
TCP 10.108.222.136:80 rr
TCP 10.244.125.128:30340 rr
UDP 10.96.0.10:53 rr
-> 10.244.125.130:53 Masq 1 0 0
-> 10.244.125.131:53 Masq 1 0 0
2、服务类型
参数查询方法:
[root@master ~]# kubectl explain svc
参数汇总梳理:
apiVersion: v1 #版本信息
kind: Service #类型
metadata: #元数据
name: service
namespace: dev
spec: #详细描述
selector: #标签选择器,指定当前Service代理哪些Pod
app: nginx
type: #Service类型,指定服务访问方式
clusterIP: #虚拟服务的IP地址
sessionAffinity: #session亲和性,支持ClientIP与None两个选项
ports: #端口信息
- protocol: TCP #协议
port: 3001 #服务端口
targetPort: 3002 #Pod端口
nodePort: 30001 #主机端口
2.1 服务类型
- ClusterIP:默认值,通过Kubernetes系统自动分配的虚拟IP地址,只能在集群内部访问;
- NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法可以使得集群外部访问Pod对应服务;
- LoadBalancer:使用外接负载均衡设备完成服务的负载分发,此模式需要增加外部设备完成;
- ExternalName:把集群外部的服务引入集群内部,直接使用即可;
3、服务使用方法
以四种服务类型实现不同的实验;
3.1 环境准备
在使用Service之前,利用Delpoyment创建出3个Pod,设置Pod标签为:app=nginx=pod;
#创建YAML文件
[root@master ~]# cat pc-deployment.yaml
apiVersion: apps/v1 #版本信息
kind: Deployment #类型
metadata: #元数据
name: pc-deployment
namespace: dev
spec: #详细描述
replicas: 3 #副本数量
selector: #选择器,指定管理那些Pod
matchLabels: #匹配标签规则
app: nginx-pod
template: #模板,当副本数量不足时,根据下面的配置创建Pod
metadata:
labels: #Pod标签
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
#调用YAML文件
[root@master ~]# kubectl apply -f pc-deployment.yaml
deployment.apps/pc-deployment created
#查看Pod地址与标签
[root@master ~]# kubectl get pod -n dev -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pc-deployment-6756f95949-bdhs9 1/1 Running 0 39s 10.244.166.172 node2.k8s <none> <none> app=nginx-pod,pod-template-hash=6756f95949
pc-deployment-6756f95949-k4b5p 1/1 Running 0 39s 10.244.112.57 node1.k8s <none> <none> app=nginx-pod,pod-template-hash=6756f95949
pc-deployment-6756f95949-n8llx 1/1 Running 0 39s 10.244.166.171 node2.k8s <none> <none> app=nginx-pod,pod-template-hash=6756f95949
#为了方便后续测试,修改三个Pod默认页面(区别名显即可)
[root@master ~]# kubectl exec -it pc-deployment-6756f95949-bdhs9 -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pc-deployment-6756f95949-bdhs9:/# echo this is testA! > /usr/share/nginx/html/index.html
root@pc-deployment-6756f95949-bdhs9:/# exit
exit
[root@master ~]# kubectl exec -it pc-deployment-6756f95949-k4b5p -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pc-deployment-6756f95949-k4b5p:/# echo this is testB! > /usr/share/nginx/html/index.html
root@pc-deployment-6756f95949-k4b5p:/# exit
exit
[root@master ~]# kubectl exec -it pc-deployment-6756f95949-n8llx -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pc-deployment-6756f95949-n8llx:/# echo this is testC! > /usr/share/nginx/html/index.html
root@pc-deployment-6756f95949-n8llx:/# exit
exit
#验证修改后结果
[root@master ~]# curl http://10.244.166.172
this is testA!
[root@master ~]# curl http://10.244.112.57
this is testB!
[root@master ~]# curl http://10.244.166.171
this is testC!
3.2 ClusterIP类型
#创建YAML文件
[root@master ~]# cat service-clusterip.yaml
apiVersion: v1 #版本信息
kind: Service #类型
metadata: #元数据
name: service-clusterip
namespace: dev
spec: #详细描述
selector: #标签选择器,指定当前Service代理哪些Pod
app: nginx-pod
type: ClusterIP #Service类型,指定服务访问方式
clusterIP: 10.96.96.96 #虚拟服务的IP地址,默认IP支持网段10.96.0.0/12
ports: #端口信息
- protocol: TCP #协议
port: 80 #服务端口
targetPort: 80 #Pod端口
#调用YAML文件
[root@master ~]# kubectl apply -f service-clusterip.yaml
service/service-clusterip created
#查看svc
[root@master ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-clusterip ClusterIP 10.96.96.96 <none> 80/TCP 60s app=nginx-pod
#查看svc详细信息
[root@master ~]# kubectl describe svc service-clusterip -n dev
Name: service-clusterip
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.96.96
IPs: 10.96.96.96
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.57:80,10.244.166.171:80,10.244.166.172:80
Session Affinity: None
Events: <none>
#查看ipvs映射关系
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
~
TCP 10.96.96.96:80 rr
# rr 为轮询策略,意味10.96.96.96:80的请求会一次发送到10.244.112.57:80,10.244.166.171:80,10.244.166.172:80三个Pod
-> 10.244.112.57:80 Masq 1 0 0
-> 10.244.166.171:80 Masq 1 0 0
-> 10.244.166.172:80 Masq 1 0 0
#验证svc服务是否生效
[root@master ~]# while true;do curl http://10.96.96.96;sleep 3;done
this is testA!
this is testC!
this is testB!
this is testA!
this is testC!
this is testB!
^C
3.2.1 Endpoint
Endpoint是Kubernetes中的一个资源对象,存储在Etcd中,用来记录一个Service对应的所有Pod的访问地址,它是根据Service配置文件中的Selector描述产生的;
一个Service由一组Pod组成,这些Pod通过Endpoint暴露出来,Endpoint是实现实际服务的端点集合,Service与Pod之间的联系是通过Endpoints实现的;
#查看Endpoint
[root@master ~]# kubectl get endpoint -n dev
NAME ENDPOINTS AGE
service-clusterip 10.244.112.57:80,10.244.166.171:80,10.244.166.172:80 5m45s
3.2.2 SessionAffinity
Service的访问请问被分发到后端的Pod上时支持两种亲和性负载分发策略:
None:默认使用Kube-proxy的策略,如随机、轮询;
ClientIP:基于客户端地址的会话保持模式,来自同一个客户端发起的所有请求会在固定时间内转发到一个固定的Pod上,默认时间为10800s(3小时);
#清理当前svc,如果没有则直接跳过
[root@master ~]# kubectl delete -f service-clusterip.yaml
service "service-clusterip" deleted
#添加或修改sessionAffinity参数为ClientIP
[root@master ~]# cat service-clusterip.yaml | grep sessionAffinity
sessionAffinity: ClientIP #亲和性修改为ClientIP
#重新调用svc
[root@master ~]# kubectl apply -f service-clusterip.yaml
service/service-clusterip created
#验证结果
[root@master ~]# while true;do curl http://10.96.96.96;sleep 3;done
this is testA!
this is testA!
this is testA!
this is testA!
this is testA!
^C
#查看ipvs规则
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
~
TCP 10.96.96.96:80 rr persistent 10800
#persistent 持续的,代表轮询算法需要保持10800s(3h)后重新轮询其他Pod(会话保持机制,短时间内同一个客户端的所有请求发送在一个Pod上进行处理)
-> 10.244.112.57:80 Masq 1 0 0
-> 10.244.166.171:80 Masq 1 0 0
-> 10.244.166.172:80 Masq 1 0 5
#删除当前svc
[root@master ~]# kubectl delete -f service-clusterip.yaml
service "service-clusterip" deleted
3.3 Headless类型
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而是自己来控制负载均衡策略,针对这些情况,Kubernetes提供了Headless Service,这类Service不会分配ClusterIP,如果需要访问,只能通过Service的域名进行查询;
Headless类型的Service就是没有的Service服务,主要应用场景有如下两种:
- Client自主选择权:有时候客户端想自己决定需要使用哪个真实的服务处理请求,可以通过查询DNS域名来获取真实服务的信息;
- EndPoint实现互相访问:Headless Service对应的每一个Endpoint都有对应的DNS域名,这样Endpoint之间就可以互相访问;
#创建YAML文件
[root@master ~]# vim service-headless.yaml
apiVersion: v1 #版本信息
kind: Service #类型
metadata: #元数据
name: service-clusterip
namespace: dev
spec: #详细描述
selector: #标签选择器,指定当前Service代理哪些Pod
app: nginx-pod
type: ClusterIP #Service类型,指定服务访问方式
clusterIP: None #虚拟服务的IP地址,默认IP支持网段10.96.0.0/12
ports: #端口信息
- protocol: TCP #协议
port: 80 #服务端口
targetPort: 80 #Pod端口
#调用YAML文件
[root@master ~]# kubectl apply -f service-headless.yaml
service/service-clusterip created
#查看svc,发现CLUSTER-IP内容显示为None
[root@master ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-clusterip ClusterIP None <none> 80/TCP 16s app=nginx-pod
#查看svc详细信息
[root@master ~]# kubectl describe svc service-clusterip -n dev
Name: service-clusterip
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.112.57:80,10.244.166.171:80,10.244.166.172:80
Session Affinity: None
Events: <none>
#查看当前Pod名称
[root@master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pc-deployment-6756f95949-bdhs9 1/1 Running 0 58m
pc-deployment-6756f95949-k4b5p 1/1 Running 0 58m
pc-deployment-6756f95949-n8llx 1/1 Running 0 58m
#登录其中一个Pod查看DNS解析IP
[root@master ~]# kubectl exec -it pc-deployment-6756f95949-bdhs9 -n dev /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pc-deployment-6756f95949-bdhs9:/# cat /etc/resolv.conf
nameserver 10.96.0.10
search dev.svc.cluster.local svc.cluster.local cluster.local k8s
options ndots:5
root@pc-deployment-6756f95949-bdhs9:/# exit
exit
#使用dig命令解析域名
[root@master ~]# dig @10.96.0.10 service-clusterip.dev.svc.cluster.local
~
service-clusterip.dev.svc.cluster.local. 30 IN A 10.244.166.172
service-clusterip.dev.svc.cluster.local. 30 IN A 10.244.166.171
service-clusterip.dev.svc.cluster.local. 30 IN A 10.244.112.57
#删除svc
[root@master ~]# kubectl delete -f service-headless.yaml
service "service-clusterip" deleted
3.4 NodePort类型
在之前的例子中,创建的Service IP地址只有集群内部可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一个类型的Service,称为NodePort类型,NodePort的工作原理其实就是将Service的端口映射到Node上的另一个端口,使得外部环境可以通过Node端口访问到内部Pod提供的服务;
#创建YAML文件
[root@master ~]# vim service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: service-nodeport
namespace: dev
spec:
selector:
app: nginx-pod
type: NodePort #svc类型
ports:
- port: 80 #svc端口
nodePort: 30080 #Node端口
targetPort: 80 #Pod端口
#调用YAML文件
[root@master ~]# kubectl apply -f service-nodeport.yaml
service/service-nodeport created
#查看svc信息
[root@master ~]# kubectl get svc -n dev -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-nodeport NodePort 10.102.191.96 <none> 80:30080/TCP 30s app=nginx-pod
#查看svc详细信息
[root@master ~]# kubectl describe svc service-nodeport -n dev
Name: service-nodeport
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.102.191.96
IPs: 10.102.191.96
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30080/TCP
Endpoints: 10.244.112.57:80,10.244.166.171:80,10.244.166.172:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
#验证结果
[root@master ~]# while true;do curl http://10.81.20.170:30080;sleep 3;done
this is testB!
this is testA!
this is testC!
^C
#删除
[root@master ~]# kubectl delete -f service-nodeport.yaml
service "service-nodeport" deleted
3.5 LoadBalancer类型
LoadBalance和NodePort基本一致,目的都是向外部暴露出一个端口,区别在于LoadBalancer会在集群的外部添加一个负载均衡设备,外部服务将访问请求发送到这个负载均衡设备上,会被该设备负载后转发到集群之中,由于需要外部设备支持,此实验无法完成;
3.6 ExternalName类型
ExternalName类型的Service用于引入集群外部的服务,通过externalName属性指定一个外部的服务地址或域名,然后在集群内部访问此Service就可以访问到外部服务;
#创建YAML文件
apiVersion: v1
kind: Service
metadata:
name: externalname
namespace: dev
spec:
type: ExternalName #service类型
externalName: www.baidu.com #域名或IP地址
#调用YAML文件
[root@master ~]# kubectl apply -f service-externalname.yaml
service/externalname created
#查看svc
[root@master ~]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
externalname ExternalName <none> www.baidu.com <none> 30s
#查看svc详细信息
[root@master ~]# kubectl describe svc externalname -n dev
Name: externalname
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ExternalName
IP Families: <none>
IP:
IPs: <none>
External Name: www.baidu.com
Session Affinity: None
Events: <none>
#使用dig命令解析域名
[root@master ~]# dig @10.96.0.10 externalname.dev.svc.cluster.local
~
externalname.dev.svc.cluster.local. 21 IN CNAME www.baidu.com.
www.baidu.com. 21 IN CNAME www.a.shifen.com.
www.a.shifen.com. 21 IN A 182.61.200.7
www.a.shifen.com. 21 IN A 182.61.200.6
#删除
[root@master ~]# kubectl delete -f service-externalname.yaml
service "externalname" deleted
3.7 应用案例
实验说明:创建两个名称空间,区别不同的Pod,在两个名称空间各自创建一个Pod(可以单独创建,也可以使用Deployment创建)、两个Service服务:Headless Service与ExternaleName Service;
#创建名称空间
[root@master ~]# kubectl create ns test1
namespace/test1 created
[root@master ~]# kubectl create ns test2
namespace/test2 created
#创建YAML文件
[root@master ~]# cat test1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: test1
spec:
replicas: 1
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
namespace: test1
spec:
selector:
app: myapp
release: canary
clusterIP: None
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp-svcname
namespace: test1
spec:
type: ExternalName
externalName: myapp-svc.test1.svc.cluster.local
#调用YAML文件
[root@master ~]# kubectl apply -f test1.yaml
deployment.apps/myapp created
service/myapp-svc created
service/myapp-svcname created
#查看pod与svc信息
[root@master ~]# kubectl get pod,svc -n test1
NAME READY STATUS RESTARTS AGE
pod/myapp-6bb4786bcd-qkkx7 1/1 Running 0 44s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/myapp-svc ClusterIP None <none> 80/TCP 44s
service/myapp-svcname ExternalName <none> myapp-svc.test1.svc.cluster.local <none> 44s
#检查DNS域名是否解析成功,解析地址获取参考3.3章节
[root@master ~]# dig -t A myapp-svc.test1.svc.cluster.local @10.96.0.10
~
myapp-svc.test1.svc.cluster.local. 30 IN A 10.244.112.63
#复制文件并修改文件内容,简便修改方式如下命令
[root@master ~]# cp test1.yaml test2.yaml
[root@master ~]# vim test2.yaml
#通过vim命令修改test1为test2
:%s/test1/test2/g
#调用YAML文件
[root@master ~]# kubectl apply -f test2.yaml
deployment.apps/myapp created
service/myapp-svc created
service/myapp-svcname created
#查看svc信息
[root@master ~]# kubectl get svc -n test1
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp-svc ClusterIP None <none> 80/TCP 4m45s
myapp-svcname ExternalName <none> myapp-svc.test1.svc.cluster.local <none> 4m45s
[root@master ~]# kubectl get svc -n test2
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp-svc ClusterIP None <none> 80/TCP 49s
myapp-svcname ExternalName <none> myapp-svc.test2.svc.cluster.local <none> 49s
#查看Pod信息
[root@master ~]# kubectl get pod -n test1 -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-6bb4786bcd-qkkx7 1/1 Running 0 5m10s 10.244.112.63 node1.k8s <none> <none>
以上是关于Docker&Kubernetes ❀ Kubernetes集群Service资源配置清单的主要内容,如果未能解决你的问题,请参考以下文章
Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法
Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法
Docker&Kubernetes ❀ Kubernetes集群实践与部署笔记知识点梳理
Docker&Kubernetes ❀ Docker 容器技术笔记链接梳理