深入理解K8s资源限制,你明白了吗?

开发 前端
资源限制通过每个容器的 containerSpec 中的 resources 字段进行设置,该字段是 v1 版本的 ResourceRequirements 类型的 API 对象。通过设置 limits 和 requests,可以分别定义资源的上限和需求。

深入理解K8s资源限制

资源限制是 Kubernetes 中可配置的重要选项之一,它包含两方面内容:

工作负载的资源需求:用于定义工作负载运行时所需的最低资源。调度器根据这一信息选择合适的节点来部署工作负载。

资源的最大限制:用于规定工作负载可以消耗的资源上限。Kubelet 节点守护进程依赖这一配置来管理 Pod 的运行和健康状态。

换句话说,资源需求确保工作负载能够正常运行,而资源限制则避免单个工作负载过度消耗节点资源。

资源限制

资源限制通过每个容器的 containerSpec 中的 resources 字段进行设置,该字段是 v1 版本的 ResourceRequirements 类型的 API 对象。通过设置 limits 和 requests,可以分别定义资源的上限和需求。

当前支持的资源类型主要有 CPU 和 内存。通常情况下,deployment、statefulset 和 daemonset 的定义中都会包含 podSpec,而 podSpec 内部会定义一个或多个 containerSpec。

以下是一个完整的 v1 资源对象的 YAML 配置示例:

resources:
    requests:
        cpu: 50m
        memory: 50Mi
  limits:
        cpu: 100m
        memory: 100Mi

可以这样理解:该容器通常需要 5% 的 CPU 时间 和 50MiB 的内存(由 requests 定义),但在高峰时允许其最多使用 10% 的 CPU 时间 和 100MiB 的内存(由 limits 定义)。

稍后我会更详细地解释 requests 和 limits 的区别,但一般来说:

  • requests 在调度阶段更为关键,因为调度器会根据 requests 判断节点是否有足够的资源来运行容器。
  • limits 在运行阶段更重要,Kubelet 会使用它来限制容器的资源消耗,确保单个容器不会过度占用节点资源。

虽然资源限制是为每个容器配置的,但 Pod 的整体资源限制可以视为其所有容器资源限制的总和。从系统的角度来看,这种关系非常直观。

内存限制

CPU资源限制比内存资源限制更复杂,但它们都是通过cgroup控制的,所以我们可以用类似的方法来处理。接下来,我们重点看它们的不同之处。

首先,我们在之前的 YAML 文件中加入 CPU 的资源限制:

resources:
  requests:
    memory: 50Mi
    cpu: 50m
  limits:
    memory: 100Mi
    cpu: 100m

这里的 m 表示千分之一核。例如,50m 代表 0.05 核,100m 代表 0.1 核,而 2000m 就是 2 核。这样配置后,容器需要至少 5% 的 CPU 资源才能运行,同时最多能使用 10% 的 CPU 资源。

接着,我们创建一个只配置了 CPU requests 的 Pod:

kubectl run limit-test --image=busybox --requests "cpu=50m" --command -- /bin/sh -c "while true; do sleep 2; done"

用以下命令可以验证 Pod 的资源配置:

kubectl get pods limit-test-5b4c495556-p2xkr -o=jsnotallow='{.spec.containers[0].resources}'

输出:

map[requests:map[cpu:50m]]

同时,用 Docker 查看容器对应的 CPU 配置:

docker ps | grep busy | cut -d' ' -f1
f2321226620e
docker inspect f2321226620e --format '{{.HostConfig.CpuShares}}'
51

这里显示 51 而不是 50,是因为 Kubernetes 把 CPU 核心划分为 1000 个份额(shares),而 Linux 内核用 1024 个时间片表示 CPU 的分配比例。CPU 的 shares 是一个相对值,用来划分 CPU 使用权:

  • 如果有两个 cgroup(A 和 B),A 的 shares 是 1024,B 是 512,那么 A 获得 66% 的 CPU 资源,B 获得 33%。
  • 如果 CPU 空闲,B 可以使用更多资源。
  • 如果新增一个 cgroup C,A 和 B 的占比会减少。

接下来,再看看设置了 CPU limits 的 Pod 会发生什么:

kubectl run limit-test --image=busybox --requests "cpu=50m" --limits "cpu=100m" --command -- /bin/sh -c "while true; do sleep 2; done"

再次用 kubectl 查看资源限制:

kubectl get pods limit-test-5b4fb64549-qpd4n -o=jsnotallow='{.spec.containers[0].resources}'

输出:

map[limits:map[cpu:100m] requests:map[cpu:50m]]

而对应的 Docker 配置:

docker inspect f2321226620e --format '{{.HostConfig.CpuShares}} {{.HostConfig.CpuQuota}} {{.HostConfig.CpuPeriod}}'
51 10000 100000

CpuShares 是对应 requests 的 CPU 份额。

