码蚁

打码改变人生

Kubernetes 中如何优雅地停止 nginx

Posted at — Nov 29, 2018

在 Kubernetes 中调整 nginx 时前端会有 502 现象,简单分析下 nginx 如何在 Kubernetes 进行优雅退出。

何谓优雅停止?

优雅停止(Graceful shutdown)这个说法来自于操作系统,我们执行关机之后都得 OS 先完成一些清理操作,而与之相对的就是硬中止(Hard shutdown),比如拔电源。

到了分布式系统中,优雅停止就不仅仅是单机上进程自己的事了,往往还要与系统中的其它组件打交道。比如说我们起一个微服务,网关把一部分流量分给我们,这时:

一般情况下,SIGKILL 是硬终止的信号,而 SIGTERM 是通知进程优雅退出的信号,因此很多微服务框架会监听 SIGTERM 信号,收到之后去做反注册等清理操作,实现优雅退出.

nginx 退出信号

     -s signal      Send a signal to the master process.  The argument signal
                    can be one of: stop, quit, reopen, reload.  The following
                    table shows the corresponding system signals:

                    stop    SIGTERM
                    quit    SIGQUIT
                    reopen  SIGUSR1
                    reload  SIGHUP

SIGNALS
     The master process of nginx can handle the following signals:

     SIGINT, SIGTERM  Shut down quickly.
     SIGHUP           Reload configuration, start the new worker process with
                      a new configuration, and gracefully shut down old worker
                      processes.
     SIGQUIT          Shut down gracefully.
     SIGUSR1          Reopen log files.
     SIGUSR2          Upgrade the nginx executable on the fly.
     SIGWINCH         Shut down worker processes gracefully.

     While there is no need to explicitly control worker processes normally,
     they support some signals too:

     SIGTERM          Shut down quickly.
     SIGQUIT          Shut down gracefully.
     SIGUSR1          Reopen log files.

nginx 进程退出分为两种

Kubernetes 的 Pod 关闭流程

当用户请求删除 Pod 时,系统会将TERM信号发送到每个容器中的主进程,并在记录 Pod 执行关闭的时间。一旦超过允许的关闭时间,就会将KILL信号发送到那些进程,然后从API服务器中删除Pod。

一个示例流程:

下图我们可以看下 Pod 在 Kubernetes 整个生命周期

PodLifeCycle.svg

nginx 在 Kubernetes 中使用 preStop 进行优雅的退出

Kubernetes 关闭 Pod 时使用的时 TERM 信号,TERM 信号在 nginx 中是快速退出,并不是优雅退出,所以我们在 preStop hook 中使用 QUIT 信号通知 nginx 退出,当 nginx 退出完成后 preStop 再退出。

下面是例示 Deployment

apiVersion: apps/v1
kind: Deployment

metadata:
  name: chaos-static-file-deployment
  namespace: chaos-prod

spec:
  selector:
    matchLabels:
      app: chaos-static-file

  replicas: 2

  template: 
    metadata:
      labels:
        app: chaos-static-file
    
    spec:
      terminationGracePeriodSeconds: 90 ## Kuberenetes 将会给应用发送SIGTERM信号,可以用来正确、优雅地关闭应用,默认为30秒
      containers:
      - name: nginx
        image: ccr.ccs.tencentyun.com/chaos/chaos-static-file:2a651d7e
        volumeMounts:
        - name: config
          mountPath: /etc/nginx/conf.d/
          readOnly: true
        ports:
        - containerPort: 80
          name: http
        livenessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 10
          timeoutSeconds: 5
          periodSeconds: 30
        readinessProbe:
          initialDelaySeconds: 10
          periodSeconds: 30
          timeoutSeconds: 5
          tcpSocket:
            port: 80
        lifecycle:
          preStop:
            exec:
              # nignx 接收到 SIGTERM 信号是快速关闭,所以需要此步骤进行优雅关闭; 一开始的 sleep 是等待服务注销,后面以伪同步的方式进行优雅关闭
              command: ["/bin/sh", "-c", "sleep 10; PID=`cat /run/nginx.pid`; kill -s SIGQUIT $PID; while kill -0 $PID; do sleep 0.1; done"]

      imagePullSecrets:
      - name: chaos-registry-auth
      
      volumes: 
      - name: config
        configMap:
          name: chaos-static-file-config-v2

后面调整 nginx 时,用户就再没有出现过 502 现象。

comments powered by Disqus