02-pod的生命周期hook

pod的生命周期

我们知道Pod是Kubernetes集群中的最小单元,而 Pod 是由容器组成的,所以在讨论 Pod 的生命周期的时候我们可以先来讨论下容器的生命周期。

实际上 Kubernetes 为我们的容器提供了生命周期钩子,就是我们说的Pod Hook,Pod Hook 是由 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。我们可以同时为 Pod 中的所有容器都配置 hook。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CuyxTkSJ-1628755387532)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210226175041783.png)]

Kubernetes 为我们提供了两种钩子函数:

PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRY POINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。(PostStart 可以在容器启动之后就执行。但需要注意的是,此 hook 和容器里的 ENTRYPOINT 命令的执行顺序是不确定的。)

PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。(PreStop 则在容器被终止之前被执行,是一种阻塞式的方式。执行完成后,Kubelet 才真正开始销毁容器。)

如果PostStart或者PreStop钩子失败, 它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态。

另外我们有两种方式来实现上面的钩子函数:

  • Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。
  • HTTP - 对容器上的特定的端点执行HTTP请求。

pod的启动终止的过程

在这里插入图片描述

pod的终止过程

1.用户向apiServer发送删除pod对象的命令
2.apiServcer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s), pod被视为dead
3.将pod标记为terminating状态
4.kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
5.端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
6.如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
7.pod对象中的容器进程收到停止信号
8.宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
9.kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见

pod的创建过程

1.用户通过kubectl或其他api客户端提交需要创建的pod信息给apiServer
2.apiServer开始生成pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
3.apiServer开始反映etcd中的pod对象的变化,其它组件使用watch机制来跟踪检查	     apiServer上的变动
4.scheduler发现有新的pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer
5.node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至
apiServer6. apiServer将接收到的pod状态信息存入etcd中

Pod生命周期内的5种状态

在整个生命周期中,Pod会出现5种状态(相位),分别如下:

挂起(Pending) : apiserver已经创建了pod资源对象,但它尚未被调度完成或者仍处于下载镜像的过程中
运行中(Running) : pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
成功(Succeeded) : pod中的所有容器都已经成功终止并且不会被重启
失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态。
未知(Unknown) : apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致

示例1环境准备使用postStart

​ 以下示例中,定义了一个Nginx Pod,其中设置了PostStart钩子函数,即在容器创建成功后,写入一句话到/usr/share/message文件中。

[root@k8s-master ~]# vim hook.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hook-demo1
spec:
  containers:
  - name: hook-demo1
    image: nginx
    lifecycle:		#生命周期,使用函数调用必须使用
      postStart:	#使用 postStart函数
        exec:		#执行
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
#使用postStart函数在容器就绪前往/usr/share/message里写入Hello from the postStart handler的一句话,
#简单理解就是容器启动后先执行写入文件,在运行nginx进程

进行创建并查看

[root@k8s-master ~]# kubectl create -f hook.yaml
pod/hook-demo1 created
[root@k8s-master ~]# kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
hook-demo1   1/1     Running   0          8s
[root@k8s-master ~]# kubectl exec hook-demo1 -it -- cat /usr/share/message
Hello from the postStart handler
#写入的文件存在说明postStart函数生效成功

示例2 优雅删除资源对象

当用户请求删除含有 pod 的资源对象时,K8S 为了让应用程序优雅关闭(即让应用程序完成正在处理的请求后,再关闭软件),K8S提供两种信息通知:

默认:K8S 通知 node 执行docker stop命令,docker 会先向容器中PID为1的进程发送系统信号SIGTERM,然后等待容器中的应用程序终止执行,如果等待时间达到设定的超时时间,或者默认超时时间(30s),会继续发送SIGKILL的系统信号强行 kill 掉进程。
使用 pod 生命周期(利用PreStop回调函数),它执行在发送终止信号之前。

