Kubernetes Nginx:如何实现零停机部署?

时间:2017-07-13 14:14:42

标签: nginx kubernetes termination

我正在尝试使用零停机时间进行kubernetes nginx部署。该过程的一部分是启动rollingUpdate,确保至少有一个pod始终在运行nginx。这非常有效。

当旧的nginx pod正在终止时,我遇到了错误。 根据{{​​3}}上的kubernetes文档,kubernetes将:

  1. 从服务的端点列表中删除pod,所以它是 终止开始时未收到任何新流量
  2. 如果已定义,则调用pre-stop hook,并等待它完成
  3. 将SIGTERM发送给所有剩余进程
  4. 在宽限期到期后将SIGKILL发送给任何剩余的进程。
  5. 我知道命令nginx -s quit应该通过在主服务器终止之前等待所有工作者完成请求来优雅地终止nginx。它优雅地响应SIGQUIT命令,而SIGTERM导致暴力终止。其他论坛说它就像在部署中添加以下preStop挂钩一样简单:

    lifecycle:
      preStop:
        exec:
          command: ["/usr/sbin/nginx", "-s", "quit"]
    

    但是,通过测试此命令,我发现nginx -s quit立即返回,而不是等待工作人员完成。它也不会返回主进程的PID,这就是我希望D:

    发生的事情是,kubernetes调用nginx -s quit,它会向工作人员发送一个正确的SIGQUIT,但不要等待他们完成。相反,它会直接跳到第3步,而SIGTERM会转而采用这些流程,导致暴力终止,从而失去连接。

    问题:有没有人想出一个在滚动部署期间优雅地关闭他们的nginx控制器并且没有停机时间的好方法? sleep解决方法不够好,我正在寻找更强大的功能。

    以下是完整部署yaml:

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
    name: nginx-ingress-controller
    spec:
      replicas: 1
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 0
     template:
        metadata:
          labels:
            app: nginx-ingress-lb
        spec:
          terminationGracePeriodSeconds: 60
          serviceAccount: nginx
          containers:
            - name: nginx-ingress-controller
              image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.8
              imagePullPolicy: Always
              readinessProbe:
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
              livenessProbe:
                httpGet:
                  path: /healthz
                  port: 10254
                  scheme: HTTP
                initialDelaySeconds: 10
                timeoutSeconds: 5
              args:
                - /nginx-ingress-controller
                - --default-backend-service=$(POD_NAMESPACE)/default-backend
                - --v=2
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: POD_NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
              ports:
                - containerPort: 80
              lifecycle:
                preStop:
                  exec:
                    command: ["/usr/sbin/nginx", "-s", "quit"]
    

1 个答案:

答案 0 :(得分:5)

我讨厌回答我自己的问题,但是在涂了一点之后,这就是我到目前为止所拥有的。

我创建了一个半阻塞的bash脚本,名为killer

#!/bin/bash

sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit

while [ -d /proc/$PID ]; do
  sleep 0.1
done

我发现在nginx pod中有一个文件/run/nginx.pid,它有主进程的PID。如果你打电话给nginx -s quit并开始等待,直到该过程消失,你基本上已经退出命令"阻止"。

请注意,在发生任何事情之前都会有sleep 3。这是由于竞争条件导致Kubernetes将一个吊舱标记为终止,但需要一点时间(<1s)将该吊舱从指向其的流量的服务中移除。

我已将此脚本安装到我的pod中,并通过preStop指令调用它。它主要起作用,但在测试过程中仍然会偶尔出现一些问题,我发现卷曲错误表明连接是由同行重置的。&#34;但这是朝着正确方向迈出的一步。