0

我们一起聊聊容器资源自愈

 7 months ago
source link: https://www.51cto.com/article/780662.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我们一起聊聊容器资源自愈

作者:安禹潼 2024-01-30 09:14:35
在企业实际在使用容器这类资源的时候,除了技术本身,要考虑的其他问题也会很多。企业管理的容器有千千万万,出于效率考虑,对于有特殊需求的容器如何进行批量创建和管理呢,这就需要在统一管理平台按照相应的模板进行创建与维护。

容器作为一种新的资源类型,已经应用于各大公司,G行也不例外。容器的轻量化特性使得它能够在故障发生时快速进行重建,将对业务的影响降到最低,我们通常称它为自愈。在Kubernetes中,自动重建的逻辑是什么?为什么我们经常说到Pod自愈而不是容器自愈?如何判定Pod状态,Pod都有什么状态?重启策略都有什么,是什么推动重启?对于不同的重启资源需求,G行如何实现?下文将一一讲述。

图1   Kubernetes架构
图1 Kubernetes架构

一、容器自愈

谈到容器自愈,为什么说是通过Pod自愈实现的呢?Pod是一组(一个或多个)容器,这些容器共享Pod的存储、网络、以及运行容器的声明。且Pod是K8s(即Kubernetes)的最小部署管理计算单元。K8s是CNCF(Cloud Native Computing Foundation)的毕业项目之一,是目前市场使用最广泛的自动化部署、扩展和管理成千上万容器化应用程序的开源系统,也是G行采用的容器管理工具。Pod运行在被称作是Node的节点中,节点既可以是物理机,也可以是虚拟机。当K8s判定Pod出现问题且需要被杀死的时候,会在运转正常且资源充足的Node节点重建完成,从而完成自愈。

图2 CNCF的毕业项目和孵化中的项目
图2 CNCF的毕业项目和孵化中的项目

二、Pod状态判定

应用程序可能因多种原因而变得不可靠,例如:暂时失联、配置错误、应用程序错误、硬件故障、资源紧张等。那么如何检测运行着应用程序的pod健康状态是好还是坏呢,K8s是通过探针来检查的,探针有三种:ReadinessProbe、StartupProbe及LivenessProbe。

 ReadinessProbe(就绪)探针:用于判断容器服务是否可用(即是否为ready状态),只有Ready状态的Pod才可以接收服务请求。

StartupProbe(启动)探针:适用于应用程序启动缓慢、网络访问延迟等场景,相应造成容器启动缓慢的情况。

LivenessProbe(存活)探针:用于判断容器是否存活①(即是否为running状态),如果探针检测到容器不健康,则Kubelet将杀死这个容器,并根据容器的重启策略(重启策略后面会说)做相应的处理。

G行通过同时使用ReadinessProbe(就绪)探针和LivenessProbe(存活)探针来判定Pod的状态。

K8s提供了5个控制这些探针的选项:

图片
图片

而这三种探针均可以通过以下三种方式②实现:

01HTTPGetAction

通过容器的IP地址、端口号及路径调用http get方法,如果相应的状态码大于等于200且小于400,则认定容器是健康状态。

02TCPSocketAction

通过容器的IP地址和端口号执行tcp检查,如果能够建立tcp连接,则表明容器健康。

03ExecAction

在容器内部运行一个命令,如果返回码为0,则表示容器健康,否则表示不健康。

 G行使用HTTPGetAction和TCPSocketAction两种方式查看连接情况。

运维人员可以使用Kubectl命令行客户端或Yaml部署模板来配置探针和IP地址、端口号、路径连接方式。下面是以LivenessProbe探针、HTTPGetAction连接方式为例,编写的Yaml文件:

图片
图片

03Pod重启策略

知道如何检查Pod的健康状态了,如果不健康,该如何进行重启呢?这里就需要说到Pod的重启策略(restartPolicy)了。

