Pod删除的过程

pod-delete-1
在删除 Kubernetes pod 的过程中,有两条平行的时间线,一是改变网络规则的时间线,另一个是 pod 的删除
pod-delete-2
管道执行kubectl delete pod 命令时,两个过程开始
网络规则生效

  1. kube-apiserver 接收到 pod 删除请求,将 pod 在 Etcd 中的状态更新为 Terminating
  2. Endpoint Controller 从 Endpoint 对象中删除 pod 的 IP
  3. kuber-proxy 根据 Endpoint 对象的变化更新 iptables 的规则,不再将流量路由到被删除的 Pod

删除pod

  1. kube-apiserver 接收到 Pod 删除请求,将 Pod 的再 Etcd 中的状态更新为 Terminating
  2. Kubelet 在节点清理容器相关资源,如存储、网络
  3. Kubelet 向容器发送 SIGTERM;如果容器内的进程没有配置,容器将立即退出
  4. 如果容器在默认的 30 秒内没有退出,Kubelet 将发送 SIGKILL 并强制它退出

如果在上述过程中没有正常关闭,可能会出现两个问题:
当前正在处理请求的pod被移除,如果请求不是幂等的,则会导致状态不一致返回502
Kubernetes 将流量路由到已经被删除的Pod,导致处理请求失败返回500,用户体验差

解决方案

为容器内的进程设置正常关闭

以SpringBoot为例,启用优雅关闭可以 Spring Boot 配置文件中添加下面设置,可以解决502问题

server:
    shutdown: graceful
spring:
    lifecycle:
         timeout-per-shutdown-phase:

添加preStopHook

当kube-apiserver接收到pod删除请求后,必须要预留一段时间,来等待网络规则的更新,避免新的流量路由到一个不可用的pod上,因此应该让Kubelet在收到删除pod事件时“sleep 一下”,并在给Pod发送SIGTERM之前留出足够的时间来更新网络规则,可以解决502问题

containers:
- name: test
  #添加下面这部分
  lifecycle:
    preStop:
      exec:
        command:
        - /bin/sh
        - -c
        - "sleep 10"

修改终止GracePeriodSeconds

Kubernetes为容器删除留下了30秒的最大时间尺度。如果Spring的优雅关闭超时时间和 Kubernetes的preStopHooks之和超过30秒,可能会导致Kubernetes在Spring Boot处理完请求之前强行删除容器。因此如果过程超过30秒,则应改timerminationGracePeriodSeconds 调整为大于30秒

apiVersion: apps/v1
kind: Deployment
metadata:
   name: test
spec:
  replicas: 1
  selector:
     matchLabels:
           app: test
  template:
    metadata:
       labels:
         app: test
    spec:
      containers:
        - name: test
          image: oms-center:latest
          ports:
            - containerPort: 8080
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 10"]  #prestop hook
       terminationGracePeriodSeconds: 45 #terminationGracePeriodSeconds

设置正常关闭可确保在容器终止之前完成处理正在进行的请求,设置preStopHook确认删除pod和更新网络规则之间的顺序关系,最后给进程留出充裕的时间来处理所有请求,设置terminationGracePeriodSeconds

制作可优雅关闭的镜像

Dockerfile使用exec的方式能够实现K8S容器应用优雅关闭,系统调用exec是以新的进程去代替原来的进程,但进程的PID保持不变

示例

[root@base test]# cat Dockerfile 
FROM centos7_jdk:latset
COPY app.jar /home
ENV JVM_OPTS="-Xms500m -Xmx1024m -Xmn250m -Xss256k"
ENV JAVA_OPTS=""
EXPOSE 8080
WORKDIR /home
ENTRYPOINT [ "sh", "-c", "java $JVM_OPTS $JAVA_OPTS -jar app.jar"]
文章作者: 鲜花的主人
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 爱吃可爱多
Kubernetes Kubernetes
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