【问题标题】:Kubernetes Nginx: How to have zero-downtime deployments?Kubernetes Nginx:如何实现零停机部署?
【发布时间】:2017-12-18 09:25:10
【问题描述】:

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

当旧的 nginx pod 终止时,我遇到了错误。 根据termination 上的 kubernetes 文档,kubernetes 将:

  1. 从服务的端点列表中删除 pod,因此它是 终止开始时未收到任何新流量
  2. 如果定义了预停止钩子,则调​​用它,并等待它完成
  3. 向所有剩余进程发送 SIGTERM
  4. 在宽限期到期后向所有剩余进程发送 SIGKILL。

我知道命令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"]

【问题讨论】:

    标签: nginx kubernetes termination


    【解决方案1】:

    我讨厌回答自己的问题,但经过一番思考之后,这就是我目前所拥有的。

    我创建了一个半阻塞的 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 将 pod 标记为终止的竞争条件,但需要一点时间(

    我已将此脚本安装到我的 pod 中,并通过 preStop 指令调用它。它主要是有效的,但在测试过程中,仍然偶尔会出现一些问题,我得到一个 curl 错误,表明连接是“由对等方重置的”。但这是朝着正确方向迈出的一步。

    【讨论】:

    • 对于任何即将尝试相同的人。由于@Lindsay Landry 提到的竞争条件,在 nginx docker 映像中使用 STOPSIGNAL SIGQUIT docs.docker.com/engine/reference/builder/#stopsignal 不起作用。您将暂时失去连接,因此请坚持使用上面的 bash 脚本。
    • @Niels-Ole STOPSIGNAL SIGQUIT 似乎工作正常,但仍需要 sleep 3 来处理竞争条件
    猜你喜欢
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 2019-11-22
    • 2013-05-12
    • 1970-01-01
    • 2011-05-08
    相关资源
    最近更新 更多