SIGKILL 是硬终止的信号,而 SIGTERM 是通知进程优雅退出的信号

terminationGracePeriodSeconds是pod最多可以容忍的时间,超过这个时间pod会被强制kill

Pod的优雅关闭流程

1.新pod启动——>等待新pod进入Ready状态

2.k8s创建endpoint,将新服务纳入负载均衡

3.旧Pod设置为Terminating状态,并从所有服务的Endpoints列表中删除。

 此时旧Pod不再接收新的流量,但pod中的容器不受影响’

4.preStop Hook被执行

 preStop Hook是一个发送到Pod中的容器特殊命令或Http请求。

 如果应用程序在接收SIGTERM时没有正常关闭,可以使用preStop Hook来触发正常关闭。 接收SIGTERM时大多数程序都会正常关闭,但如果您使用的是第三方代码或管理的系统无法控制,则preStop Hook是在不修改应用程序的情况下触发正常关闭的好方法。

5.SIGTERM信号被发送到Pod

 此时,Kubernetes将向pod中的容器发送SIGTERM信号。这个信号让容器知道它们很快就会关闭

6.Kubernetes等待优雅的终止

 此时,Kubernetes等待指定的时间称为优雅终止宽限期。默认情况下,这是30秒。值得注意的是,这与preStop Hook和SIGTERM信号并行发生。Kubernetes不会等待preStop Hook完成。

 如果你的应用程序完成关闭并在terminationGracePeriod完成之前退出,Kubernetes会立即进入下一步。

 如果您的Pod通常需要超过30秒才能关闭,请增加优雅终止宽限期。通过在Pod YAML中设置terminationGracePeriodSeconds选项来实现。

spec:

  terminationGracePeriodSeconds: 30

7.SIGKILL信号被发送到Pod,并删除Pod

 如果容器在优雅终止宽限期后仍在运行,则会发送SIGKILL信号并强制删除。与此同时,所有的Kubernetes对象也会被清除

 有些步骤是同时执行的。因此有可能会导致该Pod仍然列在服务的Endpoints中并仍然接收流量,而它已经收到SIGTERM并且已经停止,因此负载均衡器上可能会有一些Http 504。目前解决这个问题可以使用preStop Hook 在容器收到SIGTERM时sleep一段时间,以确终止期间的流量可以正确处理

spec:
  containers:
  - name: nginx
    image: nginx
    lifecycle:
      preStop:
        exec:
          command:
          - sleep
          - 30
terminationGracePeriodSeconds: 60

 preStop Hook并不会影响SIGTERM的处理,因此有可能preStopHook还没执行完就收到SIGKILL导致容器强制退出。如果preStop Hook设置了n秒,需要设置terminationGracePeriodSeconds+n秒

容器生命周期钩子

容器钩子分为两类触发点:容器创建后PostStart和容器终止前PreStop

PostStart

在容器创建之后立即执行,如果钩子花费太长时间以至于容器不能运行或者挂起, 容器将不能达到running状态

PreStop

这个钩子在容器终止之前立即被调用,它是同步的, 必须在删除容器的调用发出之前完成,如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态,如果PostStart或者PreStop钩子失败, 容器将会被kill

容器可以通过实现和注册钩子的处理程序来访问钩子,可以为容器实现两种类型的钩子处理程序:

Exec - 在容器的cgroups和命名空间内执行一个特定的命令,比如pre-stop.sh。

该命令消耗的资源被计入容器

lifecycle:
   postStart:
     exec:
       command: ["bash", "/data/sed.sh"]
   preStop:
     exec:
       command: ["/bin/sh","-c","/pre-stop.sh"]

HTTP - 对容器上的特定的端点执行HTTP请求。

spring框架服务优雅停止

对于spring框架使用 spring cloud 的服务发现组件Eureka ,它是一个服务注册中心,用于定位服务来进行中间层服务器的负载均衡和故障转移。服务启动时,会向Eureka Server注册自己的信息(IP,端口,服务信息等),Eureka Server存储这些信息

微服务启动后,会周期性(默认30秒)的向Eureka Server发送心跳以续约自己的”租期”,并可以从eureka中获取其他微服务的地址信息,执行相关的逻辑

禁用某个服务


curl -X PUT \
"http://admin:admin@ip:port/eureka/apps/{appName}/{instanceId}/status?value=OUT_OF_SERVICE"

我们可以把这样停止服务的命令写到脚本中,在pod关闭前执行该脚本