Kubernetes 笔记(15)— 应用保障、容器资源配额、容器状态探针概念及使用

news2024/9/19 10:40:40

作为 Kubernetes 里的核心概念和原子调度单位,Pod 的主要职责是管理容器,以逻辑主机、容器集合、进程组的形式来代表应用,它的重要性是不言而喻的。

在上层 API 对象的基础上,一起来看看在 Kubernetes 里配置 Pod 的两种方法:资源配额 Resources、检查探针 Probe,它们能够给 Pod 添加各种运行保障,让应用运行得更健康。

1. 容器资源配额

前面我们提到创建容器有三大隔离技术:namespacecgroupchroot。其中的 namespace 实现了独立的进程空间,chroot 实现了独立的文件系统,但唯独没有看到 cgroup 的具体应用。

cgroup 的作用是管控 CPU、内存,保证容器不会无节制地占用基础资源,进而影响到系统里的其他应用。

不过,容器总是要使用 CPU 和内存的,该怎么处理好需求与限制这两者之间的关系呢?

Kubernetes 的做法与 PersistentVolumeClaim 用法有些类似,就是容器需要先提出一个“书面申请”,Kubernetes 再依据这个“申请”决定资源是否分配和如何分配。

但是 CPU、内存与存储卷有明显的不同,因为它是直接“内置”在系统里的,不像硬盘那样需要“外挂”,所以申请和管理的过程也就会简单很多。

具体的申请方法很简单,只要在 Pod 容器的描述部分添加一个新字段 resources 就可以了,它就相当于申请资源的 Claim


apiVersion: v1
kind: Pod
metadata:
  name: ngx-pod-resources

spec:
  containers:
  - image: nginx:alpine
    name: ngx

    resources:
      requests:
        cpu: 10m
        memory: 100Mi
      limits:
        cpu: 20m
        memory: 200Mi

这个 YAML 文件定义了一个 Nginx Pod,我们需要重点学习的是 containers.resources,它下面有两个字段:

  • requests意思是容器要申请的资源,也就是说要求 Kubernetes 在创建 Pod 的时候必须分配这里列出的资源,否则容器就无法运行。
  • limits 意思是容器使用资源的上限,不能超过设定值,否则就有可能被强制停止运行。

在请求 cpumemory 这两种资源的时候,你需要特别注意它们的表示方式。

内存的写法和磁盘容量一样,使用 KiMiGi 来表示 KBMBGB,比如 512Ki、100Mi、0.5Gi 等。
CPU 因为在计算机中数量有限,非常宝贵,所以 Kubernetes 允许容器精细分割 CPU,即可以 1 个、2 个地完整使用 CPU,也可以用小数 0.1、0.2 的方式来部分使用 CPU。这其实是效仿了 UNIX“时间片”的用法,意思是进程最多可以占用多少 CPU 时间。

不过 CPU 时间也不能无限分割,KubernetesCPU 的最小使用单位是 0.001,为了方便表示用了一个特别的单位 m,也就是 milli“毫”的意思,比如说 500m 就相当于 0.5。

现在我们再来看这个 YAML,你就应该明白了,它向系统申请的是 1% 的 CPU 时间和 100MB 的内存,运行时的资源上限是 2%CPU 时间和 200MB 内存。有了这个申请,Kubernetes 就会在集群中查找最符合这个资源要求的节点去运行 Pod

下面是我在网上找的一张动图,Kubernetes 会根据每个 Pod 声明的需求,像搭积木或者玩俄罗斯方块一样,把节点尽量“塞满”,充分利用每个节点的资源,让集群的效益最大化。

你可能会有疑问:如果 Pod 不写 resources 字段,Kubernetes 会如何处理呢?

这就意味着 Pod 对运行的资源要求“既没有下限,也没有上限”,Kubernetes 不用管 CPU 和内存是否足够,可以把 Pod 调度到任意的节点上,而且后续 Pod 运行时也可以无限制地使用 CPU 和内存。

