【译】Kubernetes中的资源分配

网友投稿 1311 2022-10-29

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

【译】Kubernetes中的资源分配

本文译自Kirill Goltsman所写的Assigning Computing Resources to Containers and Pods in Kubernetes,原文地址为 https://supergiant.io/blog/assigning-computing-resources-to-containers-and-pods-in-kubernetes/ 。为使文章只关注于k8s,翻译时移除了原文中关于supergiant的部分。译文也同时参考了k8s官方文档中关于Quality of Service for Pods的部分。

Kubernetes的资源模型(resource model)被设计成既能优化容器对资源的利用又能保证Pods的高效调度和应用的高可用。Kubernetes实现这一方法的核心是在Pod创建时规定容器的resource requests和limits(资源请求和限制)。本文将介绍Kubernetes resource model的内部机制,并带着你使用Kubernetes内置的工具和API为容器分配计算资源(CPU和RAM)。希望本文能让你对如何给容器分配资源获得更加深入的理解。

How does the Kubernetes Resource Allocation Model Work?

在Kubernetes中,我们可以通过设定 CPU 和 Memory(RAM) 的requests和limits,来为Pod中的每个容器分配资源。这些设定将作为调度器(scheduler)的依据,为Pods选择合适的运行节点(node)。

Kubernetes文档将resource limit定义为 Kubernetes确保能够赋予给容器的计算资源(CPU或memory)的总量。相应的,resource limit 被定义为 Kubernetes允许容器所消耗的资源的最大量。

需要注意的是,一个Pod是否能被调度到某个节点,取决于这个Pod内所有的容器的resource requests和limits的总和。也就是说,如果Pod内的某个容器所需求的资源量与某个Node可分配的最大的资源量不匹配,这个Pod将无法被调度到该节点上。确保所有容器的资源需求总量在Node的容量范围内,既是调度器又是 kubelet 的任务。

Calculation of Resource Requests and Limits

应该记住的是,Pods的调度依赖的是 requests 而不是 limits。换句话说,如果一个Pod的resource request在Node的可分配容量之内,即使该Pod的 resource limit过大,Pod也是可以被调度到该Node上的。同样要注意的是,即使一个Node的实际memory或CPU利用率不高,如果pod的resource request超过该Node的容量了,调度器也会拒绝把pod放置在这个Node上。这个特性防止了在突然出现流量高峰的情况下,系统出现资源短缺。

Kubernetes Resource Types

Kubernetes将底层处理器架构抽象为了计算资源,将它们按照需求暴露为原始值或基本单位。对于CPU资源来说,这些基本单位是基于核心(cores)的;对于内存来说,则是基于字节的。内存资源可以使用单纯的数值或带有后缀(E、P、T、G、M、K)的定点整数表示。而一个CPU则相当于:

一个AWS vCPU一个GCP Core一个Azure vCore英特尔处理器上一个 Hyperthread(处理器要支持Hyperthreading)

Kubernetes允许按小数来指定CPU (比如 0.5 CPU)。举个例子,一个 resource request 为 0.5 CPU的容器,将会被确保获得一半CPU的算力。0.5 CPU 等同于 500m,后者的意思是 "500 millicpu" 或者 "500 minicores"。需要注意的是,在Kubernetes中,CPU资源用的是绝对量,意思是无论是在单核、双核或其它机器上,0.1 对应的量是一样的(译者解释: 对于2核的cpu来说,500m意味着用半核;2000m意味着2核都用;0.5意味着用半核;2意味着2核都用;以此类推)。

Pod Classes Depending on Resource Requests and Limits

根据 resource requests和limit的 min/max 比例,我们最终会得到3类不同的Pods:guaranted Pods、burstable Pods 和 best-effort Pods。

(译者解释,pod在创建后,会有一个 spec.qosClass字段,其值可以是 Guaranteed、Burstable和BestEffort)

Guaranteed Pods

