Kubernetes群集的零停机更新-使用drain驱逐POD去维护NODE

原文标题:Zero Downtime Server Updates For Your Kubernetes Cluster

发布时间:Jan 26, 2019

原文链接:https://blog.gruntwork.io/zero-downtime-server-updates-for-your-kubernetes-cluster-902009df5b33

文章作者:yorinasub17

在Kubernetes集群的生命周期中,总会有某个时候,你需要对集群的宿主机节点进行维护。这可能包括程序包更新,内核升级或部署新的VM映像。在Kubernetes中,这些操作被视为“自愿中断”。

译注:参考Kubernetes对自愿中断和非自愿中断的定义

链接:https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#voluntary-and-involuntary-disruptions

这篇文章是一个分为四部分的博客系列的第一篇,下一篇文章会介绍如何优雅地关闭 Pod。

在这个系列中我们会介绍 Kubernetes 提供的所有用来实现 集群中工作节点的零宕机时间更新的工具。

问题说明

我们将从简单直接的维护宿主机节点的方法开始,确定该方法的挑战和潜在风险,并逐步构建解决我们在整个系列中发现的每个问题的方法。在这个博客系列结束时我们将完成一个Kubernetes配置,该配置利用生命周期钩子,就绪探针(redinessProbe)和 PodDisruptionBudgets 来实现 Kubernetes集群的零停机时间部署。

译注:推荐阅读「 Pod的活性探针和就绪探针」

为了开始我们的旅程,让我们看一个具体的例子。假设我们有一个两节点的 Kubernetes 集群,集群上运行着一个使用了两个 Pod 和一个 Service 资源的应用程序。

现在的问题是我们要升级集群中两个宿主机节点的内核版本。我们将如何执行升级?简单粗暴的方法是使用更新的配置启动新节点,在启动新节点后关闭旧节点。尽管这种方法有效,但是这种方法存在一些问题:

  • 当关闭旧节点时,节点上的 Pod 也会被删除。如果 Pod 需要清理以正常关闭上面运行的应用程序该怎么办?底层的VM技术可能不会等待 Pod 执行清理过程。
  • 如果同时关闭所有节点怎么办?在将 Pod 重新启动到新节点中时,你的应用程序服务会短暂中断。

我们想要的是一种从旧节点上正常迁移 Pod 的方法,以确保在对节点进行更改时,没有任何工作负载在运行。或者,如示例中所述,如果要完全替换群集(例如替换VM镜像),我们希望将工作负载从旧节点移到新节点。在这两种情况下,我们都希望避免调度新的 Pod 到旧节点上,我们可以使用 kubectl drain命令来实现这一点。

把Pod调度到节点之外

排出操作( kubectl drain)实现了将所有 Pod 重新调度到节点之外的目的。在排出操作期间,该节点会被标记为不可调度(通过给节点添加 NoSchedule 污点实现)。这样可以防止新建的Pod被调度到节点上。之后,排出操作开始从节点上驱逐 Pod,通过将 TERM 信号发送到 Pod 的底层容器来关闭当前在节点上运行的容器。

尽管 kubectl drain将很好地处理将Pod 逐出节点的工作,但仍有两个因素可能会在 kubectl drain触发的操作运行期间导致服务中断:

  • 运行中的应用程序需要能够优雅地处理 TERM 信号,当一个 Pod 驱逐时,Kubernetes 会向 Pod 发送 TERM 信号,然后在强制终结容器前会等待一段时间让容器自己关闭,这个等待时间是可以配置的。但是,如果 Pod 里的应用程序不能优雅地处理 TERM 信号,则仍然会导致不干净地关闭 Pod,比如应用程序正在工作期间(例如提交数据库事务等)。
  • 应用程序将失去为其提供服务的所有 Pod 。在新节点上启动新容器时,您的服务会遭遇停机。

避免停机

为了最大程度地减少因维护集群等自愿性中断而导致的停机时间,Kubernetes 提供以下中断处理功能:

  • Graceful termination
  • Lifecycle hooks
  • PodDisruptionBudgets

本系列的其余部分中,我们将使用 Kubernetes 的这些功能来减轻驱逐事件造成的服务中断。为了使后续操作更容易,我们将在上面的示例中使用以下资源配置:

    ---      
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15
        ports:
        - containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    targetPort: 80
    port: 80

上面的配置里包含了一个 Deployment 资源的最简示例,这个 Deployment 会始终维持集群中有两个标签为 app: nginx的 Pod,另外配置里还提供了一个可用于访问集群内 Nginx Pod 的 Service 资源的定义。

我们将在本系列的整个过程中逐步增加其内容,以构建最终配置,以实现Kubernetes提供的所有功能,最大程度地减少维护操作期间的停机时间。

下一篇文章,我们将会讲解如何利用 Kubernetes 的生命周期钩子(Lifecycle Hooks)来正常关闭 Pod。

推荐阅读

玩转Kubernetes滚动更新


你可能感兴趣的:(Kubernetes群集的零停机更新-使用drain驱逐POD去维护NODE)