【问题标题】:Kubernetes Zero Downtime deployment not working - Gives 503 Service Temporarily UnavailableKubernetes 零停机时间部署不起作用 - 导致 503 服务暂时不可用
【发布时间】:2019-08-20 00:46:57
【问题描述】:

我正在尝试使用 Kubernetes 实现零停机部署。但是每次我使用新映像升级部署时,我都会看到 2-3 秒的停机时间。我正在使用 Hello-World 类型的应用程序对此进行测试,但仍然无法实现。我正在使用 Helm 图表部署我的应用程序。

根据在线博客和资源,我在 Deployment.yaml 文件中使用了 Readiness-Probe 和滚动更新策略。但这没有让我成功。 我创建了一个/health 端点,它只返回200 状态代码作为准备探测的检查。我希望在 Kubernetes 中使用就绪探针和 RollingUpdate 策略后,我可以在升级容器映像时实现服务的零停机时间。对我的服务的请求通过 Amazon ELB。

Deployment.yaml 文件如下:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: wine-deployment
  labels:
    app: wine-store
    chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
    release: {{ .Release.Name }}
    heritage: {{ .Release.Service }}
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: wine-store
  replicas: 2
  template:
    metadata:
      labels:
        app: wine-store
    spec:
      containers:
        - name: {{ .Chart.Name }}
          resources:
            limits:
              cpu: 250m
            requests:
              cpu: 200m
          image: "my-private-image-repository-with-tag-and-version-goes-here-which-i-have-hidden-here"
          imagePullPolicy: Always
          env:
          - name: GET_HOSTS_FROM
            value: dns
          ports:
          - containerPort: 8089
            name: testing-port
          readinessProbe:
            httpGet:
              path: /health
              port: 8089
            initialDelaySeconds: 3
            periodSeconds: 3 

Service.yaml 文件:

apiVersion: v1
kind: Service
metadata:
  name: wine-service
  labels:
    app: wine-store
spec:
  ports:
    - port: 80
      targetPort: 8089
      protocol: TCP
  selector:
    app: wine-store

Ingress.yaml 文件:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: wine-ingress
  annotations:
     kubernetes.io/ingress.class: public-nginx
spec:
  rules:
    - host: my-service-my-internal-domain.com
      http:
        paths:
          - path: /
            backend:
              serviceName: wine-service
              servicePort: 80

当我使用helm upgrade 命令升级映像时,我希望停机时间为零。同时,在升级过程中,我不断地使用 curl 命令访问我的服务。这个 curl 命令给我 503-service Temporarily un-available 错误 2-3 秒,然后服务再次启动。我希望这种停机时间不会发生。

【问题讨论】:

    标签: kubernetes


    【解决方案1】:

    此问题是由使用 iptables 的服务 VIP 引起的。你没有做错任何事——这是当前 Kubernetes 的限制。

    当对新 pod 的就绪探测通过时,旧 pod 被终止,kube-proxy 为服务重写 iptables。但是,在旧 pod 终止之后但在 iptables 更新之前,请求可能会命中服务,从而导致 503。

    一个简单的解决方法是使用preStop 生命周期挂钩来延迟终止:

    lifecycle:
      preStop:
        exec:
          command: ["/bin/bash", "-c", "sleep 10"]
    

    在这种情况下可能不相关,但在您的应用程序中实现优雅终止是一个好主意。拦截 TERM 信号并等待您的应用程序完成处理它已经收到的所有请求,而不是立即退出。

    或者,更多的副本、较低的maxUnavailable 和较高的maxSurge 都会降低请求到达终止 pod 的概率。

    更多信息: https://kubernetes.io/docs/concepts/services-networking/service/#proxy-mode-iptables https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods

    另一个答案错误地表明您需要一个活性探针。虽然进行活性探测是个好主意,但它不会影响您遇到的问题。未定义活动探测时,默认状态为成功。

    在滚动部署的上下文中,活性探测将无关紧要 - 一旦新 pod 上的就绪探测通过,旧 pod 将收到 TERM 信号并且 iptables 将被更新。现在旧 pod 正在终止,任何 liveness probe 都无关紧要,因为它的唯一功能是在 liveness probe 失败时重新启动 pod。

    对新 pod 的任何活性探测都无关紧要。当 pod 首次启动时,默认情况下它被认为是活动的。只有在 liveness probe 的initialDelaySeconds 之后才会开始检查,如果失败,则终止 Pod。

    https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes

    【讨论】:

      【解决方案2】:

      使用蓝绿色部署,因为即使 pod 已启动,kube-proxy 也可能需要一些时间才能将请求转发到新的 POD IP。
      所以设置新的部署,在所有 pod 都启动更新服务selector 到新的 POD 标签之后。 关注:https://kubernetes.io/blog/2018/04/30/zero-downtime-deployment-kubernetes-jenkins/

      【讨论】:

      • @akash,谢谢。没有机会通过此链接。如果 liveness-probes 也不起作用,将尝试一下。
      【解决方案3】:

      您描述的问题表明就绪探测存在问题。了解 liveness 和 readiness 探针之间的区别很重要。首先你应该实现和配置两者!

      活性探针用于检查容器是否已启动并处于活动状态。如果不是这样,kubernetes 最终会重启容器。

      反过来,就绪探针也会检查依赖关系,如数据库连接或容器依赖的其他服务来完成它的工作。作为开发人员,您必须在这里投入更多的时间来实现,而不仅仅是活性探测。您必须公开一个端点,该端点也在查询时检查提到的依赖项。

      您当前的配置使用一个健康端点,该端点通常由活性探针使用。它可能不会检查您的服务是否真的准备好接受流量。

      Kubernetes 依赖于就绪探测。在滚动更新期间,它将保持旧容器启动并运行,直到新服务声明它已准备好接收流量。因此,必须正确实施就绪探测。

      【讨论】:

      • 嘿@Randy,谢谢你的建议。我肯定会实施一个活性探测以及准备探测和再次测试。我会在这里更新。关于依赖关系,我没有。这是一个简单的 hello-World vertx 应用程序。不涉及数据库,不涉及属性文件。我将使用与 liveness 和 Readiness Probe 相同的 HTTP-GET 探针。
      • @mohdshoaib 您还可以使用生命周期探针来调试 k8s 的行为。例如。你可以记录它是否真的调用了端点来检查服务是否准备好。
      • 如果我使用kubectl logs podName -n NamespaceName 那么我会得到这些日志吗?或者我需要做Kubectl describe pod <podName> -n <namespace>
      • 使用kubectl logs,您将获得 pod 正在写的内容。如果您想在此处查看日志,则需要分别实现就绪探测以记录到 stout。
      • 我也尝试了与 liveness probe 一起使用,但没有成功。虽然我找不到探测的日志。
      猜你喜欢
      • 2017-12-09
      • 2018-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-18
      • 2011-12-19
      • 2018-09-16
      • 1970-01-01
      相关资源
      最近更新 更多