如何优雅地关闭Kubernetes集群中的Pod

原文标题:Gracefully Shutting Down Pods in a Kubernetes Cluster

发布时间:Jan 26, 2019

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

文章作者:yorinasub17

这是我们实现 Kubernetes 集群零停机时间更新的第二部分。在本系列的第一部分中,我们列举出了简单粗暴地使用kubectl drain 命令清除集群节点上的 Pod 的问题和挑战。在这篇文章中,我们将介绍解决这些问题和挑战的手段之一:优雅地关闭 Pod。

Pod驱逐的生命周期

默认情况下,kubectl drain命令驱逐节点上的 Pod 时会遵循 Pod 的生命周期,这意味着整个过程会遵守以下规则:

  • kubectl drain将向控制中心发出删除目标节点上的 Pod 的请求。随后,请求将通知目标节点上的 kubelet 开始关闭 Pod。

  • 节点上的kubelet 将会调用 Pod 里的 preStop 钩子。

  • preStop 钩子执行完成后,节点上的kubelet 会向Pod容器中运行的程序发送 TERM信号 (SIGTERM)。

  • 节点上的kubelet将最多等待指定的宽限期(在pod上指定,或从命令行传入;默认为30秒)然后关闭容器,然后强行终止进程(使用SIGKILL)。注意,这个宽限期包括执行 preStop钩子的时间。

译注:Kubelet 终止Pod前的等待宽限期有两种方式指定

  1. 在Pod定义里通过Pod模板的spec.terminationGracePeriodSeconds 设定

  2. kubectl delete pod {podName} --grace-period=60

基于此流程,我们可以利用应用程序 Pod 中的preStop钩子和信号处理来正常关闭应用程序,以便在最终终止应用程序之前对其进行“清理”。例如,假如有一个工作进程从队列中读取信息然后处理任务,我们可以让应用程序捕获 TERM 系统信号,以指示该应用程序应停止接受新任务,并在所有当前任务完成后停止运行。或者,如果运行的应用程序无法修改以捕获 TERM 信号(例如第三方应用程序),则可以使用preStop钩子来实现该服务提供的自定义API,来正常关闭应用。

在我们的示例中,Nginx 默认情况下不能处理 TERM 信号,因此,我们将改为依靠 Pod 的 preStop钩子实现正常停止Nginx。我们将修改资源定义,将生命周期钩子添加到容器的spec定义中,如下所示:

lifecycle:
  preStop:
    exec:
      command: [
        # Gracefully shutdown nginx
        "/usr/sbin/nginx", "-s", "quit"
      ]

应用此配置后,在将 TERM 信号发送给容器中的Nginx进程之前,kebulet 调用 Pod 的生命周期钩子发出命令 / usr / sbin / nginx -s quit。请注意,由于该命令将会正常停止 Nginx 进程和 Pod,因此 TERM 信号实际上在这个例子中是一个空操作。

在定义文件添加了生命周期钩子后,整个 Deployment 资源的定义变成了下面这样

---
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
        lifecycle:
          preStop:
            exec:
              command: [
                # Gracefully shutdown nginx
                "/usr/sbin/nginx", "-s", "quit"
              ]

停机后的后续流量

使用上面的preStop钩子正常关闭 Pod 可以确保 Nginx 在处理完现存流量有才会停止。但是,你可能会发现,Nginx 容器在关闭后仍会继续接收到流量,从而导致服务出现停机时间。

为了了解造成这个问题的原因,让我们来看一个示例图。假定该节点已接收到来自客户端的流量。应用程序会产生一个工作线程来处理请求。我们用在 Nginx Pod 示例图内的圆圈表示该工作线程。

正在处理请求的Nginx

假设在工作线程处理请求的同时,集群的运维人员决定对 Node1 进行维护。运维运行了kubectl drain node-1 后,节点上的kubelet 会执行 Pod 设置的preStop钩子,开始进入Nginx进程正常关闭的流程。

对节点进行维护,清出节点上的Pod时会先执行preStop钩子

由于 Nginx 仍要处理已存流量的请求,所以进入正常关闭流程后 Nginx 不会马上终止进程,但是会拒绝处理后续到达的流量,向新请求返回错误。

在这个时间点,假设一个新的服务请求到达了 Pod 上层的 Service,因为此时 Pod 仍然是上层 Service 的Endpoint,所以这个即将关闭的 Pod 仍然可能会接收到 Service 分发过来的请求。如果 Pod 真的接收到了分发过来的新请求 Nginx 就会拒绝处理并返回错误。

译注:推荐阅读学练结合快速掌握K8s Service控制器

Nginx处于关闭流程时会拒绝新来的请求

最终 Nginx 将完成对原始已存请求的处理,随后kubelet会删除 Pod,节点完成排空。

Nginx 处理完已存请求后终止进程
Pod停止运行,kubelet删除Pod

为什么会这样呢?如何避免在Pod执行关闭期间接受到来自客户端的请求呢?在本系列的下一部分中,我们会更详细地介绍 Pod 的生命周期,并给出如何在 preStop 钩子中引入延迟为 Pod 进行摘流,以减轻来自 Service 的后续流量的影响。

### 如何安全地重启Kubernetes集群 为了确保Kubernetes集群的安全重启,在虚拟机环境中操作时可以遵循特定指导。当准备就绪,允许Kerberos向导执行其功能,由于这是在一个VM环境下,可以选择“I’m ready to restart the cluster now”的选项并点击“Continue”。此时,系统将开始处理必要的重启流程[^1]。 对于更广泛的环境下的Kubernetes集群重启,建议采取更为谨慎的态度: #### 准备阶段 - **备份配置文件**:在任何更改之前,保存所有重要的配置文件副本。 - **通知相关人员**:提前告知团队成员即将进行的操作,以便他们做好相应安排。 #### 执行重启前的检查 - 验证当前节点状态是否健康; - 确认Pods和服务正常运行无异常情况存在; #### 实施策略 采用滚动更新的方式逐步重启各个节点而不是一次性全部关闭整个集群。这可以通过kubectl命令工具来实现自动化管理过程中的最小化服务中断风险。具体来说就是逐个标记节点不可调度(new nodes as unschedulable),驱逐上面正在运行的工作负载(evict running pods),等待这些资源完全迁移后再实际停止该节点的服务。 ```bash for node in $(kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}') ; do echo "Processing $node" kubectl cordon ${node} kubectl drain ${node} --ignore-daemonsets # Restart kubelet service or reboot the node here. ssh ${node} 'sudo systemctl restart kubelet' kubectl uncordon ${node} done ``` 上述脚本展示了如何遍历每一个节点,并对其进行如下操作: - 使用`cordon`指令防止新的pod被分配到此节点上, - 利用`drain`命令优雅地移除现有的pods(忽略DaemonSet管理的实例), - 对于每台机器上的kubelet服务实施重启或是直接重启动作, - 完成之后再通过`uncordon`恢复节点可调度的状态。 这种做法能够有效减少因突然断电或其他突发状况带来的负面影响,同时也使得维护工作更加灵活可控。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值