我们课程里是实验环境,这样做是当然是没有问题的,但如果是生产环境就很危险了,Pod 可能会因为资源不足而运行缓慢,或者是占用太多资源而影响其他应用,所以我们应当合理评估 Pod 的资源使用情况,尽量为 Pod 加上限制。

看到这里估计你会继续追问:如果预估错误,Pod 申请的资源太多,系统无法满足会怎么样呢?

让我们来试一下吧,先删除 Pod 的资源限制 resources.limits,把 resources.request.cpu 改成比较极端的“10”,也就是要求 10 个 CPU


  ...
  
    resources:
      requests:
        cpu: 10

然后使用 kubectl apply 创建这个 Pod,你可能会惊奇地发现,虽然我们的 Kubernetes 集群里只有 3 个 CPU,但 Pod 也能创建成功。

不过我们再用 kubectl get pod 去查看的话,就会发现它处于 Pending状态,实际上并没有真正被调度运行:

pod-resource

使用命令 kubectl describe 来查看具体原因,会发现有这么一句提示:

failed

这就很明确地告诉我们 Kubernetes 调度失败,当前集群里的所有节点都无法运行这个 Pod,因为它要求的 CPU 实在是太多了。

2. 什么是容器状态探针

现在,我们使用 resources 字段加上资源配额之后,PodKubernetes 里的运行就有了初步保障,Kubernetes 会监控 Pod 的资源使用情况,让它既不会“饿死”也不会“撑死”。

但这只是最初级的运行保障,如果你开发或者运维过实际的后台服务就会知道,一个程序即使正常启动了,它也有可能因为某些原因无法对外提供服务。其中最常见的情况就是运行时发生“死锁”或者“死循环”的故障,这个时候从外部来看进程一切都是正常的,但内部已经是一团糟了。

所以,我们还希望 Kubernetes 这个“保姆”能够更细致地监控 Pod 的状态,除了保证崩溃重启,还必须要能够探查到 Pod 的内部运行状态,定时给应用做“体检”,让应用时刻保持“健康”,能够满负荷稳定工作。

那应该用什么手段来检查应用的健康状态呢?

因为应用程序各式各样,对于外界来说就是一个黑盒子,只能看到启动、运行、停止这三个基本状态,此外就没有什么好的办法来知道它内部是否正常了。

所以,我们必须把应用变成灰盒子,让部分内部信息对外可见,这样 Kubernetes 才能够探查到内部的状态。

这么说起来,检查的过程倒是有点像现在我们很熟悉的核酸检测,Kubernetes 用一根小棉签在应用的“检查口”里提取点数据,就可以从这些信息来判断应用是否“健康”了,这项功能也就被形象地命名为“探针”(Probe),也可以叫“探测器”。

Kubernetes 为检查应用状态定义了三种探针,它们分别对应容器不同的状态:

  • Startup,启动探针,用来检查应用是否已经启动成功,适合那些有大量初始化工作要做,启动很慢的应用。
  • Liveness,存活探针,用来检查应用是否正常运行,是否存在死锁、死循环。
  • Readiness,就绪探针,用来检查应用是否可以接收流量,是否能够对外提供服务。

你需要注意这三种探针是递进的关系:应用程序先启动,加载完配置文件等基本的初始化数据就进入了 Startup 状态,之后如果没有什么异常就是 Liveness 存活状态,但可能有一些准备工作没有完成,还不一定能对外提供服务,只有到最后的 Readiness 状态才是一个容器最健康可用的状态。

初次接触这三种状态可能有点难理解,我画了一张图,你可以看一下状态与探针的对应关系:
image.png
Kubernetes 具体是如何使用状态和探针来管理容器的呢?

如果一个 Pod 里的容器配置了探针,Kubernetes 在启动容器后就会不断地调用探针来检查容器的状态:

  • 如果 Startup探针失败,Kubernetes 会认为容器没有正常启动,就会尝试反复重启,当然其后面的 Liveness 探针和 Readiness 探针也不会启动。
  • 如果 Liveness 探针失败,Kubernetes 就会认为容器发生了异常,也会重启容器。
  • 如果 Readiness 探针失败,Kubernetes 会认为容器虽然在运行,但内部有错误,不能正常提供服务,就会把容器从 Service 对象的负载均衡集合中排除,不会给它分配流量。

