开始使用 Kubernetes 时,通常会忘记设置容器资源。 至此,足以保证Docker镜像能够工作并且可以部署到Kubernetes集群中。
但后来该应用程序需要与其他应用程序一起部署在生产集群中。 为此,您需要为容器分配资源,并确保有足够的资源来启动和运行应用程序,并且其他正在运行的应用程序不会遇到问题。
团队
计算资源
我们有两种类型的资源,具有以下单位:
- 中央处理器 (CPU) - 核心;
- 内存 (MEM) - 字节。
为每个容器指定资源。 在以下 Pod YAML 文件中,您将看到一个资源部分,其中包含请求的资源和限制的资源:
- 请求的 Pod 资源 = 所有容器请求的资源之和;
- Pod 资源限制 = 所有 Pod 资源限制的总和。
apiVersion: v1
kind: Pod
metadata:
name: backend-pod-name
labels:
application: backend
spec:
containers:
— name: main-container
image: my-backend
tag: v1
ports:
— containerPort: 8080
resources:
requests:
cpu: 0.2 # REQUESTED CPU: 200m cores
memory: "1Gi" # REQUESTED MEM: 1Gi
limits:
cpu: 1 # MAX CPU USAGE: 1 core
memory: "1Gi" # MAX MEM USAGE: 1Gi
— name: other-container
image: other-app
tag: v1
ports:
— containerPort: 8000
resources:
requests:
cpu: "200m" # REQUESTED CPU: 200m cores
memory: "0.5Gi" # REQUESTED MEM: 0.5Gi
limits:
cpu: 1 # MAX CPU USAGE: 1 core
memory: "1Gi" # MAX MEM USAGE: 1Gi
请求的资源和有限的资源示例
领域 resources.requested
根据规范,Pod 是用于查找所需节点的元素之一。 您已经可以为其规划 Pod 部署。 如何找到合适的节点?
Kubernetes 由多个组件组成,包括主节点或主节点(Kubernetes Control Plane)。 主节点有几个进程:kube-apiserver、kube-controller-manager 和 kube-scheduler。
kube-scheduler 进程负责检查新创建的 Pod 并查找与所有 Pod 请求匹配的可能工作节点,包括请求的资源数量。 kube-scheduler 找到的节点列表已排序。 Pod 被调度到分数最高的节点上。
紫色 Pod 将放置在哪里?
在图中您可以看到 kube-scheduler 应该调度一个新的紫色 Pod。 Kubernetes 集群包含两个节点:A 和 B。如您所见,kube-scheduler 无法在节点 A 上调度 Pod - 可用(未请求)资源与紫色 Pod 的请求不匹配。 因此,紫色 Pod 请求的 1 GB 内存在节点 A 上不适合,因为可用内存为 0,5 GB。 但节点B有足够的资源。 因此,kube-scheduler 判定紫色 Pod 的目的地是节点 B。
现在我们知道请求的资源如何影响运行 Pod 的节点的选择。 但边际资源的影响是什么呢?
资源限制是CPU/MEM无法跨越的边界。 但是,CPU 资源是灵活的,因此达到 CPU 限制的容器不会导致 Pod 退出。 相反,CPU 限制将开始。 如果达到 MEM 使用限制,容器将因 OOM-Killer 而停止,并在 RestartPolicy 设置允许的情况下重新启动。
请求的资源和最大资源的详细信息
Docker与Kubernetes之间的资源通信
解释资源请求和资源限制如何工作的最好方法是介绍 Kubernetes 和 Docker 之间的关系。 在上图中,您可以看到 Kubernetes 字段和 Docker 启动标志是如何关联的。
记忆:要求和限制
containers:
...
resources:
requests:
memory: "0.5Gi"
limits:
memory: "1Gi"
如上所述,内存以字节为单位。 基于 G
и Gi
,最重要的是要记住它们并不等同。 第一个是十进制,第二个是二进制。 就像k8s文档中提到的例子: 128974848
, 129e6
, 129M
, 123Mi
- 它们实际上是等效的。
库伯内特选项 limits.memory
与旗帜相匹配 --memory
来自 Docker。 的情况下 request.memory
Docker 没有箭头,因为 Docker 不使用该字段。 你可能会问,这还有必要吗? 是的,需要。 正如我之前所说,这个领域对于 Kubernetes 来说很重要。 根据其中的信息,kube-scheduler 决定在哪个节点上调度 Pod。
如果为请求设置的内存不足会发生什么情况?
如果容器已达到请求内存的限制,则 Pod 会被放置在一组 Pod 中,当节点中内存不足时,这些 Pod 会停止。
如果您将内存限制设置得太低会发生什么情况?
如果容器超过内存限制,它将因 OOM-Killed 而终止。 如果可能的话,将根据 RestartPolicy 重新启动,默认值为 Always
.
如果不指定请求的内存会发生什么?
Kubernetes 将采用该限制值并将其设置为默认值。
如果不指定内存限制会发生什么?
容器没有任何限制;它可以使用任意多的内存。 如果他开始使用节点的所有可用内存,那么 OOM 将杀死他。 如果可能的话,容器将根据 RestartPolicy 重新启动。
如果不指定内存限制会发生什么?
这是最坏的情况:调度程序不知道容器需要多少资源,这可能会导致节点出现严重问题。 在这种情况下,最好对命名空间设置默认限制(由 LimitRange 设置)。 没有默认限制 - Pod 没有限制,它可以使用任意多的内存。
如果请求的内存超过节点可以提供的内存,Pod 将不会被调度。 重要的是要记住这一点 Requests.memory
- 不是最小值。 这是对足以保持容器持续运行的内存量的描述。
通常建议设置相同的值 request.memory
и limit.memory
。 这可以确保 Kubernetes 不会将 Pod 调度到有足够内存运行 Pod 但又不足以运行它的节点上。 请记住:Kubernetes Pod 规划仅考虑 requests.memory
和 limits.memory
不考虑。
CPU:请求和限制
containers:
...
resources:
requests:
cpu: 1
limits:
cpu: "1200m"
对于CPU来说,一切都有点复杂。 回到 Kubernetes 和 Docker 的关系图,可以看到 request.cpu
对应于 --cpu-shares
,而 limit.cpu
与旗帜相匹配 cpus
在 Docker 中。
Kubernetes 请求的 CPU 乘以 1024,即 CPU 周期的比例。 如果您想请求 1 个完整核心,则必须添加 cpu: 1
如上图所示。
请求完整的内核(比例 = 1024)并不意味着您的容器会收到它。 如果您的主机只有一个核心,并且您正在运行多个容器,那么所有容器必须在它们之间共享可用的 CPU。 这是怎么发生的? 让我们看一下图片。
CPU 请求 - 单核系统
让我们假设您有一个运行容器的单核主机系统。 妈妈(Kubernetes)烤了一个馅饼(CPU)并想把它分给孩子(容器)。 三个孩子想要整个馅饼(比例 = 1024),另一个孩子想要半个馅饼(512)。 妈妈为了公平起见,做了一个简单的计算。
# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%
据计算,三个孩子将获得核心的28%,而不是全部核心。 第四个孩子将获得完整内核的 14%,而不是一半。 但如果你有一个多核系统,情况就会有所不同。
CPU 请求 - 多核 (4) 系统
在上图中,您可以看到三个孩子想要一整个馅饼,一个想要半个。 由于妈妈烤了四个馅饼,所以她的每个孩子都想吃多少就吃多少。 在多核系统中,处理器资源分布在所有可用的处理器核心上。 如果一个容器被限制为少于一个完整的 CPU 核心,它仍然可以 100% 使用它。
简化上述计算可以理解 CPU 如何在容器之间分配。 当然,除了容器本身之外,还有其他进程也会使用CPU资源。 当一个容器中的进程空闲时,其他容器可以使用其资源。 CPU: "200m"
对应于 CPU: 0,2
,这意味着一个核心的大约 20%。
现在让我们谈谈 limit.cpu
。 Kubernetes 限制的 CPU 乘以 100。结果是容器每 100 µs 可以使用的时间量(cpu-period
).
limit.cpu
匹配 Docker 标志 --cpus
。 这是旧的新组合 --cpu-period
и --cpu-quota
。 通过设置它,我们指示在限制开始之前容器可以最大使用多少可用CPU资源:
- CPU的 - 组合
cpu-period
иcpu-quota. cpus = 1.5
相当于设置cpu-period = 100000
иcpu-quota = 150000
; - CPU周期 - 时期
CPU CFS调度器 ,默认100微秒; - CPU配额 - 内部的微秒数
cpu-period
,它以容器为界。
如果安装的 CPU 不足,会发生什么情况?
如果容器需要的数量超过其已安装的数量,它将从其他进程中窃取 CPU。
如果您将 CPU 限制设置得太低会发生什么情况?
由于CPU资源是可调的,因此会开启节流。
如果不指定 CPU 请求会发生什么?
与内存一样,请求值等于限制。
如果不指定 CPU 限制会发生什么?
容器将根据需要使用尽可能多的 CPU。 如果命名空间中定义了默认 CPU 策略 (LimitRange),则此限制也适用于容器。
如果您不指定请求或 CPU 限制,会发生什么情况?
与内存一样,这是最坏的情况。 调度程序不知道您的容器需要多少资源,这可能会导致节点出现严重问题。 为了避免这种情况,您需要为命名空间设置默认限制(LimitRange)。
请记住:如果您请求的 CPU 多于节点可以提供的 CPU,则 Pod 将不会被调度。 Requests.cpu
- 不是最小值,而是足以启动 Pod 并正常工作的值。 如果应用程序不执行复杂的计算,最好的选择是安装 request.cpu <= 1
并根据需要启动尽可能多的副本。
请求的资源的理想数量或资源限制
我们了解到计算资源的限制。 现在是时候回答这个问题了:“我的 Pod 需要多少资源才能运行应用程序而不出现任何问题? 理想的量是多少?
不幸的是,这些问题没有明确的答案。 如果您不知道应用程序如何工作或需要多少 CPU 或内存,最好的选择是为应用程序提供大量内存和 CPU,然后运行性能测试。
除了性能测试之外,还要在一周的监控中监控应用程序的行为。 如果图表表明您的应用程序消耗的资源少于您请求的资源,您可以减少请求的 CPU 或内存量。
举个例子看看这个
结论
请求和限制资源有助于保持 Kubernetes 集群的健康运行。 正确的限制配置可以最大限度地降低成本并保持应用程序始终运行。
简而言之,有以下几点需要牢记:
- 请求的资源是在启动时(当 Kubernetes 计划托管应用程序时)考虑的配置。 相反,限制资源在运行时非常重要——当应用程序已经在节点上运行时。
- 与内存相比,CPU 是一种受管制的资源。 如果没有足够的CPU,你的Pod将不会关闭并且节流机制将打开。
- 请求的资源和资源限制不是最小值和最大值! 通过定义所请求的资源,您可以确保应用程序运行时不会出现问题。
- 一个好的做法是将内存请求设置为等于内存限制。
- 好的安装请求
CPU <=1
,如果应用程序不执行复杂的计算。 - 如果您请求的资源多于节点上可用的资源,则 Pod 将永远不会被调度到该节点。
- 要确定请求的资源/资源限制的正确数量,请使用负载测试和监控。
我希望这篇文章可以帮助您理解资源限制的基本概念。 您将能够将这些知识应用到您的工作中。
祝你好运!
还有什么要读的:
来源: habr.com