nginx - Kubernetes Nginx : How to have zero-downtime deployments?

标签 nginx kubernetes termination

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

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

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

  • 我理解命令 nginx -s quit应该通过在主节点终止之前等待所有工作人员完成请求来优雅地终止 nginx。它优雅地响应 SIGQUIT 命令,而 SIGTERM 导致暴力终止。其他论坛说,将以下 preStop 钩子(Hook)添加到您的部署中一样简单:
    lifecycle:
      preStop:
        exec:
          command: ["/usr/sbin/nginx", "-s", "quit"]
    

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

    发生的情况是,kubernetes 调用 nginx -s quit ,这将向 worker child 发送适当的 SIGQUIT,但不等待他们完成。相反,它会直接跳到第 3 步并 SIGTERM 那些进程,从而导致暴力终止,从而丢失连接。

    问题 : 有没有人想出一个在滚动部署期间优雅地关闭 nginx Controller 并实现零停机的好方法?一个 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"]
    

    最佳答案

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

    我创建了一个半阻塞的 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 标记为终止的竞争条件,但需要一点时间(< 1 秒)才能将这个 pod 从指向它的流量的服务中删除。

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

    关于nginx - Kubernetes Nginx : How to have zero-downtime deployments?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45083275/

    相关文章:

    sockets - Nginx和uWSGI : Proper permissions setup for 502 Bad Gateway issue

    mysql - 有没有好的wordpress + php-fpm + nginx + mysql 内存优化技巧?

    .htaccess - 如何使 Zend Framework 2 与 nginx 一起工作?

    kubernetes - 我有 2 个调用相同配置的自定义覆盖。我需要在同一个文件夹中有两个 kustomization.yaml 文件

    docker - Kubernetes 持久卷和主机路径

    python - 我的功能没有运行

    bash - 如何使用 Minikube 在 pod 中捕获 SIGTERM

    php - Nginx 在动态之前提供静态页面

    azure - 如何在 azure kubernetes 上的 vnet 中配置 Azure redis 缓存?

    C - 使用 strncpy() 函数后的随机字符