知道了 Kubernetes 对这三种状态的处理方式,我们就可以在开发应用的时候编写适当的检查机制,让 Kubernetes 用“探针”定时为应用做“体检”了。

在刚才图的基础上,我又补充了 Kubernetes 的处理动作,看这张图你就能很好地理解容器探针的工作流程了:
image.png

3. 如何使用容器状态探针

如何在 PodYAML 描述文件里定义探针。

startupProbelivenessProbereadinessProbe 这三种探针的配置方式都是一样的,关键字段有这么几个:

  • periodSeconds,执行探测动作的时间间隔,默认是 10 秒探测一次。
  • timeoutSeconds,探测动作的超时时间,如果超时就认为探测失败,默认是 1 秒。
  • successThreshold,连续几次探测成功才认为是正常,对于 startupProbelivenessProbe 来说它只能是 1。
  • failureThreshold,连续探测失败几次才认为是真正发生了异常,默认是 3 次。

至于探测方式,Kubernetes 支持 3 种:ShellTCP SocketHTTP GET,它们也需要在探针里配置:

  • exec,执行一个 Linux 命令,比如 pscat 等等,和 containercommand 字段很类似。
  • tcpSocket,使用 TCP 协议尝试连接容器的指定端口。
  • httpGet,连接端口并发送 HTTP GET 请求。

要使用这些探针,我们必须要在开发应用时预留出“检查口”,这样 Kubernetes 才能调用探针获取信息。这里我还是以 Nginx作为示例,用 ConfigMap 编写一个配置文件:

# ngx-conf.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ngx-conf

data:
  default.conf: |
    server {
      listen 80;
      location = /ready {
        return 200 'I am ready';
      }
    }

在这个配置文件里,我们启用了 80 端口,然后用 location 指令定义了 HTTP 路径 /ready,它作为对外暴露的“检查口”,用来检测就绪状态,返回简单的 200 状态码和一个字符串表示工作正常。

现在我们来看一下 Pod 里三种探针的具体定义:

# ngx-pod-probe.yml

apiVersion: v1
kind: Pod
metadata:
  name: ngx-pod-probe

spec:
  volumes:
  - name: ngx-conf-vol
    configMap:
      name: ngx-conf

  containers:
  - image: nginx:alpine
    name: ngx
    ports:
    - containerPort: 80
    volumeMounts:
    - mountPath: /etc/nginx/conf.d
      name: ngx-conf-vol

    startupProbe:
      periodSeconds: 1
      exec:
        command: ["cat", "/var/run/nginx.pid"]

    livenessProbe:
      periodSeconds: 10
      tcpSocket:
        port: 80

    readinessProbe:
      periodSeconds: 5
      httpGet:
        path: /ready
        port: 80
  • StartupProbe 使用了 Shell 方式,使用 cat 命令检查 Nginx 存在磁盘上的进程号文件(/var/run/nginx.pid),如果存在就认为是启动成功,它的执行频率是每秒探测一次。
  • LivenessProbe 使用了 TCP Socket 方式,尝试连接 Nginx 的 80 端口,每 10 秒探测一次。
  • ReadinessProbe 使用的是 HTTP GET 方式,访问容器的 /ready 路径,每 5 秒发一次请求。

现在我们用 kubectl apply 创建这个 Pod,然后查看它的状态:

kubectl apply -f ngx-conf.yml
kubectl apply -f ngx-pod-probe.yml

getpod

当然,因为这个 Nginx 应用非常简单,它启动后探针的检查都会是正常的,你可以用 kubectl logs 来查看 Nginx 的访问日志,里面会记录 HTTP GET 探针的执行情况:
logs

从截图中你可以看到,Kubernetes 正是以大约 5 秒一次的频率,向 URI /ready 发送 HTTP 请求,不断地检查容器是否处于就绪状态。