重启策略应用于Pod内的所有容器,由Pod所处的Node上的Kubelet进行判断和重启操作。当某个容器异常退出或者健康检查失败时,Kubelet会根据重启策略的设置进行相应的操作。

Pod的重启策略有Always、OnFailure、Never三种,Default为Always。

Always:当容器失效时,由Kubelet自动重启该容器

OnFailure:当容器终止运行且退出码不为0时,由Kubelet自动重启该容器。

Never:不论容器运行状态如何,Kubelet都不会重启该容器。

图3  示例Pod在G行Prometheus的可视化平台Grafana上的重启情况,红线为阈值
图3 示例Pod在G行Prometheus的可视化平台Grafana上的重启情况,红线为阈值

Pod如何重启

重启策略明确了,那么是靠谁来完成重启的呢?是靠控制器来实现的。

在讲述控制器之前,先考虑这样一个场景:Pod没有副本,如果这个Pod出现问题,上面跑的容器应用也就无法运转了,服务也就中断了。所以在K8s中,在创Pod之初,就是以多副本的形式创建的。这种负责Pod副本的创建、Pod重启、调度及全生命周期自动控制的组件叫做控制器(也叫工作负载,即workload)。

控制器根据不同的功能分为Replicaset与Deployment、 DaemonSet、StatefulSet、Job和Cronjob几种。这几种控制器G行都有使用,并且在G行自建的容器统一管理平台进行了部署。这个平台融合管理了云上所有的应用相关容器资源,提高了运维效率。

图4 G行容器统一管理平台登录首页
图4 G行容器统一管理平台登录首页

Replicaset与Deployment  

图片
图片

图5   Deployment控制器下两种Pod滚动升级方式,分别是Recreate和Rolling update,各适用于大版本和小版本

 ReplicaSet(简称rs)是Replication Controller的升级版,是副本集的意思,用于保证K8s集群中有指定数量的Pods副本在运行③。一般不单独使用,而是作为Deployment理想状态的参数使用。且拥有集合式的标签选择器,可以选择多个标签。    

Deployment被称作是副本控制集(即rs)的控制器,通过为应用程序创建一个或多个rs以管理应用程序的多个版本。通过每个副本控制集(rs)的模板和副本保持的能力来管理无状态应用的工作负载(应用程序集群),比如web集群。

DaemonSet

图6  展示了DaemonSet这种类型的控制器的Pods部署
图6 展示了DaemonSet这种类型的控制器的Pods部署

DaemonSet是特殊类型的Deployment,在集群中的全部或者部分节点上,每个节点上有且仅有一份Pod的副本资源在运行。比如系统的监控、日志的收集、分布式存储、网络的代理等,都需要每个成员节点上有且只有一个Pod。例如:每个Node上只需要运行一个日志采集程序Logstach,或者只运行一个性能监控程序Prometheus Node Exporter。

而且后续加入集群的新的节点也会自动创建一个相同的Pod对象。管理员也可以使用Nodeselector(节点选择器)配合节点Label指定仅在部分具有特定特征的节点上运行指定的Pod对象。

StatefulSet

图7   有状态集在一个Pod故障被杀死,并重建新Pod的情况
图7 有状态集在一个Pod故障被杀死,并重建新Pod的情况

用来管理有状态应用的工作负载(应用程序集群),管理Pods集合的部署和伸缩,并为这些Pods提供持久存储和持久标识符。与Depolyment类似,Statefulset管理基于相同容器模板的一组Pods。但与Depolyment不同的是,Statefulset为每个Pod维护了一个有粘性的ID。这些Pods是基于相同的模板,但是不能相互替换,即无论怎么调度,每个Pod都有一个永久不变的ID。

Job和Cronjob

图8  Job和Cronjob在完成工作后回收算力的场景展示
图8 Job和Cronjob在完成工作后回收算力的场景展示

