在 Kubernetes 中使用容器时,了解涉及的资源是什么以及为何需要它们很重要。有些进程比其他进程需要更多的 CPU 或内存。这很关键,永远不应该让进程挨饿。知道了这一点,我们应该正确配置容器和 Pod,以便充分利用两者。
使用 Kubernetes 时,限制和请求是重要的设置。本文将重点关注两个最重要的:CPU 和内存。
Kubernetes 将限制定义为 容器可以使用的**最大资源量。**这意味着容器永远不会消耗超过指示的内存量或 CPU 量。
另一方面,请求是为容器保留的最低保证资源量。
让我们来看看这个部署,我们在 CPU 和内存上为两个不同的容器设置限制和请求。
kind: Deployment
apiVersion: extensions/v1beta1
# …
template:spec:containers:- name: redisimage: redis:5.0.3-alpineresources:limits:memory: 600Micpu: 1requests:memory: 300Micpu: 500m- name: busyboximage: busybox:1.28resources:limits:memory: 200Micpu: 300mrequests:memory: 100Micpu: 100m
假设我们正在运行一个集群,例如,具有 4 核和 16GB RAM 节点。我们可以提取出很多信息:
Kubernetes 将请求定义为容器使用的保证最小资源量。
基本上,它将设置容器消耗的最小资源量。
当一个 Pod 被调度时,kube-scheduler 将检查 Kubernetes 请求,以便将它分配给一个特定的节点,该节点至少可以满足 Pod 中所有容器的数量。如果请求的数量高于可用资源,则 Pod 将不会被调度并保持在 Pending 状态。
有关挂起(pending)
状态的更多信息,请查看了解 Kubernetes Pod 挂起问题:
https://sysdig.com/blog/kubernetes-pod-pending-problems/
在此示例中,在容器定义中我们设置了 100m CPU 核和 4Mi 内存的请求:
resources:requests:cpu: 0.1memory: 4Mi
使用请求:
Kubernetes 将限制定义为容器可以使用的最大资源量。
这意味着容器永远不会消耗超过指示的内存量或 CPU 量。
resources:limits:cpu: 0.5memory: 100Mi
使用限制:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NymVkZha-1670471516534)(https://files.mdnice.com/user/23818/c5a5802c-73ed-42ee-a15c-509e6d4a1901.png)]
CPU 是一种可压缩资源,这意味着它可以被拉伸以满足所有需求。如果进程请求太多 CPU,其中一些将被限制。
CPU代表计算处理时间,以核为单位。
内存是一种不可压缩的资源,这意味着它不能像 CPU 那样被拉伸。如果一个进程没有足够的内存来工作,这个进程就会被杀死。
内存在 Kubernetes 中以字节为单位。
1 Mebibyte(及其类似物 Kibibyte、Gibibyte 等)是 2 的 20 次方字节。它的创建是为了避免与公制的 Kilo、Mega 定义混淆。您应该使用这种表示法,因为它是字节的规范定义,而 Kilo 和 Mega 是 1000 的倍数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cve5zyG-1670471516538)(https://files.mdnice.com/user/23818/2f7f4a06-9863-449e-b9d2-c4e7d2cfec4c.png)]
在极少数情况下,您应该使用限制来控制 Kubernetes 中的资源使用。这是因为如果你想避免饥饿(确保每个重要进程都得到它的份额),你应该首先使用请求。
通过设置限制,你只是防止进程在异常情况下获取额外的资源,在内存的情况下导致 OOM kill,在 CPU 的情况下 Throttling(进程将需要等待直到 CPU 可以再次使用)。
有关详细信息,请查看有关 OOM 和节流的文章:
https://sysdig.com/blog/troubleshoot-kubernetes-oom/
如果您将 Pod 的所有容器中的请求值设置为等于限制,则该 Pod 将获得有保证的服务质量。
另请注意,资源使用率高于请求的 Pod 更有可能被驱逐,因此设置非常低的请求弊大于利。有关更多信息,请查看有关 Pod 驱逐和服务质量的文章:
https://sysdig.com/blog/kubernetes-pod-evicted/
多亏了命名空间,我们可以将 Kubernetes 资源隔离到不同的组中,也称为租户。
使用ResourceQuotas,您可以为整个命名空间设置内存或 CPU 限制,确保其中的实体不能从该数量中消耗更多。
apiVersion: v1
kind: ResourceQuota
metadata:name: mem-cpu-demo
spec:hard:requests.cpu: 2requests.memory: 1Gilimits.cpu: 3limits.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
如果您尝试添加容器限制或请求超过当前 ResourceQuota 的新 Pod,Kubernetes 将返回“超出配额”错误:
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: 500mdefaultRequest:cpu: 500mmin:cpu: 100mmax:cpu: "1"type: Container
default
: 如果未指定,创建的容器将具有此值。min
:创建的容器不能有小于此的限制或请求。max
: 创建的容器不能有比这更大的限制或请求。稍后,如果您创建一个没有设置请求或限制的新 Pod,LimitRange 会自动将这些值设置到它的所有容器:
Limits:cpu: 500mRequests:cpu: 100m
现在,假设您添加了一个限制为 1200M 的新 Pod。您将收到以下错误:
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
请注意,默认情况下,即使未设置 LimitRanges,Pod 中的所有容器也实际上请求 100m CPU。
为 Kubernetes 集群选择最佳限制是获得最佳能耗和成本的关键。
为 Pod 规模过大或投入过多资源可能会导致成本飙升。
过小的规模或者只占用很少的 CPU 或内存将导致应用程序不能正确执行,甚至会驱逐 Pods。
如前所述,可以不使用 Kubernetes 限制,除非在非常特殊的情况下,因为它们可能弊大于利。在内存不足的情况下,容器有可能被杀死,或者在 CPU 不足的情况下,容器可能会被限制。
对于请求,当您需要确保进程获得有保证的资源共享时请使用它。
作者:JAVIER MARTÍNEZ
原文:https://sysdig.com/blog/kubernetes-limits-requests/