当在Kubernetes中使用容器时,重要的是要知道所涉及的资源是什么以及如何需要它们。有些进程比其他进程需要更多的CPU或内存。有些是关键的,不应该被饿死。
知道了这一点,我们应该正确配置我们的容器和Pod,以获得两者的最佳效果。
在这篇文章中,我们将看到。
在使用Kubernetes时,Limits和Requests是重要的配置,主要包含CPU和内存的配置。
Kubernetes将Limits定义为一个容器使用的最大资源量,这意味着容器的消耗量永远不能超过所显示的内存量或CPU量。
另一方面,Requests是指为容器保留的资源的最小保证量。
让我们来看看下面这个deployment,我们需要为两个不同的容器在CPU和内存上设置Limits和Requests。
kind: Deployment
apiVersion: extensions/v1beta1
…
template:
spec:
containers:
- name: redis
image: redis:5.0.3-alpine
resources:
limits:
memory: 600Mi
cpu: 1
requests:
memory: 300Mi
cpu: 500m
- name: busybox
image: busybox:1.28
resources:
limits:
memory: 200Mi
cpu: 300m
requests:
memory: 100Mi
cpu: 100m
假如,我们要把该deployment部署到4C16G配置的节点上,可以得到如下信息。
Kubernetes将请求定义为容器使用的资源的最低保证量。
基本上,它将设定容器所要消耗的资源的最小数量。
当一个Pod被调度时,kube-scheduler将检查Kubernetes请求,以便将其分配给一个特定的节点:该节点至少可以满足Pod中所有容器的这个数量。如果请求的数量高于可用的资源,Pod将不会被安排,并保持在Pending状态。
关于Pending状态的更多信息,请查看Understanding Kubernetes Pod pending problems【1】。
在这个例子中,在容器定义中,我们设置了一个请求,要求100m核心的CPU和4Mi的内存。
resources:
requests:
cpu: 0.1
memory: 4Mi
Requests通常被使用在以下场景:
Kubernetes将Limits定义为一个容器使用的最大资源量。
这意味着容器的消耗量永远不能超过指定的内存量或CPU量。
resources:
limits:
cpu: 0.5
memory: 100Mi
Limits通常用于以下场景:
CPU是一种可压缩的资源,这意味着它可以被拉伸,以满足所有的需求。如果进程要求太多的CPU,其中一些将被节制。
CPU代表计算处理时间,以核为单位。
内存是一种不可压缩的资源,意味着它不能像CPU那样被拉伸。如果一个进程没有得到足够的内存来工作,这个进程就会被杀死。
在Kubernetes中,内存的单位是字节。
一个Mebibyte(以及它们的类似物Kibibyte、Gibibyte...)是20字节的2次方。它的出现是为了避免与公制中的Kilo、Mega定义相混淆。你应该使用这个符号,因为它是字节的典型定义,而Kilo和Mega是1000的倍数。
在Kubernetes中,你应该很少使用限制来控制你的资源使用。这是因为如果你想避免饥饿(确保每个重要的进程都能得到它的份额),你应该首先使用请求。
通过设置限制,你只是防止进程在特殊情况下检索额外的资源,在内存方面造成OOM杀戮,在CPU方面造成Throttling(进程将需要等待CPU可以再次使用)。
欲了解更多信息,请查看article about OOM and Throttling【2】。
如果你在一个Pod的所有容器中设置一个等于限制的请求值,该Pod将获得保证的服务质量。
还需要注意的是,资源使用量高于请求的Pod更有可能被驱逐,所以设置非常低的请求会造成弊大于利。可以在Pod eviction and Quality of Service【3】查看。
由于命名空间的存在,我们可以将Kubernetes资源隔离到不同的组,也称为租户。
通过ResourceQuota,你可以为整个命名空间设置一个内存或CPU限制,确保其中的实体不能消耗超过这个数量。
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
spec:
hard:
requests.cpu: 2
requests.memory: 1Gi
limits.cpu: 3
limits.memory: 2Gi
然后,将其应用于你的命名空间。
kubectl apply -f resourcequota.yaml --namespace=mynamespace
你可以用以下方法列出一个命名空间的当前ResourceQuota。
kubectl get resourcequota -n mynamespace
注意,如果你为命名空间中的特定资源设置了ResourceQuota,那么你就需要为该命名空间中的每个Pod指定相应的限制或请求。否则,Kubernetes将返回一个 "failed quota"的错误。
Error from server (Forbidden): error when creating "mypod.yaml": pods "mypod" is forbidden: failed quota: mem-cpu-demo: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
如果你试图添加一个新的Pod,其容器限制或请求超过了当前的ResourceQuota,Kubernetes将返回一个 "exceeded quota "的错误。
Error from server (Forbidden): error when creating "mypod.yaml": pods "mypod" is forbidden: exceeded quota: mem-cpu-demo, requested: limits.memory=2Gi,requests.memory=2Gi, used: limits.memory=1Gi,requests.memory=1Gi, limited: limits.memory=2Gi,requests.memory=1Gi
如果我们想限制一个命名空间可分配的资源总量,ResourceQuotas很有用。但如果我们想给里面的元素提供默认值,会发生什么?
LimitRanges是一种Kubernetes策略,它限制了命名空间中每个实体的资源设置。
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-resource-constraint
spec:
limits:
- default:
cpu: 500m
defaultRequest:
cpu: 500m
min:
cpu: 100m
max:
cpu: "1"
type: Container
以后,如果你创建一个没有设置请求或限制的新Pod,LimitRange会自动为其所有的容器设置这些值。
Limits:
cpu: 500m
Requests:
cpu: 100m
现在,想象一下,你添加一个新的Pod,以1200M为限。你会收到以下错误。
Error from server (Forbidden): error when creating "pods/mypod.yaml": pods "mypod" is forbidden: maximum cpu usage per Container is 1, but limit is 1200m
请注意,默认情况下,Pod中的所有容器将有效地拥有100m CPU的请求,即使没有设置LimitRanges。
为我们的Kubernetes集群选择最佳限制是关键,以便获得最佳的能源消耗和成本。
为我们的Pod分配过多的资源可能会导致成本激增。
规模过小或专用于极少的CPU或内存将导致应用程序不能正常运行,甚至Pod被驱逐。
如前所述,除非在非常特殊的情况下,否则不应该使用Kubernetes限制,因为它们可能会造成更大的伤害。在内存不足的情况下,容器有可能被杀死,在CPU不足的情况下,容器有可能被节流。
对于请求,当你需要确保一个进程获得一个有保障的资源份额时,可以使用它们。
【1】https://sysdig.com/blog/kubernetes-pod-pending-problems/
【2】https://sysdig.com/blog/troubleshoot-kubernetes-oom/
【3】https://sysdig.com/blog/kubernetes-pod-evicted/
原文:https://sysdig.com/blog/kubernetes-limits-requests/
作者:JAVIER MARTÍNEZ
《Docker中Image、Container与Volume的迁移》
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!