CpuQuota

CpuPeriod

是用来实现

limits

的:

  • CpuPeriod 表示一个时间周期(默认为 100 毫秒,即 100,000 微秒)。
  • CpuQuota 表示每周期允许使用的 CPU 时间(100m 对应 10,000 微秒)。

这些值最终映射到 cgroup:

cat /sys/fs/cgroup/cpu,cpuacct/.../cpu.cfs_period_us
100000


cat /sys/fs/cgroup/cpu,cpuacct/.../cpu.cfs_quota_us
10000

例子:

限制 1 核(每 250ms 内用 250ms CPU 时间):

echo 250000 > cpu.cfs_quota_us
echo 250000 > cpu.cfs_period_us

限制 2 核(每 500ms 内用 1000ms CPU 时间):

echo 1000000 > cpu.cfs_quota_us
echo 500000 > cpu.cfs_period_us

限制 1 核的 20%(每 50ms 用 10ms CPU 时间):

echo 10000 > cpu.cfs_quota_us
echo 50000 > cpu.cfs_period_us

简单总结:

  • requests 保证容器最少能用的 CPU 资源。
  • limits 确保容器最多使用的 CPU 时间不会超过限制。

默认限制

要为命名空间中的 Pod 设置默认的资源限制,可以使用 Kubernetes 提供的 LimitRange 资源。通过配置 LimitRange,可以为每个命名空间设置默认的 requests 和 limits,从而确保 Pod 的资源分配有合理的默认值和边界限制。以下是如何实现的说明和示例:

创建一个 LimitRange 示例:

以下 YAML 文件定义了一个 LimitRange 资源:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limit
spec:
  limits:
    - default:
        memory: 100Mi
        cpu: 100m
      defaultRequest:
        memory: 50Mi
        cpu: 50m
    - max:
        memory: 512Mi
        cpu: 500m
    - min:
        memory: 50Mi
        cpu: 50m
      type: Container

字段解析

default:

  • 设置默认的 limits 值。
  • 如果 Pod 未明确指定 limits,则系统自动分配 100Mi 内存和 100m CPU。

defaultRequest:

  • 设置默认的 requests 值。
  • 如果 Pod 未明确指定 requests,则系统自动分配 50Mi 内存和 50m CPU。

max 和 min:

  • max: 定义 limits 的最大值。如果 Pod 资源分配超过这个值,Pod 将被拒绝创建。
  • min: 定义 requests 的最小值。如果 Pod 资源分配低于这个值,Pod 也将被拒绝创建。

type:

  • 指定适用范围为 Container。

工作机制

Kubernetes 的LimitRanger准入控制器负责应用这些限制:

  • 在创建 Pod 之前,如果 Pod 的 limits 或 requests 未设置,则自动添加 LimitRange 中的默认值。
  • 如果 Pod 的资源配置超出 max 或低于 min,则拒绝创建。

示例 Pod 及 LimitRanger 插件设置的注释

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/limit-ranger: 'LimitRanger plugin set: cpu request for container limit-test'
  name: limit-test
  namespace: default
spec:
  containers:
    - name: limit-test
      image: busybox
      args:
        - /bin/sh
        - -c
        - while true; do sleep 2; done
      resources:
        requests:
          cpu: 100m

annotations: 显示 LimitRanger 插件已经为 Pod 自动添加了默认的资源 requests。

总结

1、使用 LimitRange,可以为命名空间设置默认的 requests 和 limits,避免 Pod 没有资源限制带来的风险。

2、max 和 min 设置了资源的上下限,确保 Pod 的资源分配符合命名空间的约束。

3、LimitRanger 插件会在 Pod 创建时检查并自动设置默认值,使资源限制更加自动化和规范化

责任编辑:武晓燕 来源: 步步运维步步坑
相关推荐

2024-12-05 10:00:54

K8s参数Pod

2022-11-02 10:21:41

K8s pod运维

2024-05-10 08:00:48

K8soperatorGitHub

2022-10-08 08:09:13

MGRGreatSQL事务

2023-12-08 07:40:07

并发控制

2020-07-21 08:26:08

SpringSecurity过滤器

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap数据结构hash函数

2022-05-31 07:32:19

JDK8API工具

2019-09-16 08:32:59

递归算法编程

2022-04-22 13:32:01

K8s容器引擎架构

2013-09-22 14:57:19

AtWood

2023-10-19 11:12:15

Netty代码

2021-02-17 11:25:33

前端JavaScriptthis

2009-09-25 09:14:35

Hibernate日志

2017-08-15 13:05:58

Serverless架构开发运维

2020-09-23 10:00:26

Redis数据库命令

2019-06-25 10:32:19

UDP编程通信

2024-02-21 21:14:20

编程语言开发Golang

2017-01-10 08:48:21

点赞
收藏

51CTO技术栈公众号