为了验证另两个探针的工作情况,我们可以修改探针,比如把命令改成检查错误的文件、错误的端口号:


    startupProbe:
      exec:
        command: ["cat", "nginx.pid"]  #错误的文件

    livenessProbe:
      tcpSocket:
        port: 8080                     #错误的端口号

然后我们重新创建 Pod 对象,观察它的状态。

StartupProbe 探测失败的时候,Kubernetes 就会不停地重启容器,现象就是 RESTARTS 次数不停地增加,而 livenessProbereadinessProbePod 没有执行,Pod 虽然是 Running 状态,也永远不会 READY

failed

startupProbelivenessProbe 探测失败之后,podstatus 初始都是 running 。不过,在容器重启几次之后,podstatus 会变为 CrashLoopBackOff , 如果 startupProbelivenessProbe 探测成功,readinessProbe 探测失败,podready 一直是0/1,status 一直是 running ,当然,也不会重启 。

因为 failureThreshold 的次数默认是三次,所以 Kubernetes 会连续执行三次 livenessProbe TCP Socket 探测,每次间隔 10 秒,30 秒之后都失败才重启容器:

readinessProbe 修改为错误的路径,看看它失败时 Pod 会是什么样的状态。

	readinessProbe:
      periodSeconds: 5
      httpGet:
        path: /ready11   # 错误的路径
        port: 80

normal

使用 kubectl describe pod ngx-pod-probe 查看如下,虽然探针失败,但是不会重启,ready 状态一直为 0/1。

httpfailed

4. 总结

今天我们学习了两种为 Pod 配置运行保障的方式:ResourcesProbeResources 就是为容器加上资源限制,而 Probe 就是主动健康检查,让 Kubernetes 实时地监控应用的运行状态。

  1. 资源配额使用的是 cgroup 技术,可以限制容器使用的 CPU 和内存数量,让 Pod 合理利用系统资源,也能够让 Kubernetes 更容易调度 Pod
  2. Kubernetes 定义了 StartupLivenessReadiness 三种健康探针,它们分别探测应用的启动、存活和就绪状态。
  3. 探测状态可以使用 ShellTCP SocketHTTP Get 三种方式,还可以调整探测的频率和超时时间等参数。
  • 现在的服务器都是多核 CPU,在 kubernetes 中的 CPU 指的是逻辑核 CPU,也就是操作系统里能够看到的 CPU,除了 CPU 和内存, Podresources 字段还可以为容器配置临时存储空间和自定义扩展资源。

  • StartProbelivenessProbe 探测失败后的动作其实是由字段 restartPolicy 决定的,它的默认值 OnFailure 就是重启容器

  • 探针可以配置 initialDelaySeconds 字段,表示容器启动后多久才执行探针动作,适用于某些启动比较慢的应用,它的默认值为 0。

  • 在容器里还可以配置 lifecycle 字段,在启动后和终止前安装两个钩子 postStartpreStop 执行 shell 命令或者发送 http请求做一些初始化和收尾工作。

  • postStartpreStop感觉可以做 CI/CD,或者各种 webhock 钩子,或者简单的通知。

5. 问答

1、你能够解释一下 LivenessReadiness 这两种探针的区别吗?
LivenessReadiness 都是循环探测,Liveness 探测失败会重启,而 Readiness 探测失败不会重启,可以从 Pod 状态 看出重启次数。 两者都可以单独使用,这时差异不大。 如果同时使用两者,Liveness 主要是确认应用运行着或者说活着,而 Readiness 是确认应用提供着服务或者说服务就绪着(可以接收流量)。

StartupLivenessReadiness三种探针是按顺序执行还是并行呢?
Startup成功之后才能执行后两个探针,后面两个是并行的。

2、你认为 ShellTCP SocketHTTP GET 这三种探测方式各有什么优缺点?
Shell 是从容器内部探测,TCP SocketHTTP GET 都是在容器外部探测。 TCP Socket 基于端口的探测,端口打开即成功;HTTP GET 更丰富些,可以是端口 + 路径。

