Skip to content

3.Pod与Service的关系

  • Service通过标签关联一组Pod
  • Service使用iptables或者ipvs为一组Pod提供负载均衡能力

  • 注意:svc和项目是一一对应的
bash
每个svc和每个业务项目都是一一对应的;每部署一个deployment,就需要创建一个svc;而deployment就是运行我们项目的地方;

  • 注意:service->deployment->pod
bash
在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 自己来进行管理和分配地址。

image-20230211155128918

3、定义 Service

定义 Service 的方式和我们前面定义的各种资源对象的方式类型,例如,假定我们有一组 Pod 服务,它们对外暴露了 8080 端口,同时都被打上了 app=myapp 这样的标签,那么我们就可以像下面这样来定义一个 Service 对象:

yaml
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:

yaml
#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,这种方式会提供更大的灵活性。

yaml
#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 协议。

image-20230211184311441

==💘 实战:定义与创建Service-2023.2.11(测试成功)==

image-20230211164553876

  • 实验环境
bash
实验环境: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
  • 测试

下面我们来部署测试下效果,先部署下:

bash
[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看下效果:

bash
#访问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(测试成功)==

image-20230211184037022

多端口Service定义:对于某些服务,需要公开多个端口,Service也需要配置多个端口定义,通过端口名称区分。

  • 实验环境
bash
实验环境: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
  • 部署并查看
bash
[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 这种模式来代理。

image-20230211190210557

我们来大概看下当前k8s集群kube-proxy组件的情况:

现在版本默认模式是ipvs;v1.22,已经默认使用ipvs了;

bash
[root@master1 ~]#kubectl get po -A -owide

bash
[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 小时):

yaml
apiVersion:v1kind:Servicespec:sessionAffinity:ClientIP...

这个有些场景下还是很有用的:

bash
[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。

image-20230211185810036

==💘 实战:Service代理模式-kubeadm方式修改ipvs模式-2022.7.21(测试成功)==

image-20230912071820193

  • 实验环境
bash
实验环境: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

bash
[root@master1 ~]#kubectl get cm kube-proxy -nkube-system -oyaml

方法2:看一个kube-proxypod的日志

[root@k8s-master ~]#kubectl logs kube-proxy-9249w -n kube-system

从这里可以看出kube-proxy维护的svc的代理模式类型是什么样的?:默认是ipatbles方式的。

kube-proxy是由DaemonSet控制器部署的: 注意:但是这个并没有在/etc/kubernetes/manifests/目录下:

bash
一、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进行批量删除的;)
yaml
[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的,都需要进行删除重建操作的!!!

bash
[root@k8s-master ~]#kubectl delete pod kube-proxy-9249w -n kube-system

font>

all节点都安装下ipvsadm软件包:

bash
[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,它的流程是怎么样的呢?

bash
流程包流程:客户端->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(测试成功)==

bash
二进制方式修改ipvs模式:# vi kube-proxy-config.yml mode:ipvsipvs:scheduler:"rr“# systemctl restart kube-proxy注:配置文件路径根据实际安装目录为准

iptables vs ipvs

bash
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:

bash
yuminstallipsetipvsadm-y#all节点安装ipvsadm软件包

ipvsadm命令

bash
查看负载均衡规则: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代理模式包的传输流程:

bash
流程包流程:客户端->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来查看。

image-20231115073513879

在node1上netstat命令是找不到31438端口的:

bash
[root@node1 ~]#netstat -antlp|grep31438[root@node1 ~]#

通过ipvsadm是可以看到网络规则的:

bash
[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该使哪台让用户访问呢?这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了

image-20230211214244531

  • kubernetes主服务

这里有个kubernetes主服务概念,也就是deafult命名空间下的kubernetesservice:

==💘 实战:NodePort测试-2023.2.11(测试成功)==

image-20230211220935953

  • 实验环境
bash
实验环境: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
  • 部署并测试
bash
[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])作为后端添加进去。

image-20230211214458297

🚩 注意

bash
[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)。

bash
[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。对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

yaml
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的映射。

所以,这种类型更多的是在我们服务迁移的时候使用的。

服务迁移(过渡期)

image-20230211212027354

==💘 实战:ExternalName类型自定义Endpoints测试-2023.2.12(测试成功)==

image-20230212091641950

  • 实验环境
bash
实验环境: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.

这边来创建下资源清单文件:

yaml
#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
  • 部署并查看
bash
[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。

参考文档:https:externalIPsisalistofIPaddressesforwhichnodesintheclusterwillalsoaccepttrafficforthisservice.TheseIPsarenotmanagedbyKubernetes.TheuserisresponsibleforensuringthattrafficarrivesatanodewiththisIP.Acommonexampleisexternalload-balancersthatarenotpartoftheKubernetessystem.

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(测试成功)==

image-20230212111610532

  • 实验环境
bash
实验环境: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,直接应用该资源清单即可:
bash
[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+ 的版本中已提供支持。

image-20230212135850966

默认情况下,控制面创建和管理的 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 整体的性能。

image-20230212140157292

image-20230212095352273

如果使用了 Endpointslices,假设一个服务后端有 2000 个 Pod,我们可以让每个 Endpointslices 存储 100 个端点,最终将获得 20 个 Endpointslices。添加或删除 Pod 时,只需要更新其中 1 个 Endpointslice 资源即可,这样操作后,可扩展性和网络可伸缩有了很大的提升。

比起在流量高峰时,服务为了承载流量,扩容出大量的 Pod,Endpoints 资源会被频繁更新,两个使用场景的差异就变得非常明显。更重要的是,既然服务的所有 Pod IP 都不需要存储在单个资源中,那么我们也就不必担心 etcd 中存储的对象的大小限制。

image-20230212095711856

所以我们可以了解到 Endpoints 和 Endpointslice 两种资源的不同之处了。

  • Endpoints 适用场景

    • 有弹性伸缩需求,Pod 数量较少,传递资源不会造成大量网络流量和额外处理。

    • 无弹性伸缩需求,Pod 数量不会太多。哪怕 Pod 数量是固定,但是总是要滚动更新或者出现故障的。

  • Endpointslice 适用场景:

    • 有弹性需求,且 Pod 数量较多(几百上千)。

    • Pod 数量很多(几百上千),因为 Endpoints 网络端点最大数量限制为 1000,所以超过 1000 的 Pod 必须得用 Endpointslice。

4.EndpointSlice 使用

==💘 实战:EndpointSlice 使用-2023.2.12(测试成功)==

image-20230212142709737

  • 实验环境
bash
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.25.4containerd:--max-endpoints-per-slice=5

image-20230212141431782

  • 比如我们现在创建如下的资源对象:
yaml
# 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
  • 直接应用即可
bash
[root@master1 ~]# kubectl apply -f httpbin-deploy-slice.yamldeployment.apps/httpbincreatedservice/httpbincreated
  • 当 Pod 和 Service 创建后便会自动创建 EndpointSlices 对象了:
bash
[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 个对象。

image-20230212141708427

但是当我们更新一个 Pod 的时候只有包含该 Pod 的 EndpointSlice 对象变更,该对象中包含的 Endpoints 列表非常少,这就大大提升了性能。

  • 我们可以查看任意一个 EndpointSlice 对象,如下所示:
bash
[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 属性。

bash
-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的区别

yaml
# 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就是注解;

注意

bash
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。

image-20230107215114763

🍀 微信公众号 《云原生架构师实战》

image-20230107215126971

🍀 语雀

https:

版权:此文章版权归 One 所有,如有转载,请注明出处!

链接:可点击右上角分享此页面复制文章链接

上次更新时间:

最近更新