当Kubernetes调度Pod时,容器是否有足够的资源来实际运行是很重要的。 如果大型应用程序被调度到资源有限的节点上,则节点可能会耗尽内存或CPU资源,并且可能会停止工作!
请求和限制是Kubernetes用于控制CPU和内存等资源的机制。 请求是保证容器能够得到的资源。 如果容器请求资源,Kubernetes会将其调度到可以为其提供该资源的节点上。 另一方面,限制则是确保容器的资源请求永远不会超过某个值。 容器只允许达到限制设定的资源值,无法获得更多资源。
重要的是要记住,限制永远不会低于请求。 如果你试试这个,Kubernetes将抛出一个错误,不会让你运行容器。
请求和限制基于单个容器。 虽然Pod通常包含一个容器,但通常也会看到Pods包含多个容器。 Pod中的每个容器都有自己的限制和请求,但由于Pod总是被认为是一个组,因此您需要将组内每个容器的限制和请求加在一起以获取Pod的聚合值。
有两种类型的资源:CPU和内存(还有GPU卡的资源请求)
Kubernetes调度程序使用这些来确定运行Pod的位置(即哪个节点)。
如果您是在Google Kubernetes Engine
中运行,则默认名称空间已经为您设置了一些请求和限制。
这些默认设置仅仅适用于Hello World
应用,更改成适合您的应用非常重要。
资源的典型Pod spec
可能看起来像这样。 这个Pod有两个容器:
Pod中的每个容器都可以设置自己的请求和限制,这些都是附加的设置。 因此在上面的示例中,Pod的总请求为500 mCPU
,内存为128 MiB
,总需求为1 CPU
和256MiB
。
CPU
CPU资源以毫秒定义。 如果您的容器需要运行两个完整的核心,那么您将设置值2000m
。 如果您的容器只需要1/4
的核心,那么您将设置一个250m
的值。
关于CPU请求要记住的一件事是,如果您输入的值大于最大节点的核心数,则永远不会调度您的Pod。 假设您有一个需要四个核心的Pod,但您的Kubernetes群集由双核VM组成——您的Pod将永远不会被调度!
除非您的应用程序专门用于利用多个核心(科学计算和某些数据库),否则通常最好将CPU请求保持在1
或更低,并运行更多副本以扩展它。 这为系统提供了更大的灵活性和可靠性。
就CPU限制而言,事情其实很有趣。 CPU被认为是可压缩
资源。 如果您的应用程序开始达到您的CPU限制,Kubernetes会开始限制您的容器。 这意味着CPU将受到人为限制,使您的应用程序性能可能更差! 但是,它不会被终止或退出。 您可以使用Liveness
探针的运行状况检查来确保性能未受影响。
内存
内存资源以字节为单位定义。 通常,你给内存一个mebibyte值(这基本上与兆字节相同),实际上你可以提供从字节到PB的任何单位。
和CPU一样,如果您输入的内存请求大于节点上的内存量,则你的Pod永远不会被调度。
与CPU资源不同,内存无法压缩。 因为没有办法限制内存使用量,如果容器超过其内存限制,它将被终止。 如果您的Pod由Deployment
,StatefulSet
,DaemonSet
或其他类型的控制器管理,则控制器会轮转替换。
节点
请务必记住,您无法设置大于节点提供的资源的请求。 例如,如果您拥有一个双核群集,具有2.5
核心请求的Pod则永远不会被调度到这里!
在一个理想的世界里,Kubernetes的容器设置足以照顾好一切,但这个世界是一个黑暗而可怕的地方。 人们很容易忘记设置资源限制,或者流氓团队可以设置非常高的请求和限制,并占用超过他们公平份额的群集。
要防止出现这些情况,可以在命名空间级别设置ResourceQuotas
和LimitRanges
。
创建命名空间后,可以使用ResourceQuotas
将其锁定。ResourceQuotas非常强大,但我们只看看如何使用它们来限制CPU和内存资源的使用。
资源配额可能如下所示:
看一下这个例子,你可以看到有四个部分。 配置每个部分都是可选的。
requests.cpu是命名空间中所有容器的最大组合CPU请求(以毫秒为单位)。 在上面的示例中,您可以拥有50个具有10m
请求的容器,5个具有100m
请求的容器,甚至一个具有500m
请求的容器。 只要命名空间中请求的总CPU和小于500m
!
requests.memory是命名空间中所有容器的最大组合内存请求。 在上面的示例中,您可以拥有50个具有2MiB
请求的容器,5个具有20MiB
请求的容器,甚至是具有100MiB
请求的单个容器。 只要命名空间中请求的总内存小于100MiB
!
limits.cpu是命名空间中所有容器的最大组合CPU限制。 它就像requests.cpu
,但是这里指的是限制。
limits.memory是命名空间中所有容器的最大组合内存限制。 它就像requests.memory
,但是同样地这里指的是限制。
如果您使用的是生产和开发命名空间(与每个团队或服务的命名空间不同),则常见的模式是在生产命名空间上没有配额,在开发命名空间上则是没有严格的配额。 这使得生产能够在流量激增的情况下获取所需的所有资源。
LimitRange(简称limits)基于namespace的资源管理,包括pod和container的最小、最大和default、defaultrequests等。
您还可以在命名空间中创建LimitRange
。 与命名空间作为整体查看的配额不同,LimitRange
适用于单个容器。 这有助于防止人们在命名空间内创建超小容器或超大容器。
一旦创建limits,以后创建资源时,K8S将该limits资源限制条件默认/强制给pod,创建后发现不符合规则,将暂停创建pod。
在创建资源时,用户可以为pod自定义资源管理限制,在创建时会去检查和匹配limits值,发现不匹配将在创建时报错。创建后,该pod的资源使用遵守自定义规则,而不会遵守namespace的limits限制。
LimitRange
可能如下所示:
看一下这个例子,你可以看到有四个部分。 同样,设置每个部分都是可选的。
default section设置容器中容器的默认限制。 如果在limitRange
中设置这些值,则任何未明确设置这些值的容器都将被分配默认值。
defaultRequest section设置Pod中容器的默认请求。 如果在limitRange
中设置这些值,则任何未明确设置这些值的容器都将被分配默认值。
max section将设置Pod中容器可以设置的最大限制。 默认部分不能高于此值。 同样,在容器上设置的限制不能高于此值。 请务必注意,如果设置了此值且默认部分未设置,则任何未自行显式设置这些值的容器都将被指定为最大值作为限制。
min section设置Pod中容器可以设置的最小请求。 defaultRequest
部分不能低于此值。 同样,在容器上设置的请求也不能低于此值。 请务必注意,如果设置了此值且defaultRequest
部分未设置,则min值也将成为defaultRequest
值。
kubectl delete -f lykops-limitrangerange.yaml
cat << EOF > lykops-limitrangerange.yaml
apiVersion: v1
kind: LimitRange
metadata:
namespace: default
name: lykops-limitrange
labels:
project: lykops
app: limitrange
version: v1
spec:
limits:
- max:
cpu: 1
memory: 1Gi
min:
cpu: 0.05
memory: 64Mi
type: Pod
#注意pod只能这么多参数
- default:
cpu: 0.2
memory: 200Mi
defaultRequest:
cpu: 0.01
memory: 16Mi
max:
cpu: 0.25
memory: 256Mi
min:
cpu: 0.005
memory: 8Mi
#container只能这么多参数
type: Container
EOF
kubectl create -f lykops-limitrangerange.yaml
每容器(type: container)
min:资源紧张时,最低保证可以使用的资源是: CPU 0.005个核,内存8M
max:资源空闲时,最大可以使用的资源是:CPU 0.25个核,内存256M
default:默认时,限制使用的资源是:CPU 0.2个核,内存200M
defaultRequest:默认时,最低保证可以使用的资源是: CPU 0.01个核,内存16M
每pod(type: pod)
min:最低保证可以使用的资源是: CPU 0.05个核,内存64M
max最大可以使用的资源是:CPU 1个核,内存1G
使用规则
1、每个namespace应该只有一个limits;
2、limits值设置:
每容器(type: container)
max>=default>=defaultRequest>min
每pod(type: pod)
max>=min
整个
容器的max*容器数<=pod的max
容器的min*容器数<=pod的min
3、创建资源时,pod自定义资源限制的规则:
自定义的单个request>=limits的容器的defaultrequets
自定义的request的总和>=limits的pod的min
自定义的单个limit<=limits的容器的requets
自定义的limit的总和<=limits的pod的max
使用心得
为了防止出现创建资源失败的情况,个人建议:
1、只使用limits的pod或者container中的一种,尽量不使用同时使用,特别在pod中有多容器需求的情况下。
2、尽量使用max,尽量不同时使用max和min
3、由于limits会针对该namespace下的所有新建的pods,所以在该namespace下应该运行哪些资源需求相同的业务
4、在复杂的limits配置下,不要在创建资源时使用自定义配置。
参考: http://dockone.io/article/8152