默认所有的优雅退出时间都在30秒内。kubectl delete 命令支持 --grace-period=选项,这个选项允许用户用他们自己指定的值覆盖默认值。值’0’代表 强制删除 pod. 在 kubectl 1.5 及以上的版本里,执行强制删除时必须同时指定 --force --grace-period=0。

强制删除一个 pod 是从集群状态还有 etcd 里立刻删除这个 pod。 当 Pod 被强制删除时, api 服务器不会等待来自 Pod 所在节点上的 kubelet 的确认信息:pod 已经被终止。在 API 里 pod 会被立刻删除,在节点上, pods 被设置成立刻终止后,在强行杀掉前还会有一个很小的宽限期。

同 readinessProbe一样,hook 也有类似的 Handler:

Exec 用来执行 Shell 命令;

HTTPGet 可以执行 HTTP 请求。

示例:让nginx优雅退出

[root@k8s-master ~]# mkdir -p /data/nginx/html		#创建数据挂载目录
[root@k8s-master ~]# vim hook1.yaml			#编辑yaml文件
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
  namespace: default
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: message
      mountPath: /usr/share/nginx/html
    lifecycle:
      postStart:		#容器启动前向nginx主页文件中添加postStart 字段
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/nginx/html/index.html"]
      preStop:			#容器结束前向nginx主页文件中添加preStop字段
        exec:
          command: ["/bin/sh","-c","echo Hello from the preStop handler > /usr/share/nginx/html/index.html"]
  volumes:		#将nginx主页文件位置挂载到宿主机/data/nginx/html以便后期查看
  - name: message
    hostPath:
      path: /data/nginx/html

创建及验证postStart函数

[root@k8s-master ~]# kubectl create -f hook1.yaml	#生成pod
[root@k8s-master html]# kubectl get pod -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
hook-demo1       1/1     Running   0          51m   10.244.1.2   k8s-node01   <none>           <none>
lifecycle-demo   1/1     Running   0          9s    10.244.2.3   k8s-node02   <none>           <none>
#查看ip地址及运行在那个node上,(此处是运行在node02上),那数据卷共享也会在node02上,查询preStop函数是否生效时要前往对象节点
#通过命令查看postStart函数是否生效
[root@k8s-master html]# curl 10.244.2.3		
#此时主页文件已经被postStart函数中的命令进行更改,说明postStart函数生效成功
Hello from the postStart handler

验证preStop函数

如果将容器销毁 ,PreStop这个钩子在容器终止之前立即被调用,可以看到结果如下

[root@k8s-master html]# kubectl delete -f /root/hook1.yaml	
#删除pod验证preStop函数
pod "lifecycle-demo" deleted
#前往node02验证
[root@k8s-node02 ~]# cat /data/nginx/html/index.html
#此时preStop函数的操作已经更改了nginx的主页,说明已经preStop函数生效成功
Hello from the preStop handler

当我们是使用nginx开启会话 保持后,想要结束掉进程时,发现还有用户在访问页面信息,如果强制终止会让用户体验很差,从而影响业务,我们可以借助**preStop**以优雅的方式停掉 Nginx 服务,从而避免强制停止容器,造成正在处理的请求无法响应。

apiVersion: v1
kind: Pod
metadata:
  name: hook-demo2
spec:
  containers:
  - name: hook-demo2
    image: nginx
    lifecycle:
      preStop:			#容器结束前,处理完所有的连接后进行退出
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]

总结

创建容器后,Kubernetes立即发送postStart事件。但是,不能保证在调用Container的入口点之前先调用postStart处理程序。postStart处理程序相对于Container的代码异步运行,但是Kubernetes对容器的管理会阻塞,直到postStart处理程序完成。在postStart处理程序完成之前,容器的状态不会设置为RUNNING。

Kubernetes会在容器终止之前立即发送preStop事件。除非Pod的宽限期到期,否则Kubernetes对Container的管理将一直保持到preStop处理程序完成为止。

注意: Kubernetes仅在Pod终止时才发送preStop事件。这意味着在Pod完成时不会调用preStop挂钩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值