- 现在有个问题
问题:1、如何让前端程序连接后端程序?-->LB2、如何让多个前端程序为用户提供服务?-->LB
pod是短暂的,ip是会变的;一般k8s里部署的pod都是多副本的,此时如果给用户/其它程序提供服务时,就需要有用到`负载均衡LB`来解决统一访问问题;LB肯定是要关联服务器的具体IP的;如果这一组pod版本更新后,ip也就发生了变化,如何能让LB的动态地感知这些ip发生的变化呢?(pod的动态发现)负载均衡Pod自动发现=>此时,就需要用到service这个功能了。
- service主要功能
service主要功能:1、为pod提供负载均衡(iptables、ipvs)2、动态感知pod的变化,会把podip变化更新到负载均衡
- 注意:四层和七层的区别
OSI七层模型层四层,传输层∶基于ip+port转发,不考虑其他的东西七层,应用层∶会考虑协议层面东西,例如`域名、uri、cookie、 header`,典型的http协议.
3.Pod与Service的关系
- Service通过标签关联一组Pod
- Service使用iptables或者ipvs为一组Pod提供负载均衡能力
- 注意:svc和项目是一一对应的
每个svc和每个业务项目都是一一对应的;每部署一个deployment,就需要创建一个svc;而deployment就是运行我们项目的地方;
- 注意:
service->deployment->pod
在k8s里,需要用到标签的,最常用的就是`deployment/service -> 多个pod`这些资源了,其他资源很少用到标签的;
2、三种IP
在继续往下学习 Service 之前,我们需要先弄明白 Kubernetes 系统中的三种IP,因为经常有同学混乱。
- Node IP:Node 节点的 IP 地址
- Pod IP:Pod 的 IP 地址
- Cluster IP:Service 的 IP 地址
首先,Node IP 是 Kubernetes 集群中节点的物理网卡 IP 地址(一般为内网),所有属于这个网络的服务器之间都可以直接通信,所以 Kubernetes 集群外要想访问 Kubernetes 集群内部的某个节点或者服务,肯定得通过 Node IP 进行通信(这个时候一般是通过外网 IP 了)。
然后 Pod IP 是每个 Pod 的 IP 地址,它是网络插件进行分配的,前面我们已经讲解过。
最后 Cluster IP 是一个虚拟的 IP,仅仅作用于 Kubernetes Service 这个对象,由 Kubernetes 自己来进行管理和分配地址。
3、定义 Service
定义 Service 的方式和我们前面定义的各种资源对象的方式类型,例如,假定我们有一组 Pod 服务,它们对外暴露了 8080 端口,同时都被打上了 app=myapp 这样的标签,那么我们就可以像下面这样来定义一个 Service 对象:
apiVersion:v1kind:Servicemetadata:name:myservicespec:selector:app:myappports:- protocol:TCPport:80targetPort:8080name:myapp-http
然后通过的使用 kubectl create -f myservice.yaml
就可以创建一个名为 myservice 的 Service 对象,**它会将请求代理到使用 TCP 端口为 8080,具有标签 **app=myapp
的 Pod 上,**这个 Service 会被系统分配一个我们上面说的 Cluster IP,**该 Service 还会持续的监听 selector 下面的 Pod,会把这些 Pod 信息更新到一个名为 myservice 的Endpoints 对象上去,这个对象就类似于我们上面说的 Pod 集合了。
方法1:
#nginx-svc-demo.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:nginxspec:replicas:3selector:matchLabels:app:web#1template:metadata:labels:app:web#2spec:containers:- image:nginxname:nginxports:- protocol:TCPcontainerPort:80#容器内暴露的端口,注意:这里的 containerPort:80只是一个标识,真正起作用的还是容器里服务的端口号 name:nginx-http---apiVersion:v1kind:Servicemetadata:name:myservicespec:selector:app:web#3ports:- protocol:TCPport:8080#如果没有配置targetPort,则这里的port 要和容器内暴露的端口保持一致targetPort:80#—定要和容器内你的这个应用暴露的端口保持一致name:myapp-http
方法2:
需要注意的是,Service 能够将一个接收端口映射到任意的 targetPort。默认情况下,targetPort 将被设置为与 port 字段相同的值。可能更有趣的是,targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称。因实际指派给该端口名称的端口号,在每个 backend Pod 中可能并不相同,所以对于部署和设计 Service,这种方式会提供更大的灵活性。
#nginx-svc-demo.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:nginxspec:replicas:3selector:matchLabels:app:web#1template:metadata:labels:app:web#2spec:containers:- image:nginxname:nginxports:- protocol:TCPcontainerPort:80#容器内暴露的端口,注意:这里的 containerPort:80只是一个标识,真正起作用的还是容器里服务的端口号 name:nginx-http---apiVersion:v1kind:Servicemetadata:name:myservicespec:selector:app:web#3ports:- protocol:TCPport:8080#如果没有配置targetPort,则这里的port 要和容器内暴露的端口保持一致targetPort:nginx-http#80 #—定要和容器内你的这个应用暴露的端口保持一致,这里直接使用一个containerPort name也是可以的。name:myapp-http
另外 Service 能够支持 TCP 和 UDP 协议,默认是 TCP 协议。
==💘 实战:定义与创建Service-2023.2.11(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:apiVersion:apps/v1kind:Deploymentmetadata:name:nginxspec:replicas:3selector:matchLabels:app:web#1template:metadata:labels:app:web#2spec:containers:- image:nginxname:nginxports:- protocol:TCPcontainerPort:80#容器内暴露的端口,注意:这里的 containerPort:80只是一个标识,真正起作用的还是容器里服务的端口号 name:nginx-http---apiVersion:v1kind:Servicemetadata:name:myservicespec:selector:app:web#3type:ClusterIP# 服务类型,默认就是ClusterIPports:- protocol:TCPport:8080#如果没有配置targetPort,则这里的port 要和容器内暴露的端口保持一致targetPort:80#—定要和容器内你的这个应用暴露的端口保持一致name:myapp-http
- 测试
下面我们来部署测试下效果,先部署下:
[root@master1 ~]#kubectl apply -f nginx-svc-demo.yamldeployment.apps/nginxcreatedservice/myservicecreated[root@master1 ~]#kubectl get po -owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESnginx-f4f7749b5-8wqjs1/1Running058s10.244.1.60node1<none><none>nginx-f4f7749b5-97dw51/1Running028s10.244.2.56node2<none><none>nginx-f4f7749b5-hrfnj1/1Running028s10.244.1.61node1<none><none>[root@master1 ~]#kubectl get svc -owideNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGESELECTORkubernetesClusterIP10.96.0.1<none>443/TCP68d<none>myserviceClusterIP10.107.211.179<none>8080/TCP4m49sapp=webnginxClusterIPNone<none>80/TCP54dapp=nginx[root@master1 ~]#kubectl get ep -owideNAMEENDPOINTSAGEkubernetes172.29.9.61:644368dmyservice10.244.1.60:80,10.244.1.61:80,10.244.2.56:804m52snginx<none>54d
我们来分别访问下podIP:80和svcIP:8080看下效果:
#访问podIP:80是可以的[root@master1 ~]#curl 10.244.1.62:80<!DOCTYPEhtml><html><head><title>Welcome to nginx!</title><style>html{color-scheme:lightdark;}body{width:35em;margin:0auto;font-family:Tahoma,Verdana,Arial,sans-serif;}</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page,the nginx web server is successfully installed andworking.Furtherconfigurationisrequired.</p><p>For online documentation and support please refer to<a href="http:Commercialsupportisavailableat<a href="http:<p><em>Thank you forusing nginx.</em></p></body></html>#访问svcIP:80是可以的[root@master1 ~]#curl 10.107.211.179:8080<!DOCTYPEhtml><html><head><title>Welcome to nginx!</title><style>html{color-scheme:lightdark;}body{width:35em;margin:0auto;font-family:Tahoma,Verdana,Arial,sans-serif;}</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page,the nginx web server is successfully installed andworking.Furtherconfigurationisrequired.</p><p>For online documentation and support please refer to<a href="http:Commercialsupportisavailableat<a href="http:<p><em>Thank you forusing nginx.</em></p></body></html>
测试结束。😘
==💘 实战:多端口Service定义-2022.7.21(测试成功)==
多端口Service定义
:对于某些服务,需要公开多个端口,Service也需要配置多个端口定义,通过端口名
称区分。
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:apiVersion:v1kind:Servicemetadata:labels:app:webname:webspec:ports:- port:80name:api1#port:80 nameprotocol:TCPtargetPort:80#port:80 - port:81name:api2#port:81 nameprotocol:TCPtargetPort:81#port:81selector:app:webtype:NodePort
- 部署并查看
[root@k8s-master ~]#kubectl apply -f service3.yaml[root@k8s-master ~]#kubectl get svc
一般这种情况,工作中很少用到。常规下,pod里只提供一个服务端口。
测试结束。😘
4、kube-proxy
前面我们讲到过,在 Kubernetes 集群中,每个 Node 会运行一个 kube-proxy 进程,负责为 Service 实现一种 VIP(虚拟 IP,就是我们上面说的 clusterIP)的代理形式,现在的 Kubernetes 中默认是使用的 iptables 这种模式来代理。
我们来大概看下当前k8s集群kube-proxy
组件的情况:
现在版本默认模式是ipvs
;v1.22,已经默认使用ipvs
了;
[root@master1 ~]#kubectl get po -A -owide
[root@master1 ~]#kubectl get ds -nkube-systemNAMEDESIREDCURRENTREADYUP-TO-DATEAVAILABLENODESELECTORAGEkube-flannel-ds33333<none>41dkube-proxy33333kubernetes.io/os=linux41d[root@master1 ~]#kubectl get ds kube-proxy -nkube-system -oyamlapiVersion:apps/v1kind:DaemonSetmetadata:annotations:deprecated.daemonset.template.generation:"1"creationTimestamp:"2021-10-31T00:00:26Z"generation:1labels:k8s-app:kube-proxyname:kube-proxynamespace:kube-systemresourceVersion:"808267"uid:ba1a6f0d-72c9-46a1-b295-594d860a7d70spec:revisionHistoryLimit:10selector:matchLabels:k8s-app:kube-proxytemplate:metadata:creationTimestamp:nulllabels:k8s-app:kube-proxyspec:containers:-command:-/usr/local/bin/kube-proxy---config=/var/lib/kube-proxy/config.conf---hostname-override=$(NODE_NAME)env:-name:NODE_NAMEvalueFrom:fieldRef:apiVersion:v1fieldPath:spec.nodeNameimage:registry.aliyuncs.com/k8sxio/kube-proxy:v1.22.2imagePullPolicy:IfNotPresentname:kube-proxyresources:{}securityContext:privileged:trueterminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/lib/kube-proxyname:kube-proxy-mountPath:/run/xtables.lockname:xtables-lock-mountPath:/lib/modulesname:lib-modulesreadOnly:truednsPolicy:ClusterFirsthostNetwork:truenodeSelector:kubernetes.io/os:linuxpriorityClassName:system-node-criticalrestartPolicy:AlwaysschedulerName:default-schedulersecurityContext:{}serviceAccount:kube-proxyserviceAccountName:kube-proxyterminationGracePeriodSeconds:30tolerations:-operator:Existsvolumes:-configMap:defaultMode:420name:kube-proxyname:kube-proxy-hostPath:path:/run/xtables.locktype:FileOrCreatename:xtables-lock-hostPath:path:/lib/modulestype:""name:lib-modulesupdateStrategy:rollingUpdate:maxSurge:0maxUnavailable:1type:RollingUpdatestatus:currentNumberScheduled:3desiredNumberScheduled:3numberAvailable:3numberMisscheduled:0numberReady:3observedGeneration:1updatedNumberScheduled:3
1.iptables
这种模式,kube-proxy 会 watch apiserver (基本上所有的组件都是去watch api-server的)对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某一个 Pod 上面。我们还可以使用 Pod readiness 探针
验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端,这样做意味着可以避免将流量通过 kube-proxy
发送到已知失败的 Pod 中,所以对于线上的应用来说一定要做 readiness 探针。
iptables 模式的 kube-proxy 默认的策略是,随机选择一个后端 Pod。
比如当创建 backend Service 时,Kubernetes 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。假设 Service 的端口是 1234,该 Service 会被集群中所有的 kube-proxy 实例观察到。当 kube-proxy 看到一个新的 Service,它会安装一系列的 iptables 规则,从 VIP 重定向到 per-Service
规则。 该 per-Service
规则连接到 per-Endpoint
规则,该 per-Endpoint
规则会重定向(目标 NAT
)到后端的 Pod。
注意:
假设没有
kube-proxy
,让大家去做这件事情,其实也可以,如果你对iptanles很熟悉的话,去定义一个虚拟ip,然后配置到我们的iptables规则上去,这样是可以达到预期效果的,是没问题的。
2.ipvs
除了 iptables 模式之外,kubernetes 也支持 ipvs 模式,在 ipvs 模式下,kube-proxy watch Kubernetes 服务和端点,调用 netlink
接口相应地创建 IPVS 规则
, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。该控制循环可确保 IPVS 状态与所需状态匹配。访问服务时,IPVS将流量定向到后端 Pod 之一。
IPVS 代理模式基于类似于 iptables 模式的 netfilter 钩子函数,但是使用**哈希表(我们知道哈希表在做查找的时候,它会比其他方式的效率要高很多)**作为基础数据结构,并且在内核空间中工作。
所以与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能;
与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量;
所以对于较大规模的集群会使用 ipvs 模式的 kube-proxy,只需要满足节点上运行 ipvs 的条件,然后我们就可以直接将 kube-proxy 的模式修改为 ipvs,如果不满足运行条件会自动降级为 iptables 模式,现在都推荐使用 ipvs 模式,可以大幅度提高 Service 性能。
IPVS 提供了更多选项(负载策略)来平衡后端 Pod 的流量,默认是 rr
,有如下一些策略:
- rr:round-robin
- lc:least connection (smallest number of open connections)
- dh:destination hashing
- sh:source hashing
- sed:shortest expected delay
- nq:never queue
不过现在只能整体修改策略,可以通过 kube-proxy 中配置 –ipvs-scheduler
参数来实现,暂时不支持特定的 Service 进行配置。
我们也可以实现基于客户端 IP 的会话亲和性(session亲和性),可以将 service.spec.sessionAffinity 的值设置为 "ClientIP"(默认值为 "None")即可,此外还可以通过适当设置 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
来设置最大会话停留时间(默认值为 10800 秒,即 3 小时):
apiVersion:v1kind:Servicespec:sessionAffinity:ClientIP...
这个有些场景下还是很有用的:
[root@master1 ~]#kubectl explain svc.spec……sessionAffinity<string>Supports"ClientIP"and"None".Usedtomaintainsessionaffinity.EnableclientIPbasedsessionaffinity.MustbeClientIPorNone.DefaultstoNone.Moreinfo:https:sessionAffinityConfig<Object>sessionAffinityConfigcontainstheconfigurationsofsessionaffinity.……[root@master1 ~]#kubectl explain svc.spec.sessionAffinityConfig.clientIPKIND:ServiceVERSION:v1RESOURCE:clientIP<Object>:DESCRIPTION:clientIPcontainstheconfigurationsofClientIPbasedsessionaffinity.ClientIPConfigrepresentstheconfigurationsofClientIPbasedsessionaffinity.FIELDS:timeoutSeconds<integer>timeoutSecondsspecifiesthesecondsofClientIPtypesessionstickytime.Thevaluemustbe>0&&<=86400(for1day) ifServiceAffinity=="ClientIP".Defaultvalueis10800(for3hours).
比如你的后端服务是一个websocket或者是一些长链接服务的话,这个时候你可能最好配置下session亲和性。 如果你把这个sessionAffinity给它配置成ClientIP,比如说你现在有10个请求,那么10个请求来源于不同的ip地址的话,假设你第一个请求访问我们后端服务是到达了pod1,那么后面所有的9个请求流量都会到达pod1的,这样的话,就是基于ip的session亲和性。
当然,更复杂的可能是基于header头来做session亲和性,但service不支持这种更复杂的配置。
所以,你要使用cookie的话,我们后面可以使用ingress,比如说有些ingress控制器可以帮我们做这些事情。
亲和性
Service 只支持两种形式的会话亲和性服务:None 和 ClientIP,不支持基于 cookie 的会话亲和性,这是因为 Service 不是在 HTTP 层面上工作的,处理的是 TCP 和 UDP 包,并不关心其中的载荷内容,因为 cookie 是 HTTP 协议的一部分,Service 并不知道它们,所以会话亲和性不能基于 Cookie。
==💘 实战:Service代理模式-kubeadm方式修改ipvs模式-2022.7.21(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:NAMEREADYSTATUSRESTARTSAGEcalico-kube-controllers-6949477b58-hlxp71/1Running1318dcalico-node-c5sl61/1Running3118dcalico-node-l7q5q1/1Running918dcalico-node-sck2q1/1Running818detcd-k8s-master1/1Running918dkube-apiserver-k8s-master1/1Running1018dkube-controller-manager-k8s-master1/1Running1018dkube-proxy-9249w1/1Running1218dkube-proxy-mj7l51/1Running818dkube-proxy-p9bd41/1Running918dkube-scheduler-k8s-master1/1Running1018d[root@k8s-master ~]#
方法1:查看kube-system
这个configmap
[root@master1 ~]#kubectl get cm kube-proxy -nkube-system -oyaml
方法2:看一个kube-proxy
pod的日志
[root@k8s-master ~]#kubectl logs kube-proxy-9249w -n kube-system
从这里可以看出kube-proxy维护的svc的代理模式类型是什么样的?:默认是ipatbles方式的。
kube-proxy是由DaemonSet控制器部署的: 注意:但是这个并没有在/etc/kubernetes/manifests/
目录下:
一、kubeadm方式修改ipvs模式:# kubectl edit configmap kube-proxy -n kube-system...mode:“ipvs“...# kubectl delete pod kube-proxy-btz4p -n kube-system注:1、kube-proxy配置文件以configmap方式存储2、如果让所有节点生效,需要重建所有节点kube-proxypod!!!这个需要注意!!!(那么问题来了:(1)直接修改这个会影响业务吗??--》应该会的吧。。。(2)这个也太繁琐了吧,如果有1000个节点,那么也要执行1000次删除pod操作吗?--》这个可以借助于label进行批量删除的;)
[root@k8s-master ~]#kubectl edit configmap kube-proxy -n kube-system#将mode:““改成mode:“ipvs“[root@k8s-master ~]#
kube-proxy本身没有实现热更新的机制的,因此需要重启下kube-proxy:
实际测试过程: 这里先以一个kube-proxy为例: 先定位下这个kube-peoxy在哪个节点上?
在node1上:
在k8s-master上删除次kube-proxy pod:(一共有3个pod的,都需要进行删除重建操作的!!!)
[root@k8s-master ~]#kubectl delete pod kube-proxy-9249w -n kube-system
all节点都安装下ipvsadm
软件包:
[root@k8s-node1 ~]# yum install -y ipvsadm[root@k8s-node2 ~]# yum install -y ipvsadm[root@k8s-master ~]#yum install -y ipvsadm
node1查看会有很多ipvs规则(node1上刚有更改kube-proxy的代理模式为ipvs):(k8s-node2效果一样)
virtual server和real server:
- 我们现在在node1上访问这个cluster ip,它的流程是怎么样的呢?
流程包流程:客户端->NodePort/ClusterIP(iptables/Ipvs负载均衡规则)->分布在各节点Pod查看负载均衡规则:•iptables模式iptables-save|grep<SERVICE-NAME>•ipvs模式ipvsadm-L-n
cluster ip会绑定定到kube-ipvs0这个虚拟网卡上来的; 这里和iptables不同,iptables是看不到任何实际网卡信息的,走的都iptables规则;
你要访问Nodeport也是走的这个规则:
实验结束.😘
==💘 实战:二进制方式修改ipvs模式-2023.2.11(测试成功)==
二进制方式修改ipvs模式:# vi kube-proxy-config.yml mode:ipvsipvs:scheduler:"rr“# systemctl restart kube-proxy注:配置文件路径根据实际安装目录为准
iptables vs ipvs
Iptables:•灵活,功能强大•规则遍历匹配和更新,呈线性时延IPVS:•工作在内核态,有更好的性能•调度算法丰富:rr(默认是rr),wrr,lc,wlc,iphash...1、iptables代理模式代理网关;nat;iptables功能强大;iptables可以做到防火墙的功能,还可以做到负载均衡器的功能;但,时延性比较大;2、ipvs代理模式:ipvsadm-L-n#-n代表不以名字显示(不加的话,可能会很慢,因为需要域名解析) -L代表以列出来从上往下匹配规则;QA:ipvs的几种模式:NAT,DR,还有个叫什么来着的?QA:换成ipvs后,k8s还是要用到iptables的,只是iptables里面的规则没那么多了;总结:小规模几十台可以使用iptables规则,但大规模(几百台以上)可以选择使用ipvs,效率会更好些;目前ipvs已经很成熟了:国内大厂都在用;
所以说,ipvs的效率要比iptables高,特别是当你service服务达到一定数量级之后的话,ipvs的性能要比iptables高出很多个数量级的。 所以说,如果你的集群node数量非常大,你的service服务也非常大,我们就要考虑使用ipvs了。但是,如果你的k8s集群规模较小,基本上可能小于10个节点,还是使用iptables比较好一些,但是你要使用ipvs,还是没有任何问题的。
之前,看到网上有人对ipvs和iptables 2种代理模式做了性能测试的,iptables在node节点为个位数,或者10几个节点的话,那么使用iptables代理模式效率是更高的。但是,当你超过了这个阈值之后,达到50个节点,100个节点,1000个节点,那么在性能上,ipvs要超过iptables好几个数量级的。
ipvsadm命令
安装ipvsadm
要确保各个节点上已经安装了 ipset 软件包,为了便于查看 ipvs 的代理规则,最好安装一下管理工具ipvsadm:
yuminstallipsetipvsadm-y#all节点安装ipvsadm软件包
ipvsadm命令
查看负载均衡规则:•iptables模式iptables-save|grep<SERVICE-NAME>•ipvs模式ipvsadm-L-n#常用#--list -L|-l list the table#--numeric -n numeric output of addresses and ports
node1查看会有很多ipvs规则(node1上刚有更改kube-proxy的代理模式为ipvs):(k8s-node2效果一样)
virtual server和real server:
我们现在在node1上访问这个cluster ip,它的流程是怎么样的呢?
查看ipvs代理模式包的传输流程:
流程包流程:客户端->NodePort/ClusterIP(iptables/Ipvs负载均衡规则)->分布在各节点Pod查看负载均衡规则:•iptables模式iptables-save|grep<SERVICE-NAME>•ipvs模式ipvsadm-L-n
cluster ip会绑定定到kube-ipvs0这个虚拟网卡上来的; 这里和iptables不同,iptables是看不到任何实际网卡信息的,走的都iptables规则;
你要访问Nodeport也是走的这个规则:
注意:NodePort这个端口号是虚拟出来的
记录时间:2023年11月15日
NodePort这个端口号是虚拟出来的,在node节点上用netstat命令
是找不到的,只能通过ipvsadm
来查看。
在node1上netstat命令
是找不到31438端口的:
[root@node1 ~]#netstat -antlp|grep31438[root@node1 ~]#
通过ipvsadm
是可以看到网络规则的:
[root@node1 ~]#ipvsadm -L -n|grep31438TCP172.29.9.62:31438rrTCP10.244.1.0:31438rrTCP10.244.1.1:31438rr
5、Service常见类型
我们在定义 Service 的时候可以指定一个自己需要的类型的 Service,如果不指定的话默认是 ClusterIP
类型。
我们可以使用的服务类型如下:
1.ClusterIP
集群内部使用
通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的服务类型。
2.NodePort
对外暴露应用
通过每个 Node 节点上的 IP 和**静态端口(NodePort)**暴露服务。**NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。**通过请求 NodeIp:NodePort(注意是k8s集群的每个节点都可以通过这种方式去访问的)
,可以从集群的外部访问一个 NodePort 服务。 访问地址:<任意NodeIP>:<NodePort>
每个NodePort都会随机分配一个端口号,端口范围:30000-32767
注意:service的nodePort的取值范围有默认值:30000-32767,你手动指定的话,也要在这个范围内才可以的,当然不在这个范围内,也是可以的,但就有可能和其它端口冲突。
- 负载均衡器
NodePort:会在每台Node上监听端口接收用户流量,在实际情况下,对用户暴露的只会有一个IP和端口,那这么多台Node该使哪台让用户访问呢?这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。
- kubernetes主服务
这里有个kubernetes主服务
概念,也就是deafult命名空间下的kubernetes
service:
==💘 实战:NodePort测试-2023.2.11(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:apiVersion:apps/v1kind:Deploymentmetadata:name:nginxspec:replicas:3selector:matchLabels:app:web#1template:metadata:labels:app:web#2spec:containers:- image:nginxname:nginxports:- protocol:TCPcontainerPort:80#容器内暴露的端口,注意:这里的 containerPort:80只是一个标识,真正起作用的还是容器里服务的端口号 name:nginx-http---apiVersion:v1kind:Servicemetadata:name:myservicespec:selector:app:web#3type:NodePort# 服务类型,默认是ClusterIPports:- protocol:TCPport:8080#如果没有配置targetPort,则这里的port 要和容器内暴露的端口保持一致targetPort:nginx-http#—定要和容器内你的这个应用暴露的端口保持一致name:myapp-http
- 部署并测试
[root@master1 ~]#kubectl apply -f service-nodeport-demo.yamldeployment.apps/nginxcreatedservice/myservicecreated[root@master1 ~]#kubectl get poNAMEREADYSTATUSRESTARTSAGEnginx-757d547965-7rhbp1/1Running055snginx-757d547965-t6h6m1/1Running025snginx-757d547965-zkxs91/1Running025s[root@master1 ~]#kubectl get svcNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEkubernetesClusterIP10.96.0.1<none>443/TCP68dmyserviceNodePort10.103.191.211<none>8080:32302/TCP6m37s#测试,符合预期[root@master1 ~]#curl 172.29.9.62:32302<!DOCTYPEhtml><html><head><title>Welcome to nginx!</title><style>html{color-scheme:lightdark;}body{width:35em;margin:0auto;font-family:Tahoma,Verdana,Arial,sans-serif;}</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page,the nginx web server is successfully installed andworking.Furtherconfigurationisrequired.</p><p>For online documentation and support please refer to<a href="http:Commercialsupportisavailableat<a href="http:<p><em>Thank you forusing nginx.</em></p></body></html>
我们可以看到 myservice 的 TYPE 类型已经变成了 NodePort,后面的 PORT(S) 部分也多了一个 32302的映射端口。
测试结束。😘
3.LoadBalancer
对外暴露应用,适用公有云
**使用云提供商的负载局衡器,可以向外部暴露服务。**外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。(注意:LoadBalancer也会自动生成NodePort,而NodePort也会自动生成ClusterIp的。)
LoadBalancer:与NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台(例如阿里云、腾讯云、AWS等)上的负载均衡器,将每个Node([NodeIP]:[NodePort]
)作为后端添加进去。
🚩 注意
[root@master1 ingress-nginx]#kubectl get pods -n ingress-nginx -owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESingress-nginx-admission-create--1-5h6rr0/1Completed020m10.244.1.25node1<none><none>ingress-nginx-admission-patch--1-jdn2k0/1Completed020m10.244.2.18node2<none><none>ingress-nginx-controller-46kbb1/1Running07m58s10.244.2.20node2<none><none>ingress-nginx-controller-xtbn41/1Running010m10.244.0.2master1<none><none>ingress-nginx-controller-zxffk1/1Running08m20s10.244.1.27node1<none><none>[root@master1 ingress-nginx]#kubectl get svc -n ingress-nginxNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEingress-nginx-controllerLoadBalancer10.108.58.24680:32439/TCP,443:31347/TCP20mingress-nginx-controller-admissionClusterIP10.101.184.28<none>443/TCP20m
另外一个 ingress-nginx-controller 就是ingress 控制器对外暴露的服务,我们可以看到默认是一个 LoadBalancer 类型的 Service,我们知道该类型是用于云服务商的,我们这里在本地环境,暂时不能使用,但是可以通过他的 NodePort 来对外暴露,后面我们会提供在本地测试环境提供 LoadBalancer 的方式。
4.ExternalName
ExternalName:通过返回 CNAME
和它的值,可以将服务映射到 externalName
字段的内容(例如, foo.bar.example.com)。
[root@master1 ~]# kubectl explain svc.spec"ExternalName"aliasesthisservicetothespecifiedexternalName.Several(各自的,几个的) otherfieldsdonotapplytoExternalNameservices.Moreinfo:https:externalName<string>externalNameistheexternalreferencethatdiscoverymechanismswillreturnasanaliasforthisservice(e.g. aDNSCNAMErecord). No proxyingwillbeinvolved(涉及).MustbealowercaseRFC-1123hostname(https:"ExternalName".
ExternalName 是 Service 的特例,它没有 selector
,也没有定义任何的端口和 Endpoint。对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
kind:ServiceapiVersion:v1metadata:name:my-servicenamespace:prodspec:type:ExternalNameexternalName:my.database.example.com
当访问地址 my-service.prod.svc.cluster.local
(后面服务发现的时候我们会再深入讲解)时,集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME
记录。访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。如果后续决定要将数据库迁移到 Kubernetes 集群中,可以启动对应的 Pod,增加合适的 Selector 或 Endpoint,修改 Service 的 type,完全不需要修改调用的代码,这样就完全解耦了。
注意下如下讲解内容:
以后在访问我们的service的时候,其实就被重定向到了下面这个mysql.rds.beijing.aliyuncs.com
这个域名了。那为什么要做这样一个事情呢?
这种类型更多的可能是用于我们服务迁移的这样一个场景,比如最开始我们的服务是部署在我们的rds
上的,现在我们就把服务迁移到了k8s上来了,但是例如我们这个mysql服务不会立刻把它部署到我们的k8s上去,那么这样的话,如果我们的程序还是写上之前的mysql.rds.beijing.aliyuncs.com
,那以后我把它迁移到了k8s过后,我还要去修改我的程序,如果能够把它统一当成k8s里面的一个服务的话,那是不是就比较好了,所以这个时候,我们就可以把这个mysql.rds.beijing.aliyuncs.com
去做一个externalname,去做一个CNAME的映射。
所以,这种类型更多的是在我们服务迁移的时候使用的。
服务迁移
(过渡期)
==💘 实战:ExternalName类型自定义Endpoints测试-2023.2.12(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:kind:Servicemetadata:name:etcd-k8snamespace:kube-systemlabels:k8s-app:etcdspec:type:ClusterIPclusterIP:Noneports:- name:portport:2379---apiVersion:v1kind:Endpointsmetadata:name:etcd-k8s# 名称必须和 Service 一致namespace:kube-systemlabels:k8s-app:etcdsubsets:- addresses:- ip:10.151.30.57# Service 将连接重定向到 endpointports:- name:portport:2379# endpoint 的目标端口
上面这个服务就是将外部的 etcd 服务引入到 Kubernetes 集群中来。
- 自定义Endpoints
我们可以看到,当前集群只有一个etcd.
假设我们再k8s集群外部有一个etcd集群(3个节点),这个时候,我想在k8s集群内部来使用这个集群,该怎么做呢?最好的方式就是把这个外部etcd集群给它引入到k8s集群里来,怎么引入呢?-->"自定义Endpoints引入进来",因为我们刚才说过,如果创建service的话,默认就会创建一个同名的Endpoints.
这边来创建下资源清单文件:
#etcd-svc.yamlapiVersion:v1kind:Servicemetadata:name:etcd-svcspec:type:ClusterIPclusterIP:None#一定没有clusterIP,要设置成None 没有定义selectorports:- name:clientport:2379---apiVersion:v1kind:Endpointsmetadata:name:etcd-svcsubsets:#配置subsets- addresses:#Service 将连接重定向到Endpoints列表 - ip:10.151.30.11- ip:10.151.30.20- ip:10.151.30.23ports:- name:clientport:2379
- 部署并查看
[root@master1 ~]#kubectl apply -f etcd.svc.yaml service/etcd-svcunchangedendpoints/etcd-svccreated[root@master1 ~]#kubectl get svc etcd-svcNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEetcd-svcClusterIPNone<none>2379/TCP60s[root@master1 ~]#kubectl get ep etcd-svcNAMEENDPOINTSAGEetcd-svc10.151.30.11:2379,10.151.30.20:2379,10.151.30.23:237946s[root@master1 ~]#kubectl describe svc etcd-svcName:etcd-svcNamespace:defaultLabels:<none>Annotations:<none>Selector:<none>Type:ClusterIPIPFamilyPolicy:RequireDualStackIPFamilies:IPv4,IPv6IP:NoneIPs:NonePort:client2379/TCPTargetPort:2379/TCPEndpoints:10.151.30.11:2379,10.151.30.20:2379,10.151.30.23:2379SessionAffinity:NoneEvents:<none>[root@master1 ~]#
注意:这种方式和我们之前的ClusterIP类型类似,唯一不同的就是这种类型没有ClusterIp,那么这种情况下,我们该如何去访问我们的etcd-svc呢?
这个的话,就要做一下我们的service的自动发现了,下节课和大家讲解一下。
因为我们的ClusterIP也是不稳定的。
假如说我们的svc-demo被重建了,那么这个CLusterIP也会变化的。所以它也不是一个稳定的方式。
所以,通过ClusterIp去访问我们的服务也是不靠谱的,这个下节课我们来讲一下我们服务发现的知识。
实验结束。😘
5.externalIPs
Service 的属性中还有一个 externalIPs 的属性,从 Kubernetes 官网文档可以看到该属性的相关描述:
如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。通过外部 IP(作为目的 IP 地址)进入到集群,传到 Service 的端口上的流量,将会被路由到 Service 的Endpoint 上,externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
这里最重要的一点就是确保使用哪个 IP 来访问 Kubernetes 集群,使用外部 IP Service 类型,我们可以将Service 绑定到连接集群的 IP。
6、Endpoints 与 Endpointslices
1.Endpoints
我们已经知道在 Service 创建时,Kubernetes 会根据 Service 关联一个 Endpoints 资源,若 Service 没有定义 selector 字段,将不会自动创建 Endpoints。Endpoints 是 Kubernetes 中的一个资源对象,存储在 etcd中,用来记录一个 Service 对应一组 Pod 的访问地址,一个 Service 只有一个 Endpoints 资源,Endpoints 资源会去观测 Pod 集合,只要服务中的某个 Pod 发生变更,Endpoints 就会进行同步更新。
==💘 实战:Endpoints测试-2023.2.12(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:apiVersion:apps/v1kind:Deploymentmetadata:name:httpbinspec:replicas:3selector:matchLabels:app:httpbintemplate:metadata:labels:app:httpbinspec:containers:- name:httpbinimage:kennethreitz/httpbin:latestimagePullPolicy:IfNotPresentports:- containerPort:80---apiVersion:v1kind:Servicemetadata:name:httpbinspec:selector:app:httpbinports:- name:httpport:80protocol:TCPtargetPort:80type:ClusterIP
- 在该应用中我们定义了 3 个副本,然后创建了一个 Service 对象来关联这些 Pod,直接应用该资源清单即可:
[root@master1 ~]#kubectl apply -f httpbin-deploy.yamldeployment.apps/httpbincreatedservice/httpbincreated[root@master1 ~]# kubectl get pods -l app=httpbin-owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATEShttpbin-549c696b8d-2v67s1/1Running08m53s10.244.1.5node1<none><none>httpbin-549c696b8d-jjr271/1Running08m53s10.244.2.5node2<none><none>httpbin-549c696b8d-lljkw1/1Running08m53s10.244.2.4node2<none><none>[root@master1 ~]# kubectl get pods -l app=httpbin-owideNAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATEShttpbin-549c696b8d-2v67s1/1Running08m53s10.244.1.5node1<none><none>httpbin-549c696b8d-jjr271/1Running08m53s10.244.2.5node2<none><none>httpbin-549c696b8d-lljkw1/1Running08m53s10.244.2.4node2<none><none>[root@master1 ~]# kubectl get svc httpbinNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEhttpbinClusterIP10.103.29.35<none>80/TCP9m14s[root@master1 ~]# kubectl get ep httpbinNAMEENDPOINTSAGEhttpbin10.244.1.5:80,10.244.2.4:80,10.244.2.5:809m24s[root@master1 ~]# kubectl get ep httpbin -oyamlapiVersion:v1kind:Endpointsmetadata:annotations:endpoints.kubernetes.io/last-change-trigger-time:"2023-02-12T03:04:54Z"creationTimestamp:"2023-02-12T03:04:00Z"name:httpbinnamespace:defaultresourceVersion:"8431"uid:ecce8bfc-e1dc-4a11-bd76-46ed766d1dafsubsets:-addresses:-ip:10.244.1.5nodeName:node1targetRef:kind:Podname:httpbin-549c696b8d-2v67snamespace:defaultuid:1fd41301-ecbe-4e12-ba73-80430e2842dd-ip:10.244.2.4nodeName:node2targetRef:kind:Podname:httpbin-549c696b8d-lljkwnamespace:defaultuid:47d28332-6763-42d8-a5c2-8729abfab7cb-ip:10.244.2.5nodeName:node2targetRef:kind:Podname:httpbin-549c696b8d-jjr27namespace:defaultuid:b80a0452-631d-49f3-a17c-acf4111a5b91ports:-name:httpport:80protocol:TCP[root@master1 ~]#
由于我们这里创建了一个 Service 对象,所以也会自动创建一个对应的 Endpoints 对象,只有当 Pod 正常运行后才会被包含到 Endpoints 对象中去,所以往往如果是线上应用我们都是强烈推荐为 强烈推荐为 Pod 配置上 readiness probe的,当应用还未就绪的时候就不会进入 Endpoints,也就不会对外提供服务了,当应用下线后就从该对象中摘掉。
从上述示例可以看到,Endpoints 中的所有网络端点,分别对应了每个 Pod 的 IP 地址,也就是上面对象中的subsets 里面的数据。
测试结束。😘
2.Endpoints 的不足之处
但实际上 Endpoints 也有它的一些不足之处,比如:
Kubernetes 限制单个 Endpoints 对象中可以容纳的端点数量。当一个服务有超过 1000 个后备端点时,Kubernetes 会截断Endpoints 对象中的数据,这种情况下,Kubernetes 选择最多1000 个可能的后端端点来存储到 Endpoints 对象中,并在 Endpoints 中配置上
endpoints.kubernetes.io/over-capacity:truncated
注解。如果后端 Pod 的数量低于 1000,控制平面会移除该注解。一个 Service 只有一个 Endpoints 资源,这意味着它需要为支持相应服务的每个 Pod 存储 IP 等网络信息。这导致 Endpoints 资源变的十分巨大,其中一个端点发生了变更,将会导致整个 Endpoints 资源更新。当业务需要进行频繁端点更新时,一个巨大的 API 资源被相互传递,而这会影响到 Kubernetes 组件的性能,并且会产生大量的网络流量和额外的处理。
所以当你的应用规模达到了上千规模的话,我们就不能使用原有的这种方案了,一个新的对象 Endpointslices 就出现了,Endpointslices 为 Endpoints 提供了一种可扩缩和可拓展的替代方案,缓解处理大量网络端点带来的性能问题,还能为一些诸如拓扑路由的额外功能提供一个可扩展的平台,该特性在 Kubernetes v1.21+ 的版本中已提供支持。
默认情况下,控制面创建和管理的 EndpointSlice 将包含不超过 100 个端点,但是我们可以使用 kubecontroller-manager 的 --max-endpoints-per-slice
标志设置此值,其最大值为 1000。
3.为什么需要 Endpointslices
为了说明这些问题的严重程度,这里举一个简单的例子。
假设我们有一个 2000 个 Pod 副本的服务,它最终生成的Endpoints 资源对象会很大(比如 1.5MB (etcd 具有最大请求大小限制1.5MB),还会截断成 1000),在生产环境中,如果该服务发生滚动更新或节点迁移,那么 Endpoints 资源将会频繁变更,当该列表中的某个网络端点发生了变化,那么就要将完整的 Endpoint 资源分发给集群中的每个节点。如果我们在一个具有 3000 个节点的大型集群中,这会是个很大的问题,每次更新将跨集群发送 4.5GB 的数据(1.5MB*3000 ,即 Endpoint 大小*节点个数),并且每次端点更新都要发送这么多数据。想象一下,如果进行一次滚动更新,共有 2000 个 Pod 全部被替换,那么传输的数据量将会是TB 级数据。这不进对集群内的网络带宽浪费巨大,而对 Master 的冲击非常大,会影响 Kubernetes 整体的性能。
如果使用了 Endpointslices,假设一个服务后端有 2000 个 Pod,我们可以让每个 Endpointslices 存储 100 个端点,最终将获得 20 个 Endpointslices。添加或删除 Pod 时,只需要更新其中 1 个 Endpointslice 资源即可,这样操作后,可扩展性和网络可伸缩有了很大的提升。
比起在流量高峰时,服务为了承载流量,扩容出大量的 Pod,Endpoints 资源会被频繁更新,两个使用场景的差异就变得非常明显。更重要的是,既然服务的所有 Pod IP 都不需要存储在单个资源中,那么我们也就不必担心 etcd 中存储的对象的大小限制。
所以我们可以了解到 Endpoints 和 Endpointslice 两种资源的不同之处了。
Endpoints 适用场景:
有弹性伸缩需求,Pod 数量较少,传递资源不会造成大量网络流量和额外处理。
无弹性伸缩需求,Pod 数量不会太多。哪怕 Pod 数量是固定,但是总是要滚动更新或者出现故障的。
Endpointslice 适用场景:
有弹性需求,且 Pod 数量较多(几百上千)。
Pod 数量很多(几百上千),因为 Endpoints 网络端点最大数量限制为 1000,所以超过 1000 的 Pod 必须得用 Endpointslice。
4.EndpointSlice 使用
==💘 实战:EndpointSlice 使用-2023.2.12(测试成功)==
- 实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:--max-endpoints-per-slice=5
- 比如我们现在创建如下的资源对象:
# httpbin-deploy-slice.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:httpbinspec:replicas:17selector:matchLabels:app:httpbintemplate:metadata:labels:app:httpbinspec:containers:- name:httpbinimage:kennethreitz/httpbin:latestimagePullPolicy:IfNotPresentports:- containerPort:80---apiVersion:v1kind:Servicemetadata:name:httpbinspec:selector:app:httpbinports:- name:httpport:80protocol:TCPtargetPort:80type:ClusterIP
- 直接应用即可
[root@master1 ~]# kubectl apply -f httpbin-deploy-slice.yamldeployment.apps/httpbincreatedservice/httpbincreated
- 当 Pod 和 Service 创建后便会自动创建 EndpointSlices 对象了:
[root@master1 ~]#kubectl get svcNAMETYPECLUSTER-IPEXTERNAL-IPPORT(S) AGEhttpbinClusterIP10.111.73.187<none>80/TCP13skubernetesClusterIP10.96.0.1<none>443/TCP69dmyserviceNodePort10.103.191.211<none>8080:32302/TCP16h[root@master1 ~]#kubectl get endpointsliceNAMEADDRESSTYPEPORTSENDPOINTSAGEhttpbin-k9hv7IPv48010.244.2.20,10.244.2.2223shttpbin-ns5hxIPv48010.244.2.16,10.244.1.19,10.244.2.14+2more...25shttpbin-t5r2sIPv48010.244.1.20,10.244.2.17,10.244.1.22+2more...24shttpbin-wqklkIPv48010.244.1.16,10.244.1.17,10.244.1.15+2more...30skubernetesIPv46443172.29.9.6169dmyservice-jkhgxIPv4<unset><unset>16h#注意:这里也是有ep对象的。[root@master1 ~]#kubectl get epNAMEENDPOINTSAGEhttpbin10.244.1.15:80,10.244.1.16:80,10.244.1.17:80+14more...9m19skubernetes172.29.9.61:644369dmyservice<none>16h
由于我们这里配置的每个 EndpointSlice 最多有 5 个 Endpoint,一共 17 个副本,所以这里自动创建了 4 个EndpointSlices 对象,当然现在 kube-proxy 组件会 Watch 所有的这个 4 个对象。
但是当我们更新一个 Pod 的时候只有包含该 Pod 的 EndpointSlice 对象变更,该对象中包含的 Endpoints 列表非常少,这就大大提升了性能。
- 我们可以查看任意一个 EndpointSlice 对象,如下所示:
[root@master1 ~]#kubectl get endpointslice httpbin-k9hv7 -oyamladdressType:IPv4apiVersion:discovery.k8s.io/v1endpoints:-addresses:-10.244.2.20conditions:ready:trueserving:trueterminating:falsenodeName:node2targetRef:kind:Podname:httpbin-549c696b8d-vrmlrnamespace:defaultuid:808bff2e-011b-4a81-8ada-7a4ba2821bdb-addresses:-10.244.2.22conditions:ready:trueserving:trueterminating:falsenodeName:node2targetRef:kind:Podname:httpbin-549c696b8d-vfsbvnamespace:defaultuid:cace1a79-2d0b-44d2-940e-673bfe0a8057kind:EndpointSlicemetadata:annotations:endpoints.kubernetes.io/last-change-trigger-time:"2023-02-12T06:15:32Z"creationTimestamp:"2023-02-12T06:15:35Z"generateName:httpbin-generation:2labels:endpointslice.kubernetes.io/managed-by:endpointslice-controller.k8s.iokubernetes.io/service-name:httpbinname:httpbin-k9hv7namespace:defaultownerReferences:-apiVersion:v1blockOwnerDeletion:truecontroller:truekind:Servicename:httpbinuid:fcd0bbc9-215d-4d3b-bcb0-686ee4d6388aresourceVersion:"25120"uid:e1ad3c60-7839-487e-8c5f-f7c7cddbaecbports:-name:httpport:80protocol:TCP[root@master1 ~]#
从上面可以看到 EndpointSlice 对象中通过 endpoints 属性来保存 Endpoint 数据,每个 Endpoint 中 包含Pod IP、节点名以及关联的 Pod 对象信息,其中还包括一个 conditions 属性。
-addresses:-10.244.2.20conditions:#端点的状态ready:trueserving:trueterminating:falsenodeName:node2targetRef:kind:Podname:httpbin-549c696b8d-vrmlrnamespace:defaultuid:808bff2e-011b-4a81-8ada-7a4ba2821bdb
EndpointSlice 存储了可能对使用者有用的、有关端点的状态,分别是 ready、 serving 和 terminating 。
Ready(就绪):ready 是映射 Pod 的 Ready 状况的。对于处于运行中的 Pod,它的 Ready 状况被设置为True,应该将此 EndpointSlice 状况也设置为 true。出于兼容性原因,当 Pod 处于终止过程中,ready 永远不会为 true。
Serving(服务中):serving 状况与 ready 状况相同,不同之处在于它不考虑终止状态。如果 EndpointSliceAPI 的使用者关心 Pod 终止时的就绪情况,就应检查此状况。
Terminating(终止中):terminating 是表示端点是否处于终止中的状况,对于 Pod 来说,这是设置了删除时间戳的 Pod。
此外 EndpointSlice 中的每个端点都可以包含一定的拓扑信息,拓扑信息包括端点的位置,对应节点、可用区的信息,这些信息体现为 EndpointSlices 的如下端点字段:
- nodeName - 端点所在的 Node 名称
- zone - 端点所处的可用区。
为了确保多个实体可以管理 EndpointSlice 而且不会相互产生干扰, Kubernetes 定义了标签endpointslice.kubernetes.io/managed-by
,用来标明哪个实体在管理某个 EndpointSlice。 端点切片控制器会在自己所管理的所有 EndpointSlice 上将该标签值设置为 endpointslice-controller.k8s.io
,管理EndpointSlice 的其他对象也应该为此标签设置一个唯一值。
此外还有一个地址类型 AddressType:IPv4、IPv6、FQDN(全限定域名)。
关于 Service 的使用还有很多其他特性,比如 LoadBalancer,我们将在后面的课程中慢慢接触到。
测试结束。😘
FAQ
label和annotations的区别
# volume-pod.yamlapiVersion:v1kind:Podmetadata:name:volume-podnamespace:kube-systemlabels:k8s-app:test-volumenode-env:testannotations:own:youdianzhishibuild:test
1.label更多用于开发 人员和我们运维人员,对使用k8s人员来说的,用于来标记的;用于资源对象匹配和用户筛选用的; 2.annotations更多是用于其它应用程序来读取资源对象时来使用的;annotations就是注解;
注意
service,一般是没有什么情况,要去删除它的,因此这个ip是可以长期占有的;service只认标签,其他一概不认;service就是一个声明,没有什么重启的概念clusterIP是对应svc的,一般不会变啊,除非你删除了svc然后重建;通过监听端口来引流的;注意:公有云的话,一般推荐使用`LoadBalancer`;自建k8s的话,推荐使用`NodePort`;Pod对外暴露:集群之内(pod、node)的其他应用,集群之外的其他应用或者用户;#注意:CLUSTER-IPCLUSTER-IP可以用`kubectl get svc`输出的;PodIP可以用`kubectl get pod -o wide`输出;(kubectlgetep也可以输出)ClusterIp是k8s集群之内的网络;Service三种常用类型都是拥有这个`cluster ip`的:service默认都会创建一个clusterip;VIP:集群ip,虚拟ip;=>vip,clusterip是一个虚拟地址存在的;clusterip可以手动指定,但是没必要;这个Clusterip在集群内部,任何POd,任何node都是可以访问到的;那么问题来了:node应该都是可以直接访问任何ns下的svc的;但pod里可以访问任何ns下的svc吗?;--是可以的;
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 微信二维码 x2675263825 (舍得), qq:2675263825。
🍀 微信公众号 《云原生架构师实战》
🍀 语雀