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

sam*_*ght 6 docker google-cloud-platform kubernetes google-kubernetes-engine gke-networking

我在运行最新版本 Kubernetes ( ) 的 GKE Autopilot 集群上使用 GKE 设置了一个(非常)简单的部署1.18.15-gke.1501,并附加了一个链接到简单ClusterIP服务的入口(外部 HTTP(s) 负载均衡器)。

每当我使用新映像更新部署时,我都会遇到大约 5-15 分钟的停机时间,其中负载均衡器返回 502 错误。看起来控制平面创建了新的、更新的 Pod,允许进行服务级别运行状况检查(不是负载均衡器的健康检查,它还没有创建 NEG),然后同时杀死旧的 Pod是时候设置新的 NEG 了。然后,直到一段可变的时间后,它才会删除旧的 NEG。

在此输入图像描述

Pod 上的日志显示运行状况检查正在进行,但 GKE 仪表板显示 Ingress 状态的结果不一致。入口将显示正常,但服务将显示 502。

我尝试过的事情

  • 将 Pod 数量从 1 个增加到 3 个。这对某些部署有帮助,但在所有其他部署中,它都会增加负载均衡器正确解析所需的时间。
  • 尝试设置maxSurge为 1 和maxUnavailable0。这根本没有改善停机时间。
  • 添加lifecycle.preStop.exec.command: ["sleep", "60"]到部署上的容器。这是 GKE 文档中建议的。
  • 多次重新创建入口、服务、部署和集群。
  • 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
Run Code Online (Sandbox Code Playgroud)

服务配置:

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
Run Code Online (Sandbox Code Playgroud)

后端配置:

apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: foundation-service-config
spec:
  # sessionAffinity:
  #   affinityType: "GENERATED_COOKIE"
  #   affinityCookieTtlSec: 120
  connectionDraining:
    drainingTimeoutSec: 60
Run Code Online (Sandbox Code Playgroud)

入口配置:

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
Run Code Online (Sandbox Code Playgroud)

Tom*_*ood 1

我认为这可能与云 sql 身份验证代理 sidecar 未正确终止有关,导致负载均衡器陷入困境。

请注意GCP 文档中的这一点(我已将关键部分设为斜体

症状

502 错误或拒绝连接。潜在原因 新端点通常在连接到负载均衡器后变得可访问,前提是它们响应运行状况检查。如果流量无法到达端点,您可能会遇到 502 错误或拒绝连接。

502 错误和拒绝连接也可能是由不处理 SIGTERM 的容器引起的。如果容器没有显式处理 SIGTERM,它会立即终止并停止处理请求。负载均衡器继续将传入流量发送到已终止的容器,从而导致错误。

容器本机负载均衡器只有一个后端端点。在滚动更新期间,旧端点在新端点编程之前被取消编程。

配置容器本机负载均衡器后,后端 Pod 首次部署到新区域中。当区域中至少有一个端点时,负载均衡器基础设施就在该区域中进行编程。当新端点添加到区域时,负载均衡器基础设施将被编程并导致服务中断。

解决

配置容器以处理 SIGTERM 并在整个终止宽限期内(默认为 30 秒)继续响应请求。将 Pod 配置为在收到 SIGTERM 时开始失败运行状况检查。这会指示负载均衡器在端点取消编程过程中停止向 Pod 发送流量。

默认情况下,代理不能很好地处理 SIGTERM,并且不会在 SIGTERM 上正常退出(请参阅相关问题),但是它现在有一个很好的标志来处理此问题,因此您可以使用类似的东西

- name: cloud-sql-proxy
      image: gcr.io/cloudsql-docker/gce-proxy:1.23.1
      command:
        - "/cloud_sql_proxy"
        - "-instances={{ .Values.postgresConnectionName }}=tcp:5432"
        - "-term_timeout=60s"
      securityContext:
        runAsNonRoot: true
      resources:
        requests:
          memory: "2Gi"
          cpu:    "1"
Run Code Online (Sandbox Code Playgroud)

添加 term_timeout 标志主要是为我解决了这个问题,但在部署期间仍然偶尔会看到 502。一旦我设置了 term_timeout,将副本增加到 3 个(我的集群是区域性的,所以我想覆盖所有区域)似乎有所帮助。