当一个Pod内的每个容器,其 request.memory等于limit.memory且request.cpu等于limit.cpu时,这个Pod被认为是 Guaranteed。

Example:

containers: name: first resources: limits: cpu: 20m memory: 1Gi requests: cpu: 20m memory: 1Gi name: second resources: limits: cpu: 300m memory: 400Mi requests: cpu: 300m memory: 400Mi

在本例中,名为first和second的容器,各自内部的request和limit都是相等的。这使得它们所处的Pod 为 guaranted。

Burstable Pods

需要满足2个条件:

a. 不是 Guaranteed Pod;

b. Pod内至少有一个容器设置了 memory 或 cpu request。

Example:

containers: name: first resources: limits: memory: 2Gi requests: memory: 1Gi name: second resources: limits: cpu: 500m requests: cpu: 300m

Best-Effort Pods

如果一个Pods内的所有容器都没有设置resource requests和limits,则这个pod被认为是 best-effort。

Example:

containers: name: first resources: name: second resources:

Kubernetes根据上述不同类型的pod,将给出不同的资源使用权和优先级。Best-Effort Pods 有着最低的优先级,在系统内存不足时,它们是第一批被清理的对象。Guaranteed Pods有着最高的优先级,通常不会被杀死或节流,除非资源使用超过了limits的限制并且没有其它更低优先级的pods可清理了。最后,Burstable Pods有着最小的资源保证(译者注,因为设置了resource request)但是条件允许时允许使用更多的计算资源。在没有Best-Effort Pods存在并且系统容量不足时,Burstable Pods将是集群中第一批被杀死的。

下面的规则适用于所有这3类pods:

如果节点中内存充足,容器可以使用比memory request规定的更多的内存。但不能超过limit所限制的量。这类容器有被终止的可能。如果终止的容器被设置为可重启的,kubelet 会负责这一块。容器的cpu使用可能会被允许超限一小段时间。是否允许取决于容器的运行时环境(Docker、rkt)。因此有些容器在CPU使用上可以超限运行一小段时间,而有些则不能。CPU是否能超限使用还取决于Node中剩余多少空闲CPU。如果有其它容器也在争取这些资源,则要参考容器的resource request。如果没有别的容器想要这些资源,容器可以使用尽可能多的资源。

Why Use Resource Requests and Limits at All?

对于 resource requests和limits如何影响Pods的命运,我们现在有了基本的理解。然而,我们为什么要使用它们呢?

我们有2个主要动机:安全高效地使用计算资源;确保高优先级的Pods正常运行。更确切地说:

CPU和memory requests比较低的pods,有更好的机会被调度如果你把resource limits设置的高于resource requests,则在资源充足时,Pods可以利用更多的资源。同时,设定resource limits后,可以保证资源不会过度使用

在创建Pod时,也允许用户不设定resource requestst和limits,这种情况则符合以下规则:

容器可以使用Node上的所有资源如果容器所在的namespace设置了memory或CPU limit,集群管理员可以使用 LimitRange 为所有容器指定limit的默认值

Tutorial

接下来,我们将向你展示,使用Kubernetes内置的工具给容器分配resource requests和limits是多么容易。

要完成本示例,得满足以下前提:

一个运行中的Kubernetes集群。你可以使用 Minikube安装一个单节点集群一个配置好了的可以与集群通信的 kubectl 命令行工具集群中需要运行着 Heapster service。可通过 kubectl get services --namespace=kube-system 来查看是否安装了该服务

好了,我们可以开始给Kubernetes中的容器分配资源了。

Step 1: Create a new namespace

创建一个新的namespace是一个好的实践,它能帮我们将项目中的计算资源和集群中其它的部分进行分离。我们使用以下命令来创建namespace:

kubectl create namespace assigning-resources-tut

控制台会输出以下内容:

namespace "assigning-resources-tut" created

Step 2: Specify CPU requests and limits

