一文读懂 Kubernetes 是如何调度 Pod 的
bigegpt 2024-10-26 08:18 16 浏览
随着云原生的不断发展,kubernetes 在我们的应用场景中越来越重要。
对于用过 kubernetes 的小伙伴都知道, Pod 是一组容器的集合,这些容器共享网络、UTS、命名空间,并且可以直接进行通信。
如果是 Pod 与 Pod 之间的通信 还得考虑是同一节点内的还是不同节点的,这个就不展开聊了,今天主要跟大家讨论下Pod的调度问题。
我们都知道 kubernetes 中 Pod可以通过设置Label、指定节点、设置亲和/反亲和等方式来进行调度,那么Pod调度的细节是什么样的?Pod的生命周期kubernetes是如何感知的?
Pod 相位
在介绍Pod 创建流程之前,我们先看一下Pod的相位状态,主要有5种。
- Pending:API Server 创建了Pod资源对象并已存入etcd 中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。
- Running:Pod 已经被调度至某节点,并且所有容器都已经被 kubelet创建完成。
- Succeeded:Pod 中的所有容器都已经成功终止并且不会被重启。
- Failed:所有容器都已经终止,但至少有一个容器终止失败,退出状态或已经被系统终止。
- Unknown:API Server无法正常获取到Pod对象的状态信息,通常是由于其无法与所在工作节点的kubelet通信所致。
Pod 创建
我们可以从下图中很直观地看出 Pod 的一个创建流程。
- 用户通过 kubectl 或其他API客户端提交 Pod Spec 给 API Server。
- API Server 尝试着将Pod对象的相关信息存入 etcd 中,待写入操作执行完成,API Server即会返回确认信息至客户端。
- API Server 开始反映 etcd 中的状态变化。
- 所有的Kubernetes组件均使用“watch”机制来跟踪检查API Server上的相关变动。
- kube-scheduler(调度器)通过其“watcher”觉察到API Server创建了新的Pod对象但尚未绑定至任何工作节点。
- kube-scheduler 为Pod对象挑选一个工作节点并将结果信息更新至API Server。
- 调度结果信息由API Server更新至 etcd 存储系统,而且 API Server 也开始反映此Pod对象的调度结果。
- Pod 被调度到的目标工作节点上的 kubelet (watch到了)尝试在当前节点上调用Docker启动容器,并将容器的结果状态回送至 API Server。
- API Server 将 Pod 状态信息存入 etcd 系统中。
- 在etcd 确认写入操作成功完成后,API Server 将确认信息发送至相关的 kubelet,事件将通过它被接受。
其中创建流程第6步骤,kube-scheduler 通过Label、NodeName、Affinity(亲和性),并结合Pod的requests、limits以及节点的kubelet 设置来判断将 Pod 调度到哪一个Node 上。
我们从流程中还可以看出来,最核心的就是 Apiserver 的watch机制(实际是Etcd的watch),Scheduler 以及kubelet 都是通过 watch 机制去感知 Pod 的调度情况的。
这时就有小伙伴问了,kubernetes 控制面组件中的 kube-contreller-manager 怎么没有在流程中体现呢?
因为 kube-contreller-manager 包含了很多的控制器,管理的是更高级的一些资源对象。比如Deployment、StatefullSet、DaemonSet等等,如果 Pod 是通过这些对象去创建的话,这个时候kube-contreller-manager 派上用场了,它也会通过 watch 资源对象的的最新状态,并不断进行调谐从而达到用户(yaml)所期望的 Pod 状态。
Pod 终止
我们再来说下 Pod 的终止流程。
- 用户发送删除Pod对象的命令。
- API 服务器中的Pod对象会随着时间的推移而更新,在宽限期内(默认为30秒),Pod被视为“dead”。
- 将Pod标记为“Terminating”状态。
- (与第 3 步同时运行)kubelet在监控到Pod对象转为“Terminating”状态的同时启动Pod关闭过程。
- (与第 3 步同时运行)端点控制器监控到Pod对象的关闭行为时将其从所有匹配到此端点的Service资源的端点列表中移除。
- 如果当前Pod对象定义了preStop钩子处理器,则在其标记为“terminating”后即会以同步的方式启动执行;如若宽限期结束后,preStop仍未执行结束,则第2步会被重新执行并额外获取一个时长为2秒的小宽限期。
- Pod对象中的容器进程收到TERM信号。
- 宽限期结束后,若存在任何一个仍在运行的进程,那么Pod对象 即会收到SIGKILL信号。
- Kubelet请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,它变得对用户不再可见 。
钩子函数
在终止流程中,kubelet 会执行 preStop 钩子函数,该函数常常用于让容器中的服务优雅地关闭或者是通知其他服务等场景。
同样的,可以在 Pod 中设置 preStop 钩子函数之,还可以设置 postStart 函数,该函数将于容器创建后立即运行,常常用于一些服务组件注册、环境部署等。
除了 钩子函数,Pod 的生命周期中还有其他一些重要行为,比如 初始化容器(init container )与 探针。
初始化容器
即应用程序 的主容器启动之前要运行的容器,常用于为主容器执行一些预置操作。
比如初始化配置,将pod或者主容器注册到配置中心等。
容器探测
探针主要分类三种,分别是livenessProbe、readinessProbe与startupProbe,其中 startupProbe 是在1.16版本后加的探针方式。
- livenessProbe,用于判定容器是否处于“运行”( Running )状态。
livenessProbe检测未通过,kubelet 将杀死容器并根据其 restartPolicy 决定是否将其重启。
- readinessProbe,用于判断容器是否准备就绪并可对外提供服务。
readinessProbe未通过检测的容器意味着其尚未准备就绪,端点控制器(如Service 对象)会将其IP从所有匹配到此Pod对象的Service对象的端点列表中移除。
- startupProbe,用于判断容器中的应用是否已经启动。
startupProbe 如果设置了,则在此探针成功之前,其他探针都会被禁用。
资源需求与限制
- requests:资源定义的确保可用值,即容器运行可能用不到这些额度的资源,但用到时必须要确保有如此多的资源可用。
- limits:用于限制资源可用的最大值。
Pod 中可以对container 进行 requests 和 limits 的设置。通过这两个资源参数进行内存或者CPU的限制,从而达到对容器资源消耗的控制。示例如下:
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
上述提到 kube-scheduler 在选择节点进行 Pod 调度跟 Pod 的 requests 与 limits 也有关系,为什么呢?
试想下,如果在进行 Pod 调度的时候不考虑这个因素,那么一个节点上的Pod 资源上限总和可能会超出节点的资源总量,从而会干扰业务的正常运行。
如果某一个节点上 Pod 资源总和已达到上限,刚刚好又调度了一个 Pod 到该节点,此时会出现什么情况呢?
这个时候就不得不提到 QOS 了。
pod服务质量类别,即 QOS(Quality of Service)。在内存资源紧缺时,应该以何种次序先后终止哪些Pod对象?Kubemetes无法自行对此做出决策,它需要借助于 Pod 对象的优先级完成判定。根据 Pod 对象的 requests 和 limits 属性,Kubemetes 将 Pod 对象归类到 BestEffort 、 Burstable 和 Guaranteed 三个服务质量。
- Guaranteed:每个容器都为CPU资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的Pod资源会自动归属于此类别,这类Pod资源具有最高优先级。
- Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别要求的Pod资源将自动归属于此类别,它们具有中等优先级。
- BestEffort:未为任何一个容器设置requests或limits属性的Pod资源将自动归属于此类别,它们的优先级为最低级别。
对于QOS 如何打分,大家可以在源码中kubernetes/pkg/apis/core/v1/helper/qos/qos.go 开始看起。
参考资料
https://kubernetes.io/
往期推荐
相关推荐
- Docker篇(二):Docker实战,命令解析
-
大家好,我是杰哥上周我们通过几个问题,让大家对于Docker有了一个全局的认识。然而,说跟练往往是两个概念。从学习的角度来说,理论知识的学习,往往只是第一步,只有经过实战,才能真正掌握一门技术所以,本...
- docker学习笔记——安装和基本操作
-
今天学习了docker的基本知识,记录一下docker的安装步骤和基本命令(以CentOS7.x为例)一、安装docker的步骤:1.yuminstall-yyum-utils2.yum-con...
- 不可错过的Docker完整笔记(dockerhib)
-
简介一、Docker简介Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,...
- 扔掉运营商的 IPTV 机顶盒,全屋全设备畅看 IPTV!
-
其实现在看电视节目的需求确实大大降低了,折腾也只是为了单纯的让它实现,享受这个过程带来的快乐而已,哈哈!预期构想家里所有设备直接接入网络随时接收并播放IPTV直播(电信点播的节目不是太多,但好在非常稳...
- 第五节 Docker 入门实践:从 Hello World 到容器操作
-
一、Docker容器基础运行(一)单次命令执行通过dockerrun命令可以直接在容器中执行指定命令,这是体验Docker最快捷的方式:#在ubuntu:15.10容器中执行ech...
- 替代Docker build的Buildah简单介绍
-
Buildah是用于通过较低级别的coreutils接口构建OCI兼容镜像的工具。与Podman相似,Buildah不依赖于Docker或CRI-O之类的守护程序,并且不需要root特权。Builda...
- Docker 命令大全(docker命令大全记录表)
-
容器生命周期管理run-创建并启动一个新的容器。start/stop/restart-这些命令主要用于启动、停止和重启容器。kill-立即终止一个或多个正在运行的容器rm-于删除一个或...
- docker常用指令及安装rabbitMQ(docker安装rabbitmq配置环境)
-
一、docker常用指令启动docker:systemctlstartdocker停止docker:systemctlstopdocker重启docker:systemctlrestart...
- 使用Docker快速部署Storm环境(docker部署confluence)
-
Storm的部署虽然不是特别麻烦,但是在生产环境中,为了提高部署效率,方便管理维护,使用Docker来统一管理部署是一个不错的选择。下面是我开源的一个新的项目,一个配置好了storm与mono环境的D...
- Docker Desktop安装使用指南:零基础教程
-
在之前的文章中,我多次提到使用Docker来安装各类软件,尤其是开源软件应用。鉴于不少读者对此有需求,我决定专门制作一期关于Docker安装与使用的详细教程。我主要以Macbook(Mac平台)为例进...
- Linux如何成功地离线安装docker(linux离线安装httpd)
-
系统环境:Redhat7.2和Centos7.4实测成功近期因项目需要用docker,所以记录一些相关知识,由于生产环境是不能直接连接互联网,尝试在linux中离线安装docker。步骤1.下载...
- Docker 类面试题(常见问题)(docker面试题目)
-
Docker常见问题汇总镜像相关1、如何批量清理临时镜像文件?可以使用sudodockerrmi$(sudodockerimages-q-fdanging=true)命令2、如何查看...
- 面试官:你知道Dubbo怎么优雅上下线的吗?你:优雅上下线是啥?
-
最近无论是校招还是社招,都进行的如火如荼,我也承担了很多的面试工作,在一次面试过程中,和候选人聊了一些关于Dubbo的知识。Dubbo是一个比较著名的RPC框架,很多人对于他的一些网络通信、通信协议、...
- 【Docker 新手入门指南】第五章:Hello Word
-
适合人群:完全零基础新手|学习目标:30分钟掌握Docker核心操作一、准备工作:先确认是否安装成功打开终端(Windows用户用PowerShell或GitBash),输入:docker--...
- 松勤软件测试:详解Docker,如何用portainer管理Docker容器
-
镜像管理搜索镜像dockersearch镜像名称拉取镜像dockerpullname[:tag]列出镜像dockerimages删除镜像dockerrmiimage名称或id删除...
- 一周热门
- 最近发表
-
- Docker篇(二):Docker实战,命令解析
- docker学习笔记——安装和基本操作
- 不可错过的Docker完整笔记(dockerhib)
- 扔掉运营商的 IPTV 机顶盒,全屋全设备畅看 IPTV!
- 第五节 Docker 入门实践:从 Hello World 到容器操作
- 替代Docker build的Buildah简单介绍
- Docker 命令大全(docker命令大全记录表)
- docker常用指令及安装rabbitMQ(docker安装rabbitmq配置环境)
- 使用Docker快速部署Storm环境(docker部署confluence)
- Docker Desktop安装使用指南:零基础教程
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)