docker - GKE Autopilot Ingress 在部署后 5-15 分钟内返回 502 错误

标签 docker kubernetes google-cloud-platform google-kubernetes-engine gke-networking

我在运行最新版本 Kubernetes ( 1.18.15-gke.1501 ) 的 GKE Autopilot 集群上使用 GKE 设置了一个(非常)简单的部署,并附加了一个链接到简单 ClusterIP 的入口(外部 HTTP(s) 负载均衡器)。服务。
每当我使用新镜像更新部署时,我都会遇到大约 5-15 分钟的停机时间,此时负载均衡器会返回 502 错误。似乎控制平面创建了新的、更新的 pod,允许通过服务级别的健康检查(不是负载均衡器,它尚未创建 NEG),然后同时杀死旧的 pod是时候设置新 NEG 了。然后它不会删除旧的 NEG,直到一段时间后。
enter image description here
Pod 上的日志显示运行状况检查正在通过,但 GKE 仪表板显示 Ingress 状态的结果不一致。入口将显示为正常,但服务将显示 502。
我尝试过的事情

  • 将 Pod 的数量从 1 增加到 3。这对某些部署有所帮助,但在其他所有部署中,它都会增加负载均衡器正确解析所需的时间。
  • 尝试设置 maxSurge到 1 和 maxUnavailable到 0。这根本没有改善停机时间。
  • 添加 lifecycle.preStop.exec.command: ["sleep", "60"]到部署上的容器。 This was suggested in the GKE docs here.
  • 多次重新创建入口、服务、部署和集群。
  • 添加 BackendConfig对增加其消耗较慢的服务。
  • 添加一个在文档中找到的准备门应该可以解决这个问题,但由于某种原因没有?

  • 以上都没有帮助或对事情下降的时间产生任何显着差异。
    我真的很困惑为什么这不起作用。感觉就像我错过了一些非常明显的东西,但这也是一个如此简单的配置,你会认为它......只是工作?任何人都知道发生了什么?
    配置文件
    部署配置:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: foundation-deployment
    spec:
      replicas: 3
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 0
          maxSurge: 1
      selector:
        matchLabels:
          app: foundation-web
      template:
        metadata:
          labels:
            app: foundation-web
        spec:
          readinessGates:
            - conditionType: "cloud.google.com/load-balancer-neg-ready"
    
          serviceAccountName: foundation-database-account
          containers:
            # Run Cloud SQL proxy so we can safely connect to Postgres on localhost.
            - name: cloud-sql-proxy
              image: gcr.io/cloudsql-docker/gce-proxy:1.17
              resources:
                requests:
                  cpu: "250m"
                  memory: 100Mi
                limits:
                  cpu: "500m"
                  memory: 100Mi
              command:
                - "/cloud_sql_proxy"
                - "-instances=nine-foundation:us-central1:foundation-staging=tcp:5432"
              securityContext:
                runAsNonRoot: true
            # Main container config
            - name: foundation-web
              image: gcr.io/project-name/foundation_web:latest
              imagePullPolicy: Always
              lifecycle:
                preStop:
                  exec:
                    command: ["sleep", "60"]
              env:
               # Env variables
              resources:
                requests:
                  memory: "500Mi"
                  cpu: "500m"
                limits:
                  memory: "1000Mi"
                  cpu: "1"
              livenessProbe:
                httpGet:
                  path: /healthz
                  port: 4000
                initialDelaySeconds: 10
                periodSeconds: 10
              readinessProbe:
                httpGet:
                  path: /healthz
                  port: 4000
                initialDelaySeconds: 10
                periodSeconds: 10
              ports:
                - containerPort: 4000
    
    服务配置:
    apiVersion: v1
    kind: Service
    metadata:
      name: foundation-web-service
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
        cloud.google.com/backend-config: '{"ports": {"4000": "foundation-service-config"}}'
    spec:
      type: ClusterIP
      selector:
        app: foundation-web
      ports:
        - port: 4000
          targetPort: 4000
    
    后端配置:
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: foundation-service-config
    spec:
      # sessionAffinity:
      #   affinityType: "GENERATED_COOKIE"
      #   affinityCookieTtlSec: 120
      connectionDraining:
        drainingTimeoutSec: 60
    
    入口配置:
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: foundation-web-ingress
      labels:
        name: foundation-web-ingress
    spec:
      backend:
        serviceName: foundation-web-service
        servicePort: 4000
    

    最佳答案

    您的 Autopilot 集群在新部署期间遇到延迟的原因是集群的主节点正在进行更新。每次用户在集群上部署时,GKE Autopilot 系统都会更新主节点。
    但是,为了防止在生产的关键时刻发生这种情况,您可以为此集群创建一个维护时段,以便您可以控制自动集群维护(例如自动升级)何时可以和不可以在您的 GKE Autopilot 集群上发生.
    我希望这能解释这个问题。
    供您引用:
    Kubernetes 的就绪探测默认值为 10 分钟。这意味着,即使部署仍在进行,就绪探针也会在 10 分钟后将其标记为失败。
    GKE Autopilot 在整个部署步骤(不仅仅是等待就绪状态)上设置了一个可配置的超时时间,在等待就绪状态期间,Kubernetes 会调用就绪探针来监控部署。
    就绪探针基于 Kubernetes 默认值,在 10 分钟后标记部署失败。 GKE Autopilot 会看到来自就绪探测器的消息,并报告部署由于超出截止日期而失败。
    作为一种可能的解决方案,可以通过以秒为单位指定“progressDeadlineSeconds”[5] 值,在您的 YAML 中扩展就绪探测默认超时。默认值为 600 秒(10 分钟)。关于它的更多细节在这里[6]。我建议尝试将其添加到您的 YAML 文件并增加超时以查看这是否能解决手头的问题。
    当出现过度缩小时。我们建议客户将 minNodes 自动缩放配置值设置为等于 maxNodes。
    Cluster Autoscaler 认为可以在现有节点之一上调度 pod,但调度程序表示不能。 Pod 不会被安排,也不会发生扩展。在这种情况下,我们建议创建一个新的节点池或调整支持现有节点池的 MIG 的大小作为快速缓解措施。
    正如您所提到的,您多次重新创建入口、服务、部署和集群,请确保遵循以下步骤:
    不完整的垃圾收集
    Google Kubernetes Engine 垃圾收集器每两分钟收集一次容器原生负载均衡器。如果集群在负载均衡器完全移除之前被删除,您需要手动删除负载均衡器的 NEG。
    通过运行以下命令查看项目中的 NEG:

    gcloud compute network-endpoint-groups list
    
    在命令输出中,查找相关 NEG。
    要删除 NEG,请运行以下命令,其中 neg 是 NEG 的名称:
    gcloud compute network-endpoint-groups delete [neg]
    
    将工作负载推出与端点传播保持一致
    https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts
    备注 :在使用 Pod 就绪反馈来管理工作负载推出的集群中不会发生此问题。有关更多信息,请参阅 Pod 准备情况。
    当您将工作负载部署到集群或更新现有工作负载时,容器原生负载均衡器传播新端点所需的时间可能比完成工作负载推出所需的时间更长。您在本指南中部署的示例部署使用两个字段来使其推出与端点的传播保持一致:terminationGracePeriodSeconds 和 minReadySeconds。
    TerminationGracePeriodSeconds 允许 Pod 通过在计划删除 Pod 后等待连接终止来正常关闭。
    minReadySeconds 在创建 Pod 后添加一个延迟期。您指定新 Pod 应处于就绪状态的最短秒数,而其任何容器都不会崩溃,以便将 Pod 视为可用。
    您应该将工作负载的 minReadySeconds 和 terminateGracePeriodSeconds 值配置为 60 秒或更高,以确保服务不会因工作负载推出而中断。
    TerminationGracePeriodSeconds 适用于所有 Pod 规范,而 minReadySeconds 适用于 Deployments 和 DaemonSets。
    要了解有关微调部署的更多信息,请参阅 RollingUpdateStrategy。
    Pod readinessProbe 中的 initialDelaySeconds 不受尊重
    您可能希望容器原生负载均衡器遵守 Pod 的 readinessProbe 中的 initialDelaySeconds 配置;但是,readinessProbe 是由 kubelet 实现的,initialDelaySeconds 配置控制 kubelet 健康检查,而不是容器原生负载均衡器。容器原生负载均衡有自己的负载均衡健康检查。
    部署失败
    您的 Deployment 可能会在尝试部署其最新的 ReplicaSet 而从未完成时卡住。这可能是由于以下一些因素造成的:
    Insufficient quota
    Readiness probe failures
    Image pull errors
    Insufficient permissions
    Limit ranges
    Application runtime misconfiguration
    For more information on failed deployments please refer [4].
    
    由于这个产品比较新,我想分享以下关于GKE Autopilot的文档以供引用:
  • GKE Autopilot 概述:
    https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview
  • Autopilot集群架构:
    https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-architecture
  • 关于 Kubernetes 部署的文章:
    https://medium.com/polarsquad/check-your-kubernetes-deployments-46dbfbc47a7c
    [4]。部署失败:
    https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#failed-deployment
    [5]。进度截止秒数:
    https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#progress-deadline-seconds
    [6]部署:
    https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
  • 关于docker - GKE Autopilot Ingress 在部署后 5-15 分钟内返回 502 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66810269/

    相关文章:

    docker - Docker hub 存储库数量的限制

    ubuntu - SSH 服务器不接受连接

    azure - KEDA 缩放器无法在使用 pod 身份进行触发身份验证的 AKS 上工作

    go - 在 kubernetes 中处理 kafka 客户端更新

    c# - AKS集群Pod Kube配置位置

    email - GCP错误报告-通知所有者的电子邮件

    tensorflow 每次运行发现多个图形事件

    firebase - 在哪里保存和读取 DigitalOcean 应用平台的凭证文件?

    docker - Bazel - 在 Monorepo 中构建、推送、部署 Docker 容器到 Kubernetes

    docker - 在 GCP 中 kubernetes 内的同一节点上从 Pod 到 Pod 的通信