本教程将使用单容器Pod,这也是Kubernetes中最常见的Pod类型。用的容器镜像是NGINX。为了指定 CPU和memory request,我们在Pod manifest中使用 spec.containers.resources.requests。对于resource limits,我们使用 spec.containers.resources.limits字段。我们决定把NGINX容器的resource request设置为 0.5 CPU、CPU limit设置为 1 CPU。同时 memory request 设置为 500MiB 且 memory limit 为 700MiB。

下面是Pod的配置文件:

apiVersion: v1kind: Podmetadata: name: test-pod namespace: assigning-resources-tutspec: containers: - name: nginx image: nginx:latest resources: limits: cpu: "1" memory: "700Mi" requests: cpu: "0.5" memory: "500Mi"

Step 3: Create a Pod

执行以下命令:

kubectl create -f test-pod.yaml --namespace=assigning-resources-tut

Step 4: Check whether the pod's container is running in our namespace

运行以下命令:

kubectl get pod test-pod --namespace=assigning-resources-tut

可以看到如下输出:

NAME READY STATUS RESTARTS AGEtest-pod 1/1 Running 0 8s

这意味着 test-pod 在运行中,没重启过并且存活了8秒了。

也可以运行以下命令,以yaml格式查看pod的详细信息:

kubectl get pod test-pod --output=yaml --namespace=assigning-resources-tut

一部分输出如下:

spec: containers: - image: nginx:latest imagePullPolicy: Always name: nginx resources: limits: cpu: "1" memory: 700Mi requests: cpu: 500m memory: 500Mi

Step 5: Checking the actual resource usage

能够追踪Pod的资源使用情况是很方便的。我们可以使用 Heapster service 做检查。Heapster可以对Kubernetes进行集群监控和性能分析。

要使用Heapster,我们首先要启动一个proxy:

kubectl proxy

该proyx在当前终端窗口运行。为了使用Heapster,我们需要再开启一个终端窗口。要获取CPU使用率,在新的终端窗口中执行:

curl http://localhost:8001/api/v1/namespaces/kube-system/services/heapster/proxy/api/v1/model/namespaces/assigning-resources-tut/pods/test-pod/metrics/cpu/usage_rate

可以看到,我们访问了指向了我们namespace下的test-pod下的 cpu/usage_rate 接口。得到的结果类似于下面:

{ "metrics": [ { "timestamp": "2018-05-13T21:43:40Z", "value": 0.1 }, { "timestamp": "2018-05-13T21:44:40Z", "value": 0.2 }, { "timestamp": "2018-05-13T21:45:00Z", "value": 0.22 }

它展示的是每个时间点上的CPU使用情况。这便于我们追踪CPU随时间的变化。

同样,要获取内存使用情况,访问 memory/usage :

curl http://localhost:8001/api/v1/namespaces/kube-system/services/heapster/proxy/api/v1/model/namespaces/assigning-resources-tut/pods/test-pod/metrics/memory/usage

下面的输出意味着Pod使用了13246454的RAM。

{ "timestamp": "2018-05-13T22:00:40Z", "value": 13246464 }, { "timestamp": "2018-05-13T22:01:00Z", "value": 13246464 }

Step 6: Deleting the pod

本文快要结束了,我们把Pod清理掉吧。

kubectl delete pod test-pod --namespace=assigning-resources-tut

Conclusion

希望本文能帮你理解Kubernetes resource model实际上是如何工作的。如我们所学的这样,resource requests 和 limits这一概念简单且强大。合理地使用它们能帮助我们控制pods如何利用集群中的计算资源。Kubernetes也提供了灵活的方式来创建不同优先级的pods,方便最有效的方式来分发有限的资源;同时也确保了最重要的应用和容器总是处于运行状态,降低了突发的流量高峰和node故障带来的影响。

上一篇:中档级。该级别的磁盘阵列适用于中大型企业
下一篇:入门级。该级别的磁盘阵列适用于中小型企业
相关文章

 发表评论

暂时没有评论,来抢沙发吧~