Kubernetes优雅停止Pod

原文:https://i4t.com/4424.html



首先我们先简单的分析一下"优雅的停止Pod"

优雅停止(Graceful shutdown)这个说法来自于操作系统,比如我们windows关机系统首先会退出软件然后一步步到达关机,而相对的就是硬终止(Hard shutdown),简单的理解就是直接拔电源

到了微服务中,网关会把流量分配给每个Pod节点上,比如我们上线更新Pod的时候

  • 如果我们直接将Pod杀死,那这部分流量就无法得到正确处理,会影响部分用户,通常来说网关或者注册中心会将我们的服务保持一个心跳,过了心跳超时之后会自动摘除我们的服务,但是有一个问题就是超时时间可能是30秒也可能是60秒,虽然不会影响我们的系统,但是会产生用户轻微抖动。
  • 如果我们在停止前执行一条命令,通知网关或者注册中心这台主机进行下线,那么注册中心就会标记这台主机已经下线,不进行流量转发,用户就不会有任何影响,这就是优雅停止,将滚动更新影响最小化

Pod Hook

Pod Hook是由kubelet发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。我们可以同时为Pod中的所有容器都配置hook

在k8s中,理想的状态是pod优雅释放,并产生新的Pod。但是并不是每一个Pod都会这么顺利

  • Pod卡死,处理不了优雅退出的命令或者操作
  • 优雅退出的逻辑有BUG,陷入死循环
  • 代码问题,导致执行的命令没有效果

对于以上问题,k8s的Pod终止流程中还有一个"最多可以容忍的时间",即grace period (在pod的.spec.terminationGracePeriodSeconds字段定义),这个值默认是30秒,当我们执行kubectl delete的时候也可以通过--grace-period参数显示指定一个优雅退出时间来覆盖Pod中的配置,如果我们配置的grace period超过时间之后,k8s就只能选择强制kill Pod



Kubernetes为我们提供了两种钩子函数:

  • PostStart :这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。 主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费时间过长以及于不能运行或者挂起,容器将不能达到Running状态。
  • PreStop :钩子在容器终止前立即被调用。它是阻塞的,意味着它是同步的,所以它必须在删除容器的调用出发之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起,Pod阶段将停留在Running状态并且不会达到failed状态

如果PostStart或者PreStop钩子失败,它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的,比如在停止容器之前预先保留状态。

这里稍微简单说一下Pod终止的过程

  • 用户发送命令删除Pod,Pod进入Terminating状态
  • service摘除Pod节点
  • 当kubelet看到Pod已被标记终止,开始执行preStop钩子,假如preStop hook的运行时间超过了grace period,kubelet会发送SIGTERM并等2秒
    官方文档介绍

在Pod Hook钩子函数中有Exec和HTTP两种方式

  • Exec - 用于执行一段特定的命令,不过要注意的是该命令小号的资源会被计入容器
  • HTTP - 对容器上的特定端点执行HTTP请求

基于PostStart命令演示

首先我们先进行演示PostStart的两种方式

第一种Exec
我们echo一段话追加到 /tmp/message,在Pod启动前进行操作

cat >>exec_test.yaml<<EOF
apiVersion: v1
kind: Pod
metadata:
  name: abcdocker
  labels:
    name: abcdocker
spec:
  containers:
  - name: abcdocker
    image: nginx
    ports:
      - containerPort: 80
    lifecycle:
      postStart:
        exec:
          command:
          - bash
          - -c
          - ‘echo "https://i4t.com" > /tmp/message‘
EOF

使用kubectl apply -f exec_test.yaml进行创建

可以通过下面查看结果,pod的目录已经有我们在yaml文件写的测试文件

