新钛云服已累计为您分享771篇技术干货


在Kubernetes中,创建和删除Pod是最常见的任务之一。
当你执行滚动更新、扩展部署、发布新版本、执行作业和定时作业等操作时,都会创建Pod。
但是,在Pod被驱逐后,例如将节点标记为不可调度时,Pod也会被删除并重新创建。
如果这些Pod的性质是如此短暂,那么当一个Pod正在响应请求时,如果被告知关闭,会发生什么?在关闭之前,请求是否会完成?那么后续的请求呢?是否会被重定向到其他地方?
在讨论Pod被删除时会发生什么之前,有必要谈谈当Pod被创建时会发生什么。
假设你想在集群中创建以下Pod:
pod.yaml
apiVersion: v1kind: Podmetadata:name: my-podspec:containers:- name: webimage: nginxports:- name: webcontainerPort: 80
$ kubectl apply -f pod.yaml
在数据库中保存集群的状态
Pod的定义被API接收并进行检查,随后存储在数据库(etcd)中。
Pod也被添加到调度器的队列中。
调度器执行以下操作:
检查Pod的定义。
收集关于工作负载的详细信息,例如CPU和内存请求。
通过筛选器和判定的过程决定最适合运行该Pod的节点。
在此过程结束时:
Pod在etcd中被标记为已调度。
Pod被分配给一个节点。
Pod的状态被存储在etcd中。
然而,此时Pod仍然不存在。
当你使用
kubectl apply -f
命令提交一个Pod的YAML文件时,该YAML文件会被发送到Kubernetes API。
API将Pod保存在数据库(etcd)中。

3. 调度器为该Pod分配了最适合的节点,Pod的状态变为Pending。此时,Pod只存在于etcd中。

在控制平面中发生了前述任务,并且状态存储在数据库中。
**那么是谁在你的节点上创建Pod呢?
Kubelet-Kubernetes代理
容器运行时接口(CRI):负责为Pod创建容器。 容器网络接口(CNI):负责将容器连接到集群网络并分配IP地址。 容器存储接口(CSI):负责在容器中挂载卷。
$ docker run -d <my-container-image>
为Pod生成有效的IP地址。 将容器连接到网络的其他部分。





Pods和服务
选择器(selector):用于指定接收流量的Pod。 目标端口(targetPort):Pod用于接收流量的端口。
apiVersion: v1kind: Servicemetadata:name: my-servicespec:ports:- port: 80targetPort: 3000selector:name: app
IP address + port = endpoint---------------------------------10.0.0.3 + 3000 = 10.0.0.3:3000
$ kubectl get services,endpointsNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)service/my-service-1 ClusterIP 10.105.17.65 <none> 80/TCPservice/my-service-2 ClusterIP 10.96.0.1 <none> 443/TCPNAME ENDPOINTSendpoints/my-service-1 172.17.0.6:80,172.17.0.7:80endpoints/my-service-2 192.168.99.100:8443
创建一个Pod。 删除一个Pod。 在Pod上修改标签。
$ kubectl get services,endpointsNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)service/my-service-1 ClusterIP 10.105.17.65 <none> 80/TCPservice/my-service-2 ClusterIP 10.96.0.1 <none> 443/TCPNAME ENDPOINTSendpoints/my-service-1 172.17.0.6:80,172.17.0.7:80endpoints/my-service-2 192.168.99.100:8443









在Kubernetes中使用端点
端点在Kubernetes中被多个组件使用。
让我们考虑一个由三个节点组成的集群,其中有两个Pod,并且没有服务。Pod的状态被存储在etcd中。






apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: my-ingressspec:rules:- http:paths:- backend:service:name: my-serviceport:number: 80path:pathType: Prefix
在这张图片中,有一个带有两个副本的Ingress控制器和一个Service的部署(Deployment)。

2. 如果你想通过Ingress将外部流量路由到Pods,你应该创建一个Ingress配置文件(一个YAML文件)。

kubectl apply -f ingress.yaml命令,Ingress控制器就会从控制平面中获取配置文件。

serviceName属性,用于描述应该使用哪个Service。






Pod被存储在etcd中。 调度器分配一个节点,并将该节点写入etcd。 kubelet收到新的已调度Pod的通知。 kubelet将创建容器的任务委托给容器运行时接口(CRI)。 kubelet将容器连接到容器网络接口(CNI)的任务委托给它。 kubelet将容器中的挂载卷的任务委托给容器存储接口(CSI)。 容器网络接口分配一个IP地址。 kubelet将IP地址报告给控制平面。 IP地址被存储在etcd中。
kubelet等待成功的就绪探针(Readiness probe)。 所有相关的端点(对象)都会收到变更的通知。 端点将新的端点(IP地址+端口对)添加到它们的列表中。 Kube-proxy收到端点变更的通知。Kube-proxy在每个节点上更新iptables规则。 Ingress控制器收到端点变更的通知。控制器将流量路由到新的IP地址上。 CoreDNS收到端点变更的通知。如果Service的类型是Headless,DNS条目将被更新。 云服务提供商收到端点变更的通知。如果Service的类型是LoadBalancer,新的端点将作为负载均衡池的一部分进行配置。 集群中安装的任何服务网格都会收到端点变更的通知。 任何订阅端点变更的其他操作员也会收到通知。
删除Pod
kubectl delete pod删除一个Pod,该命令首先会发送到Kubernetes API。





将容器中的任何挂载卷从容器存储接口(CSI)卸载。 将容器从网络中分离,并释放IP地址给容器网络接口(CNI)。 将容器销毁给容器运行时接口(CRI)。
kubectl delete pod删除一个Pod,该命令首先会发送到Kubernetes API。






优雅关闭
在退出之前等待更长的时间。 尽管收到SIGTERM信号,仍然处理传入的流量。 最后,关闭现有的长连接(例如数据库连接或WebSockets)。 关闭进程。
apiVersion: v1kind: Podmetadata:name: my-podspec:containers:- name: webimage: nginxports:- name: webcontainerPort: 80lifecycle:preStop:exec:command: ["sleep", "15"]





优雅期限和滚动更新
apiVersion: apps/v1kind: Deploymentmetadata:name: appspec:replicas: 3selector:matchLabels:name: apptemplate:metadata:labels:name: appspec:containers:- name: app# image: nginx:1.18 OLDimage: nginx:1.19ports:- containerPort: 3000
创建一个包含新容器镜像的Pod。 销毁一个现有的Pod。 等待Pod就绪。
首先创建一个新的Pod,并终止一个之前的Pod。 新的Pod需要2秒钟准备就绪,然后Kubernetes创建一个新的Pod。 与此同时,正在终止的Pod保持终止状态20秒钟。

终止长时间运行的任务

总结
原文地址:https://learnk8s.io/graceful-shutdown
推荐阅读


推荐视频