Liveness指的是进程是否存在,Readiness则是指是否能够正常提供服务,所以可以使用 tcp协议检测Liveness,进程存在端口即存在,使用 http检测服务,只有服务启动了参能够相应请求。

Shell是系统内进程级别交互,所以只能够本地访问,Tcp可以跨机器访问,但是访问的级别比较低,不能够获得顶层数据,Http是协议层数据,可以拿到应用层的服务信息,但是关注顶层信息,底层故障,顶层无法提供有价值信息了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/441377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dell t630服务器风扇控制笔记记录(耗时一天)

1、打开虚拟控制台得用IE; 2、Dell PowerEdge T640 加装显卡之后风扇狂转问题解决 - 知乎 感谢知乎Billy, 操作步骤: 1、查看iDrac版本,必须在3.30.30.30及以下,之后的版本关闭了手动控制风扇转速的权限&#xff0…

从视图树到GPU:探索Android渲染机制

简介 在 Android 中,渲染技术可以分为 CPU 渲染和 GPU 渲染两种方式。CPU 渲染是直接使用 CPU 处理数据,并将其显示在屏幕上,而 GPU 渲染则是将数据传递给 GPU 进行处理和显示。 具体的渲染技术如下: Canvas绘图:An…

多层感知器介绍

一、概览 现实世界中很多真实的问题都不是线性可分的,即无法使用一条直线、平面或者超平面分割不同的类别,其中典型的例子是异或问题(Exclusive OR,XOR),即假设输入为x1和x2,如果它们相同&…

Linux远程访问及控制SSH命令

目录 一. SSH服务1.1 SSH基础1.1.1什么是SSH服务器?1.1.2SSH优点1.1.3常见的ssh协议 二. 服务端配置文件常用选项2.1设置白名单2.2设置黑名单 三. SSH服务的两种验证方式3.1 公钥与私钥的关系 四. ssh客户端程序4.1ssh远程登录4.2 scp 远程复制4.3 sftp 安全的ftp 五…

Direct3D 12——计算着色器——计算着色器概念

计算着色器虽然是一种可编程的着色器,但Direct3D并没有将它直接归为渲染流水线中的一部分。虽然如此,但位于流水线之外的计算着色器却可以读写GPU资源。从本质上来说,计算着 色器能够使我们访问GPU来实现数据并行算法,而不必渲染出…

ESP32设备驱动-BH1745NUC 亮度和颜色传感器驱动

BH1745NUC 亮度和颜色传感器驱动 文章目录 BH1745NUC 亮度和颜色传感器驱动2、硬件准备3、软件准备4、驱动实现BH1745NUC 是具有 IC 总线接口的数字颜色传感器 IC。 该 IC 感应红光、绿光和蓝光 (RGB) 并将它们转换为数字值。 高灵敏度、宽动态范围和出色的 Ircut 特性使该 IC …

【CSS3】CSS3 伪元素字体图标 ( 生成 icommon 字体文件 | 字体图标基本使用 | 使用伪元素实现 icommon 字体图标显示 )

文章目录 一、icommon 字体图标基本使用1、生成 icommon 字体文件2、字体图标基本使用 二、使用伪元素实现 icommon 字体图标显示 一、icommon 字体图标基本使用 字体图标 指的是 将图标做成字体样式 , 在 放图标的地方 使用 文字 即可实现 图标显示 ; 1、生成 icommon 字体文件…

Vue2-黑马(十三)

目录: (1)实战-permissions.js-动态路由 (2)实战-第三方登录-流程分析 (3)实战-第三方登录-代码解读 (1)实战-permissions.js-动态路由 在做根据用户角色动态生成路由…

【Unity+MySQL】实现注册登录系统(升级版)

目录 1 UI界面重新设计1.1 注册界面1.2 登录界面1.3 交互实现 2 注册功能完善2.1 判断用户输入的用户名是否与数据库中的重复2.2 将当前时间更新至用户表的当前注册时间列2.3 将用户输入的注册密码使用哈希加密 3 登录功能完善 接着 上篇文章所谈到的系统缺陷,这篇…

==与equals()的理解