[[email protected] yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
abcdocker   1/1     Running   0          37s

[[email protected] yaml]# kubectl exec -it -n default abcdocker /bin/bash
[email protected]:/# cat /tmp/message
https://i4t.com
[email protected]:/#
[email protected]:/# exit

创建容器后,Kubernetes立即发送postStart事件。但是,不能保证在调用Container的入口点之前先调用postStart处理程序。postStart处理程序相对于Container的代码异步运行,但是Kubernetes对容器的管理会阻塞,直到postStart处理程序完成。在postStart处理程序完成之前,容器的状态不会设置为RUNNING。

第二种HTTP方式
使用HttpGet配置Host、Path、Port

apiVersion: v1
kind: Pod
metadata:
  name: abcdocker
  labels:
    name: abcdocker
spec:
  containers:
  - name: abcdocker
    image: nginx
    ports:
      - containerPort: 80
    lifecycle:
      postStart:
        httpGet:
          host: i4t.com
          path: index.html
          port: 80

这里就不进行演示了,因为日志会看不到这个请求


基于PreStop环境演示

起因:
在生产环境中使用spring框架,由于服务更新过程中,服务容器被直接充值,部分请求仍被分发到终止的容器(没有配置钩子,熟悉默认环境),导致服务出现500错误,这部分错误请求数据占用比较少,因为Pod滚动更新都是一对一。因为部分用户会产生服务器错误的情况,考虑使用优雅的终止方式,将错误请求降到最低,直至滚动更新不影响用户

Eureka是一个基于REST的服务,作为Spring Cloud服务注册中心,用于定位服务来进行中间层服务器的负载均衡和故障转移。各服务启动时,会向Eureka Server注册自己的信息(IP、端口、服务信息等),Eureka Server会存储这些信息,微服务启动后,会周期性(默认30秒)的向Eureka Server发送心跳以续约自己的租期,并且可以从eureka中获取其他微服务的地址信息,执行相关逻辑

由于Eureka默认的心跳检测为30秒,当K8S下线Pod时Eureka会有30秒的异常问题,所以我们需要在Pod 停止前发送一条请求,通知Eureka进行下线操作,这样进行优雅的停止对用户的影响做到最小

具体yaml如下

apiVersion: v1
kind: Pod
metadata:
  name: abcdocker
  labels:
    name: abcdocker
spec:
  containers:
  - name: abcdocker
    image: nginx
    ports:
      - containerPort: 80
    lifecycle:
      preStop:
        exec:
          command:
            - bash
            - -c
            - ‘curl -X POST --data DOWN http://127.0.0.1:8080/service-registry/instance-status  -H
              "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8";sleep 30‘

####### 参数解释
127.0.0.1:8080 #代表eureka地址
service-registry    #代表注册中心
DOWN        #执行down请求
sleep       #等待30秒

当我们删除Pod的时候就会执行上面的命令操作,并且等待30秒

[[email protected] yaml]# kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
abcdocker   1/1     Running   0          2m16s
[[email protected] yaml]# kubectl delete pod abcdocker
pod "abcdocker" deleted

#此刻Pod不会马上删除,而是执行Exec中的命令,并等待30秒

配置中添加了一个sleep时间,主要是作为服务停止的缓冲时间

总结: Hook调用的日志没有暴露给Pod的Event,所以只能到通过describe命令来获取,如果是正常的操作是不会有event,如果有错误可以看到FailedPostStartHook和FailedPreStopHook这种event。并且如果Hook调用出现错误,则Pod状态不会是Running

原文地址:https://blog.51cto.com/abcdocker/2450082

时间: 2024-10-08 04:20:26

Kubernetes优雅停止Pod的相关文章

Docker Kubernetes 创建管理 Pod

Docker Kubernetes 容器扩容与缩容 环境: 系统:Centos 7.4 x64 Docker版本:18.09.0 Kubernetes版本:v1.8 管理节点:192.168.1.79 工作节点:192.168.1.78 工作节点:192.168.1.77 管理节点:创建pod yaml文件 vim pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-test labels: os: centos spec: contain

Kubernetes对象之Pod

系列目录 Pod是Kubernetes调度的最小单元.一个Pod可以包含一个或多个容器,因此它可以被看作是内部容器的逻辑宿主机.Pod的设计理念是为了支持多个容器在一个Pod中共享网络和文件系统 因此处于一个Pod中的多个容器共享以下资源: PID命名空间:Pod中不同的应用程序可以看到其他应用程序的进程ID. network命名空间:Pod中多个容器处于同一个网络命名空间,因此能够访问的IP和端口范围都是相同的.也可以通过localhost相互访问. IPC命名空间:Pod中的多个容器共享In

Kubernetes — 深入解析Pod对象:基本概念(一)

在上一篇文章中,我详细介绍了 Pod 这个 Kubernetes 项目中最重要的概念. 现在,你已经非常清楚:Pod,而不是容器,才是 Kubernetes 项目中的最小编排单位.将这个设计落实到 API 对象上,容器(Container)就成了 Pod 属性里的一个普通的字段.那么,一个很自然的问题就是:到底哪些属性属于 Pod 对象,而又有哪些属性属于 Container 呢? 要彻底理解这个问题,你就一定要牢记我在上一篇文章中提到的一个结论:Pod 扮演的是传统部署环境里“虚拟机”的角色.

kubernetes基本概念 pod, service

k8s的部署架构 kubernetes中有两类资源,分别是master和nodes,master和nodes上跑的服务如下图, kube-apiserver | kubelet kube-controller-manager | kube-scheduler | kube-proxy ---------------------- -------------------- k8s master node (non-master) master:负责管理整个集群,例如,对应用进行调度(扩缩).维护应

Kubernetes对象之Pod详解(附安装部署方法)

首先介绍一下K8S是什么:(引用自K8S中文社区) Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署.自动扩缩容.维护等功能. 通过Kubernetes你可以: 快速部署应用 快速扩展应用 无缝对接新的应用功能 节省资源,优化硬件资源的使用 其实K8S能够做的事情有很多,而且操作简单,十分方便,下面先介绍如何安装,然后是对于pod详细介绍,如果你对docker还不怎么了解,可以先参考前面的文章学习一下! 环境介绍: CentOS 7.2 Kubernetes

kubernetes中的Pod简述与实践

Pod的概念详细的Pod解释可参考k8s官网,关于Pod的概念主要有以下几点:(1)Pod是kubernetes中你可以创建和部署的最小也是最简的单位.一个Pod代表着集群中运行的一个进程:(2)在Kubrenetes集群中Pod的使用方式:(3)Pod中如何管理多个容器 理解Pod上面已经说了"Pod是kubernetes中你可以创建和部署的最小也是最简的单位.一个Pod代表着集群中运行的一个进程."Pod中封装着应用的容器(有的情况下是好几个容器),存储.独立的网络IP,管理容器如

kubernetes 实践之Pod

首先看一个例子,Guestbook,对k8s对于容器应用的基本操作和用法进行理解,本例通过pod .RC.Service等资源对象创建完成,架构图: ①.创建redis-master的RC和Service [[email protected]_master php-redis]# cat redis-master-controller-RC.yaml apiVersion: v1 kind: ReplicationController metadata: name: redis-master #

kubernetes 无法删除 pod 问题的解决

[摘要] kubernetes 可能会产生垃圾或者僵尸pod,在删除rc的时候,相应的pod没有被删除,手动删除pod后会自动重新创建,这时一般需要先删除掉相关联的resources,实际中还要具体情况具体分析. 在使用Helm部署gitlab的时候发现有垃圾的pod存在,一直删除不掉 # kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE gitlab-migrations.1-2km-4rwnm 1/1 Running

Springboot 优雅停止服务的几种方法

在使用Springboot的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭.而且一些没有执行完的程序就会直接退出. 我们很多时候都需要安全的将服务停止,也就是把没有处理完的工作继续处理完成.比如停止一些依赖的服务,输出一些日志,发一些信号给其他的应用系统,这个在保证系统的高可用是非常有必要的.那么咱么就来看一下几种停止springboot的方法. 第一种就是Springboot提供的actuator的功能,它