Job是用来定义并启动一个批处理任务,是单次性作业控制器。这任务通常并行或者串行启动多个计算进程去处理一批工作项,即work item,工作项处理完成后,整个批处理任务结束。比如Hadoop的离线数据处理、视频解码、或者HPC业务等,都需要很多个节点提供一个集中式的大算力。与传统算力相比,Job控制器能在保留结果的同时,快速回收算力,因为一个Job完成后,就会立即杀死使用的Pod。

 Cronjob控制器用于周期性调度Job控制器。传统环境使用的一般用到的是7*24小时不间断的备份服务器,现在可以使用Cronjob控制器周期性的起一个Job作业,做完后,保留结果,杀死Pod,回收算力。Cronjob基本照搬了Linux操作系统的周期性任务Crontab,用minutes、hours、dayofmonth、month、dayofweek来进行定义。

需要注意,一些控制器对Pod的重启策略要求,G行也是按如下执行的:

Replicaset或者DaemonSet:必须设置为always,需要保证该容器持续运行。

 Job:onFailure或Never,确保容器执行完成后不再重启。

特定场景的Pod重启

Pod对Node有特定要求的场景:

Node节点的配置是多种类型的,比如有的安装了SSD磁盘,有的没有。有的是AMD64的,有的是AMD32的。如果想着把新建的Pod运行在AMD64的Node上,该怎么做呢。下面是Pod的Yaml配置:

图片
图片

Pod之间相互依存或者互斥的场景:

     现在想新建这么两个Pod,有互相依存关系,需要放到同一个Region内,该如何实现呢。像这种互为亲和或者互斥关系的Pod是通过在Yaml文件中增加TopologyKey属性,来声明目标拓扑内的Pod是否在一起的。下面是一个亲和的例子,目标Pod的标签值是APP:”Nginx”。亲和Pod的标签值也是一样。增加的TopologyKey值为topology.kubernetes.io/region,意味着这两个Pod给配置到了同一个Region下。

图片
图片

 这些相互依赖或者相互之间频繁调用的Pod,需要尽可能的部署在同一个Zone、机房、机架、Node节点。反之,就需要让这些Pod尽可能的互相远离。简而言之,就是Pod之间在同一个拓扑域中共存或互斥。拓扑域指由相同地理空间中的几个Node节点组成。

一些常规的拓扑域有:

kubernetes.io/hostname;topology.kubernetes.io/region;topology.kubernetes.io/zone。

在企业实际在使用容器这类资源的时候,除了技术本身,要考虑的其他问题也会很多。企业管理的容器有千千万万,出于效率考虑,对于有特殊需求的容器如何进行批量创建和管理呢,这就需要在统一管理平台按照相应的模板进行创建与维护。在Pod进行重建后,如何保证客户端应用屏蔽这些Pod IP地址的变化及数量的变化呢,这就需要通过定义Pod上层的Service进行保障。不同的应用系统有自身的架构特点,在进行控制器配置的时候如何进行考量呢,需要选择哪种控制器呢,这就需要进行交付前的资源配置梳理。等等问题。总之,在考虑到基本的技术特性的同时,再应用系统自身特点相结合,才能够将技术的最大价值加以发挥。

① 容器的状态一共有五个:created(已创建)、running(运行中)、paused(暂停)、exited(停止)、dead(死亡)、restarted(重启中)、removing(迁移中)。②每种探测方式,还需要额外设置initialDelaySeconds和timeoutSeconds这两个参数。initialDelaySeconds表示容器启动后进行首次健康检查的等待时间,单位是秒。timeoutSeconds表示健康检查请求发送后等待响应的超时时间,单位是秒。如果超时,则Kubelet认为容器无法提供服务,会重启该容器。③例如:Pod所在节点发生宕机,K8s就会第一时间观察到这个故障,并自动创建一个新Pod对象,将其调度到其他合适的节点上,K8s会实时监控集群中目标Pod的副本数量,并尽力与Deployment中声明的Replicas数量保持一致。

责任编辑:武晓燕 来源: 匠心独运维妙维效

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK