微服务中,网关会把流量分配给每个Pod节点上

1. 如果我们直接将Pod杀死,那这部分流量就无法得到正确处理,会影响部分用户,通常来说网关或者注册中心会将我们的服务保持一个心跳,过了心跳超时之后会自动摘除我们的服务,但是有一个问题就是超时时间可能是30秒也可能是60秒,虽然不会影响我们的系统,但是会产生用户轻微抖动。


2. 如果我们在停止前执行一条命令,通知网关或者注册中心这台主机进行下线,那么注册中心就会标记这台主机已经下线,不进行流量转发,用户就不会有任何影响,这就是优雅停止,将滚动更新影响最小化

 

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

在k8s中,理想的状态是pod优雅释放,并产生新的Pod。但是并不是每一个Pod都会这么顺利

Pod卡死,处理不了优雅退出的命令或者操作
优雅退出的逻辑有BUG,陷入死循环
代码问题,导致执行的命令没有效果

对于以上问题,k8s的Pod终止流程中还有一个"最多可以容忍的时间",即grace period (在pod的.spec.terminationGracePeriodSeconds字段定义),这个值默认是30秒,当我们执行kubectl delete的时候也可以通过--grace-period参数显示指定一个优雅退出时间来覆盖Pod中的配置,如果我们配置的grace period超过时间之后,k8s就只能选择强制kill Pod

 

Kubernetes终止生命周期

1 - K8S 启动新POD。
2 - K8S等待新POD进入Ready(Running) 状态。
3 - K8S创建Endpoint。此时,k8s创建endpoint,将新服务纳入负载均衡。
4 - 用户删除pod,Pod设置为”Terminating”状态,并从所有服务的Endpoints列表中删除。此时,Pod停止获得新的流量。但在Pod中运行的容器不会受到影响。
5 - preStop Hook被执行。 preStop Hook是一个发送到Pod中的容器特殊命令或Http请求。
6 - SIGTERM信号被发送到Pod。 此时,Kubernetes将向pod中的容器发送SIGTERM信号。这个信号让容器知道它们很快就会关闭。
7 - Kubernetes等待优雅的终止 此时,Kubernetes等待指定的时间称为优雅终止宽限期。默认情况下,这是30秒。值得注意的是,这与preStop Hook和SIGTERM信号并行发生。Kubernetes不会等待preStop Hook完成。

 

 

基于PreStop环境演示

在生产环境中使用spring框架,由于服务更新过程中,服务容器被直接充值,部分请求仍被分发到终止的容器(没有配置钩子,熟悉默认环境),导致服务出现500错误,这部分错误请求数据占用比较少,因为Pod滚动更新都是一对一。因为部分用户会产生服务器错误的情况,考虑使用优雅的终止方式,将错误请求降到最低,直至滚动更新不影响用户

Eureka是一个基于REST的服务,作为Spring Cloud服务注册中心,用于定位服务来进行中间层服务器的负载均衡和故障转移。各服务启动时,会向Eureka Server注册自己的信息(IP、端口、服务信息等),Eureka Server会存储这些信息,微服务启动后,会周期性(默认30秒)的向Eureka Server发送心跳以续约自己的租期,并且可以从eureka中获取其他微服务的地址信息,执行相关逻辑。。

由于Eureka默认的心跳检测为30秒,当K8S下线Pod时Eureka会有30秒的异常问题,所以我们需要在Pod 停止前发送一条请求,通知Eureka进行下线操作,这样进行优雅的停止对用户的影响做到最小

apiVersion: v1
kind: Pod
metadata:
  name: abcdocker
  labels:
    name: abcdocker
spec:
  containers:
  - name: abcdocker
    image: nginx
    ports:
      - containerPort: 80
    lifecycle:
      preStop:
        exec:
          command:
            - bash
            - -c
            - 'curl -X POST --data DOWN http://127.0.0.1:8080/service-registry/instance-status  -H
              "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8";sleep 30'

####### 参数解释
127.0.0.1:8080 #代表eureka地址
service-registry    #代表注册中心
DOWN        #执行down请求
sleep       #等待30秒

 

当我们删除Pod的时候就会执行上面的命令操作,并且等待30秒

[root@yzsjhl82-135 yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
abcdocker   1/1     Running   0          2m16s
[root@yzsjhl82-135 yaml]# kubectl delete pod abcdocker
pod "abcdocker" deleted

#此刻Pod不会马上删除,而是执行Exec中的命令,并等待30秒

 

配置中添加了一个sleep时间,主要是作为服务停止的缓冲时间。