java中的数据类型分为基本数据类型、基本数据类型对应的包装类型(引用类型),引用类型三种数据类型。 每一个基本类型java都提供了一个与之对应的包装类型,该包装类型是一个引用类型,并且在基本类型与包装类型之间提供了自动拆箱和…

AD21原理图----网络连线(网络线、网络标签、总线、差分对、信号线束)

目录 网络连线 网络线(Wire) 网络标签 总线 差分对 信号线束 网络连线 网络线(Wire) 网络标签 可以跨原理图 总线 用于放置同一类数据 使用步骤 第一步:先绘制网络线 第二步:利用网络标签进行连接&a…

虚拟机下Ubuntu系统的Docker部署

虚拟机下Ubuntu系统的微服务项目Docker部署 文章目录 虚拟机下Ubuntu系统的微服务项目Docker部署1、Ubuntu安装 Docker2、修改后端微服务的配置2.1 修改 MySQL 的配置2.2 修改 Redis 的配置2.3 修改 Nacos 的配置 3、生成微服务镜像4、拉取远程镜像5、生成前端镜像5.1 准备文件…

MacOS安装MongoDB与Redis

1.安装MongoDB: brew tap mongodb/brew brew install mongodb-community 后台服务方式运行mongodb: brew services restart mongodb/brew/mongodb-community 直接运行mongodb非后台服务 /usr/local/opt/mongodb-community/bin/mongod --config /usr/local/etc/mongod.con…

化工行业数字化“智能工厂”-解决方案(ppt可编辑)

本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除。 总体架构 设计理念—数据集成与流转 九大核心价值之一 九大核心价值之二 九大核心价值之三 九大核心价值之四 九大核心价值之五 九大核心价值之六 九大核心价值之七 九大核心…

数据库学习-常用的SQL语句

背景: 汇整一下自己学习数据库过程中常见的题目及语句。 一.实例分析题 二.简单SQL查询: 1):统计每个部门员工的数目select dept,count(*) from employee group by dept;2):统计每个部门员工的数目大于一个的记录se…

3.4 迭代法

4.1 雅克比迭代法: 雅可比迭代法是一种用于求解线性方程组的迭代算法,其基本思想是将线性方程组中的系数矩阵拆分为对角线矩阵和非对角线矩阵两部分,并利用对角线矩阵的逆矩阵来迭代求解方程组。 具体地,设线性方程组为Axb&…

操作系统笔记--虚拟内存的使用

1--背景概念 在计算机系统中,当多道程序同时运行时可能会出现内存不足的情况,一般可通过以下技术进行解决: 覆盖技术: 当程序太大超出内存容量时,可以采用手动覆盖的技术,只把需要的指令和数据保存在内存当…

SSM整合、环境配置以及基础综合测试(单表查询、多表查询和数据分页、前后端分离、Vue3)

SSM整合、环境配置以及基础综合测试 准备:创建maven项目以及项目框架准备 SSM整合简介 介绍: SSM(SpringSpringMVCMyBatis) 整合,就是三个框架协同开发。Spring整合Mybatis就是将Mybatis核心配置文件当中数据源的配置、事务处理、以及工厂的配置&…

Docker的使用说明

目录 第一章什么是Docker 1.1.Docker的概述 1.2.什么是容器 1.3.Docker核心概念 第二章.安装 Docker 2.1.安装环境部署 2.2.安装 Docker-CE并设置为开机自动启动 2.2.Docaker的简单信息查看 第三章.Docker 操作 3.1.Docker的镜像操作 3.2.Docker 容器操作 3.3.容器…

Baumer工业相机堡盟工业相机如何联合BGAPISDK和佳能EF变焦镜头实现相机的自动变焦(C#)

Baumer工业相机堡盟工业相机如何联合BGAPISDK和佳能EF变焦镜头实现相机的自动变焦(C#) Baumer工业相机Baumer工业相机BGAPISDK中控制变焦镜头的技术背景代码案例分享第一步:开启相机自动调焦功能模块第二步:控制自动变焦镜头电机的…