文档,https://kubernetes.io/zh-cn/docs/concepts/configuration/manage-resources-containers/
1.Pod 资源限制
1.1 什么是资源限制
在 Kubernetes 集群中,为了使系统能够稳定的运⾏,通常会对 Pod 的资源使⽤量进⾏限制
在 Kubernetes 集群中,如果有⼀个程序出现异常,并占⽤⼤量的系统资源。如果未对该 Pod 进⾏资源限制的话,可能会影响其他的 Pod 正常运⾏,从⽽造成业务的不稳定性
1.2 如何实现资源限制
Kubernetes 通过 Requests
和 Limits
字段来实现对 Pod 的资源进⾏限制
- Requests:启动 Pod 时申请分配的资源⼤⼩;
(Pod在调度的时候requests⽐较重要)
- Limits:限制 Pod 运⾏时最⼤可⽤的资源⼤⼩;
(Pod在运⾏时limits⽐较重要)
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义 cpu 的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
spec.containers[].resources.requests.cpu //定义创建容器时预分配的CPU资源
spec.containers[].resources.requests.memory //定义创建容器时预分配的内存资源
spec.containers[].resources.limits.cpu //定义 cpu 的资源上限
spec.containers[].resources.limits.memory //定义内存的资源上限
1.3 资源限制的⽬的与意义
CPU:为集群中运⾏的容器配置CPU请求和限制
,可以有效利⽤集群上可⽤的 CPU 资源
- 设置 Pod CPU 请求 设定在较低的数值,可以使 Pod 更有机会被调度
- 设置 CPU 限制⼤于 CPU 请求,可以完成如下两件事
- 1、当 Pod 碰到⼀些突发负载时,它可以合理利⽤可⽤的 CPU 资源
- 2、当 Pod 在突发流量期间 可使⽤的 CPU 被限制为合理的数值,从⽽可以避免影响其他 Pod 的正常运⾏;
内存:为集群中运⾏的容器配置内存请求和限制
,可以有效利⽤集群节点上可⽤的内存资源
- 通过将 Pod 的内存请求设定在较低的数值,可以使 Pod 更有机会被调度
- 通过让
内存限制⼤于内存请求
,可以完成如下两件事:- 当 Pod 碰到⼀些突发负载时,可以更好的利⽤其主机上的可⽤内存
- 当 Pod 在突发负载期间
可使⽤的内存被限制为合理的数值
,从⽽可以避免影响其他 Pod 的运⾏
2.资源限制单位换算
2.1 CPU 限制单位
1 核 CPU 等于 1000 毫核,当定义容器为 0.5 时,所能⽤到的 CPU 资源时 1 核⼼ CPU 的⼀半,对于 CPU 资源单位,表达式 0.1
等价于表达式 100m
,可以看作 100 millicpu
在 Kubernetes 系统上,1 个单位的 CPU 相当于虚拟机上的 1 颗虚拟 CPU(vCPU)或物理机上的一个超线程(Hyperthread,或称为一个逻辑 CPU),它支持分数计量方式,一个核心(1core)相当于 1000 个微核心(millicores),因此 500m 相当于是 0.5 个核心,即二分之一个核心
1 核⼼ = 1000 millicpu (1 Core = 1000m)
0.5 核 = 500 millicpu (0.5 Core = 500m)
1 核⼼ = 1000 millicpu (1 Core = 1000m)
0.5 核 = 500 millicpu (0.5 Core = 500m)
💡 说明
m 毫核,cpu 单位;Kubernetes 集群中的每一个节点可以通过操作系统的命令来确认本节点的 CPU 内核数量,然后将这个数量乘以 1000,得到的就是节点总 CPU 总毫数。比如一个节点有四核,那么该节点的 CPU 总毫量为 4000m,如果你要使用 0.5 core,则你要求的是 4000*0.5 = 2000m :::
举例:当我们有 1 个物理 CPU,16 核⼼,如果某个 Pod 最多使⽤⼀半的核⼼数,则表达式可以写⼊如下两种:
limits.cpu: 8
limits.cpu: 8000m 计算公式:(16000*0.5=8000m)
limits.cpu: 8
limits.cpu: 8000m 计算公式:(16000*0.5=8000m)
❌ 注意
Kubernetes 不允许设置精度⼩于 1m 的 CPU 资源。因此当 CPU 单位⼩于 1 时,只能使⽤毫核来表示。例如:期望使⽤ 1 个 CPU 的 0.5%,应该写 5m ⽽不是 0.005
2.2 内存分配单位
内存的基本单位是字节数(Bytes),也可以加上国际单位,⼗进制的 E、P、T、G、M,K、m,或⼆进制的 Ei、Pi、Ti、Gi、Mi、Ki,内存的计量方式与日常使用方式相同
MiB ≠ MB,MB 是十进制单位,MiB 是二进制,平时我们以为 MB 等于 1024KB,其实 1MB=1000KB,1MiB 才等于 1024KiB。中间带字母 i 的是国际电工协会(IEC)定的,走 1024 乘积;KB、MB、GB 是国际单位制,走 1000 乘积
1MB = 1000 KB = 1000000 Bytes
1Mi = 1024 KB = 1048576 bytes
1MB = 1000 KB = 1000000 Bytes
1Mi = 1024 KB = 1048576 bytes
❌ 注意
如果你为某个资源指定了限制,但不指定请求, 并且没有应用准入时机制为该资源设置默认请求, 然后 Kubernetes 复制你所指定的限制值,将其用作资源的请求值
内存的计量方式与日常使用方式相同
2.3 计算
cpu
##查看CPU的限制##
[root@k8s-node1 ~]# docker exec -it 6933185dbe4b /bin/bash
root@pod-limits:/# cd /sys/fs/cgroup/cpu/
root@pod-limits:/sys/fs/cgroup/cpu# cat cpu.cfs_period_us
100000
root@pod-limits:/sys/fs/cgroup/cpu# cat cpu.cfs_quota_us
200000
#反向计算出--cpus参数
#cpu.cfs_quota_us / cpu.cfs_period_us = cpu的限制
root@pod-limits:/sys/fs/cgroup/cpu# expr `cat cpu.cfs_quota_us` / `cat cpu.cfs_period_us`
2
##查看CPU的限制##
[root@k8s-node1 ~]# docker exec -it 6933185dbe4b /bin/bash
root@pod-limits:/# cd /sys/fs/cgroup/cpu/
root@pod-limits:/sys/fs/cgroup/cpu# cat cpu.cfs_period_us
100000
root@pod-limits:/sys/fs/cgroup/cpu# cat cpu.cfs_quota_us
200000
#反向计算出--cpus参数
#cpu.cfs_quota_us / cpu.cfs_period_us = cpu的限制
root@pod-limits:/sys/fs/cgroup/cpu# expr `cat cpu.cfs_quota_us` / `cat cpu.cfs_period_us`
2
cpu.cfs_period_us 和 cpu.cfs_quota_us 来限制该组中的所有进程在单位时间里可以使用的 cpu 时间。 cpu.cfs_period_us:时间周期(微秒); cpu.cfs_quota_us:指的是在 cpu.cfs_period_us 周期内可使用的 cpu 的时间(微秒);多核场景下,如配置 cpu.cfs_period_us=10000,而 cfs_quota_us=20000,表示该 cgroup 可以完全使用 2 个 cpu。所以 cpu 的计算方法为:cfs_quota_us / cpu.cfs_period_us
mem
##查看内存的限制##
[root@k8s-node1 ~]# docker exec -it 6933185dbe4b /bin/bash
root@pod-limits:~# cd /sys/fs/cgroup/memory/
root@pod-limits:/sys/fs/cgroup/memory# cat memory.limit_in_bytes
2147483648 (Byte字节)
内存的计算方法为:2147483648÷1024÷1024÷1024 = 2(G)
##查看内存的限制##
[root@k8s-node1 ~]# docker exec -it 6933185dbe4b /bin/bash
root@pod-limits:~# cd /sys/fs/cgroup/memory/
root@pod-limits:/sys/fs/cgroup/memory# cat memory.limit_in_bytes
2147483648 (Byte字节)
内存的计算方法为:2147483648÷1024÷1024÷1024 = 2(G)
3.实践
安装 metrics-server
官方文档,https://github.com/kubernetes-sigs/metrics-server
requests
kubectl explain pod.spec.containers.resources
kubectl explain pod.spec.containers.resources
[root@kube-master yaml]# cat requests-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
name: busybox
args:
- "/bin/sh"
- "-c"
- "sleep 60000"
resources:
requests: #资源申请
cpu: 500m #容器申请500毫核(一个CPU核心时间的1/2)
memory: 500Mi #容器申请500M内存
[root@kube-master yaml]# cat requests-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
name: busybox
args:
- "/bin/sh"
- "-c"
- "sleep 60000"
resources:
requests: #资源申请
cpu: 500m #容器申请500毫核(一个CPU核心时间的1/2)
memory: 500Mi #容器申请500M内存
- 超出内存
[root@kube-master yaml]# cat requests-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
name: busybox
args:
- "/bin/sh"
- "-c"
- "sleep 60000"
resources:
requests:
cpu: 500m
memory: 2048Mi
nodeName: kube-node01
[root@kube-master yaml]# cat requests-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
name: busybox
args:
- "/bin/sh"
- "-c"
- "sleep 60000"
resources:
requests:
cpu: 500m
memory: 2048Mi
nodeName: kube-node01
[root@kube-master yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
requests-pod 0/1 OutOfmemory 0 4s
[root@kube-master yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
requests-pod 0/1 OutOfmemory 0 4s
[root@kube-master yaml]# kubectl describe pod requests-pod
...
Status: Failed
Reason: OutOfmemory
Message: Pod Node didn't have enough resource: memory, requested: 2147483648, used: 0, capacity: 1934282752
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning OutOfmemory 10s kubelet Node didn't have enough resource: memory, requested: 2147483648, used: 0, capacity: 1934282752
[root@kube-master yaml]# kubectl describe pod requests-pod
...
Status: Failed
Reason: OutOfmemory
Message: Pod Node didn't have enough resource: memory, requested: 2147483648, used: 0, capacity: 1934282752
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning OutOfmemory 10s kubelet Node didn't have enough resource: memory, requested: 2147483648, used: 0, capacity: 1934282752
limits
[root@kube-master yaml]# cat limit-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: limited-pod
spec:
containers:
- image: busybox
command: ["sleep","600000"]
name: busybox
resources:
requests: #资源申请
cpu: 200m #容器申请200毫核(一个CPU核心时间的1/5)
memory: 80Mi #容器申请80M内存
limits: #资源限制
cpu: 2 #容器最大允许使用2核CPU
memory: 2Gi #容器最大允许使用2GB内存
nodeName: kube-node01
[root@kube-master yaml]# cat limit-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: limited-pod
spec:
containers:
- image: busybox
command: ["sleep","600000"]
name: busybox
resources:
requests: #资源申请
cpu: 200m #容器申请200毫核(一个CPU核心时间的1/5)
memory: 80Mi #容器申请80M内存
limits: #资源限制
cpu: 2 #容器最大允许使用2核CPU
memory: 2Gi #容器最大允许使用2GB内存
nodeName: kube-node01
kubectl describe nodes kube-node01
kubectl describe nodes kube-node01
❌ 注意
节点上所有 pod 的资源 limits 之和可以超过节点资源总量的 100%
requests 不同的是,limits 并不会影响 pod 的调度结果
如果只设置了 limit,则 request 默认会根据 limit 自动设定
运⾏超过容器内存限制的应⽤
当节点拥有足够的可用内存时,容器可以使用其请求的内存。但是,容器不允许使用超过其限制的内存
。如果容器分配的内存超过其限制,该容器会成为被终止的候选容器。如果容器继续消耗超出其限制的内存,则终止容器。如果终止的容器可以被重启,则 kubelet 会重新启动它。
[root@kube-master yaml]# cat memory-request-limit-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: memory-request-limit-2
spec:
containers:
- name: memory-request
image: polinux/stress
command: ["stress", "--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"] ## 容器会尝试分配 250 MiB 内
存,这远⾼于 100 MiB 的限制,模拟1个进程产⽣250M内存
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi"
[root@kube-master yaml]# cat memory-request-limit-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: memory-request-limit-2
spec:
containers:
- name: memory-request
image: polinux/stress
command: ["stress", "--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"] ## 容器会尝试分配 250 MiB 内
存,这远⾼于 100 MiB 的限制,模拟1个进程产⽣250M内存
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi"
4.资源配置范围管理 LimitRange
4.1 概念
默认情况下,Kubernetes 中所有容器都没有任何 CPU 和内存限制。LimitRange 用来给 Namespace 增加一个资源限制,包括最小、最大和默认资源。
4.2 为什么需要 LimitRange
为单个容器设置资源 requests 和 limits 很有必要性:
1.提升 QoS 等级,防止在 OOM 时被首先 kill;
2.默认情况下 Pod 会以无限制的 CPU 和内存运行,很有可能因故吞掉所在工作节点上的所有可用计算资源。
通过配置 Pod 的计算资源 Requests 和 Limits,我们可以限制 Pod 的资源使用,但对于 Kubemetes 集群管理员而言,配置每一个 Pod 的 Requests 和 Limits 是烦琐且限制性过强的。更多时,我们需要的是对集群内 Requests 和 Limits 的配置做一个全局的统一的限制。
💡 说明
LimitRange 资源支持限制 Container、Pod 和 PersistentVolumeClaim 三种资源对象的系统资源用量
创建
# more limits.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: limitrange
spec:
limits:
- type: Pod #指定整个pod的资源limits
min: #pod中所有容器的Requests值的总和的下限
cpu: 50m
memory: 5Mi
max: #pod中所有容器的Limits值的总和的上限
cpu: 1
memory: 1Gi
- type: Container #指定容器的资源限制
defaultRequest: #容器Requests默认值
cpu: 100m
memory: 10Mi
default: #容器Limits默认值
cpu: 200m
memory: 100Mi
min: #pod中所有容器的Requests值的下限
cpu: 50m
memory: 5Mi
max: #pod中所有容器的Limits值的上限
cpu: 1
memory: 1Gi
maxLimitRequestRatio: #每种资源Requests与Limits的最大比值
cpu: 4
memory: 10
- type: PersistentVolumeClaim #指定请求PVC存储容量的最小值和最大值
min:
storage: 1Gi
max:
storage: 10Gi
# more limits.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: limitrange
spec:
limits:
- type: Pod #指定整个pod的资源limits
min: #pod中所有容器的Requests值的总和的下限
cpu: 50m
memory: 5Mi
max: #pod中所有容器的Limits值的总和的上限
cpu: 1
memory: 1Gi
- type: Container #指定容器的资源限制
defaultRequest: #容器Requests默认值
cpu: 100m
memory: 10Mi
default: #容器Limits默认值
cpu: 200m
memory: 100Mi
min: #pod中所有容器的Requests值的下限
cpu: 50m
memory: 5Mi
max: #pod中所有容器的Limits值的上限
cpu: 1
memory: 1Gi
maxLimitRequestRatio: #每种资源Requests与Limits的最大比值
cpu: 4
memory: 10
- type: PersistentVolumeClaim #指定请求PVC存储容量的最小值和最大值
min:
storage: 1Gi
max:
storage: 10Gi
查看
#kubectl describe limitranges limitrange
Name: limitrange
Namespace: default
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod cpu 50m 1 - - -
Pod memory 5Mi 1Gi - - -
Container memory 5Mi 1Gi 10Mi 100Mi 10
Container cpu 50m 1 100m 200m 4
PersistentVolumeClaim storage 1Gi 10Gi - - -
#kubectl describe limitranges limitrange
Name: limitrange
Namespace: default
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod cpu 50m 1 - - -
Pod memory 5Mi 1Gi - - -
Container memory 5Mi 1Gi 10Mi 100Mi 10
Container cpu 50m 1 100m 200m 4
PersistentVolumeClaim storage 1Gi 10Gi - - -
LimitRange 中各项配置的意义和特点如下:
- 不论是 CPU 还是内存,在 LimitRange 中,Pod 和 Container 都可以设置 Min、Max 和 Max Limit / Requests Ratio 参数。Container 还可以设置 Default Request 和 Default Limit 参数,而 Pod 不能设置 Default Request 和Default Limit 参数。
- 对 Pod 和 Container 的参数解释如下。
- Container:
- Container 的 Min(上面的 100m 和 3Mi)是 Pod 中所有容器的 Requests 值下限;
- Container 的 Max(上面的 2 和 1Gi)是 Pod 中所有容器的 Limits 值上限;
- Container 的 Default Request(上面的 200m 和 100Mi)是 Pod 中所有未指定 Requests 值的容器的默认 Requests 值;
- Container 的 Default Limit(上面的300m和200Mi)是 Pod 中所有未指定 Limits 值的容器的默认 Limits 值。
- 对于同一资源类型,这 4 个参数必须满足以下关系:Min ≤ Default Request ≤ Default Limit ≤ Max。
- Pod:
- Pod 的 Min(上面的 200m 和 6Mi)是 Pod 中所有容器的 Requests 值的总和下限;
- Pod 的 Max(上面的 4 和 2Gi)是 Pod 中所有容器的 Limits 值的总和上限。
- 容器未指定 Requests 值或者 Limits 值时,将使用 Container 的 Default Request 值或者 Default Limit 值。
- Container 的 Max Limit/Requests Ratio(上面的 5 和 4)限制了 Pod 中所有容器的 Limits 值与 Requests 值的比例上限;而 Pod 的 Max Limit / Requests Ratio(上面的 3 和 2)限制了 Pod 中所有容器的 Limits 值总和与 Requests 值总和的比例上限。
- Container:
- 如果设置了 Container 的 Max,那么对于该类资源而言,整个集群中的所有容器都必须设置 Limits,否则无法成功创建。Pod 内的容器未配置 Limits 时,将使用 Default Limit 的值(本例中的 300m CPU 和 200MiB 内存),如果也未配置 Default,则无法成功创建。
- 如果设置了 Container 的 Min,那么对于该类资源而言,整个集群中的所有容器都必须设置 Requests。如果创建 Pod 的容器时未配置该类资源的 Requests,那么在创建过程中会报验证错误。Pod 里容器的 Requests 在未配置时,可以使用默认值 defaultRequest(本例中的 200m CPU 和 100MiB 内存);如果未配置而且没有使用默认值 defaultRequest,那么默认等于该容器的 Limits;如果容器的 Limits 也未定义,就会报错。
- 对于任意一个 Pod 而言,该 Pod 中所有容器的 Requests 总和都必须大于或等于 6MiB,而且所有容器的 Limits 总和都必须小于或等于 1GiB;同样,所有容器的 CPU Requests 总和都必须大于或等于 200m,而且所有容器的 CPU Limits 总和都必须小于或等于 2。
- Pod里任何容器的 Limits 与 Requests 的比例都不能超过 Container 的Max Limit / Requests Ratio;Pod 里所有容器的 Limits 总和与 Requests 总和的比例都不能超过 Pod 的 Max Limit / Requests Ratio。
❌ 注意
需要注意的是,CPU Limits 强制配置这个选项,在 Kubernetes 集群中默认是开启的;除非在部署kubelet服务时通过设置--cpu-cfs-quota=false
来关闭该限制。
测试
#cat default.yaml
apiVersion: v1
kind: Pod
metadata:
name: default-pod
spec:
containers:
- image: busybox
name: busybox
args:
- /bin/sh
- -c
- sleep 60000
#cat default.yaml
apiVersion: v1
kind: Pod
metadata:
name: default-pod
spec:
containers:
- image: busybox
name: busybox
args:
- /bin/sh
- -c
- sleep 60000
- 查看
[root@kube-master yaml]# kubectl describe pod default-pod
[root@kube-master yaml]# kubectl describe pod default-pod
容器的 requests 和 limits 与我们在 LimitRange 对象中设置的一致
cpu 超限制
# kubectl run cpu-over --image=busybox --restart=Never --requests='cpu=1200m,memory=30Mi' sleep 6000
The Pod "cpu-over" is invalid: spec.containers[0].resources.requests: Invalid value: "1200m": must be less than or equal to cpu limit
# kubectl run cpu-over --image=busybox --restart=Never --requests='cpu=1200m,memory=30Mi' sleep 6000
The Pod "cpu-over" is invalid: spec.containers[0].resources.requests: Invalid value: "1200m": must be less than or equal to cpu limit
内存超限制
# kubectl run cpu-over --image=busybox --restart=Never --requests='cpu=200m,memory=300Mi' sleep 6000
The Pod "cpu-over" is invalid: spec.containers[0].resources.requests: Invalid value: "300Mi": must be less than or equal to memory limit
# kubectl run cpu-over --image=busybox --restart=Never --requests='cpu=200m,memory=300Mi' sleep 6000
The Pod "cpu-over" is invalid: spec.containers[0].resources.requests: Invalid value: "300Mi": must be less than or equal to memory limit
不指定 CPU 和 mem Limits
如果没有为容器指定 CPU 限制,那么容器在可以使用的 CPU 资源是没有上限。因而可以使用所在节点上所有的可用 CPU 资源,这样可能会造成某一个 Pod 占用了大量的 CPU 时间,可能会影响其他的 Pod 正常运行,从而造成业务的不稳定性。
这个也不用担心,在 Kubernetes 中,可以通过LimitRange自动为容器设定,所使用的 CPU 资源和内存资源最大最小值
5.资源配额管理(ResourceQuota)
资源配额管理(Resource Quotas
)通过 ResourceQuota
对象,可以定义资源配额,这个资源配额可以为每个命名空间都提供一个总体的资源限制:它可以限制命名空间中某种类型的对象的总数量上限,也可以设置命名空间中 Pod 可以使用的计算资源的总上限。
在使用资源配额时,需要注意以下两点:
- 如果集群中总的可用资源小于各命名空间中资源配额的总和,那么可能会导致资源竞争。在发生资源竞争时,Kubernetes 系统会遵循先到先得的原则。
- 不管是资源竞争还是配额修改,都不会影响已创建的资源使用对象。
5.1 概念
Kubemetes 可以通过存活探针(liveness probe)检查容器是否还在运行。可以为 pod 中的每个容器单独指定存活探针。如果探测失败,Kubemetes 将定期执行探针并重新启动容器。
资源配额(Resource Quotas)是用来限制用户资源用量的一种机制,限制 Pod 的请求不会超过配额,需要在 namespace 中创建一个 ResourceQuota 对象
资源配额类型:
- 计算资源。包括 cpu 和 memory
- 存储资源。包括存储资源的总量以及指定 storage class 的总量
- 对象数。即可创建的对象的个数
5.2 ResourceQuota 作用
尽管 LimitRange 资源能限制单个容器、Pod 及 PVC 等相关计算资源或存储资源的用量,但用户依然可以创建数量众多的此类资源对象进而侵占所有的系统资源。于是,Kubernetes 提供了 ResourceQuota 资源用于定义名称空间的对象数量或系统资源配额
❌ 注意
LimitRange 应用于单独的 pod,ResourceQuota 应用于命名空间中所有的 pod
5.3 在 Master 中开启资源配额选型
资源配额可以通过在 kube-apiserver 的 --admission-control
参数值中添加 ResourceQuota
参数进行开启。如果在某个命名空间的定义中存在 ResourceQuota,那么对于该命名空间而言,资源配额就是默认开启的。一个命名空间可以有多个 ResourceQuota 配置项。(重启服务的时候会提示:–admission-control has been deprecated, Use --enable-admission-plugins or --disable-admission-plugins instead. Will be removed in a future version.)更换使用 --enable-admission-plugins
即可。
5.3.1 计算资源配额(Compute Resource Quota)
资源配额可以限制一个命名空间中所有 Pod 的计算资源的总和。ResourceQuota 目前支持闲置的计算资源类型如表:
资源名称 | 描述 |
---|---|
cpu | 所有非终止状态的 Pod,CPU Requests 的总和不能超过该值 |
requests.cpu | 所有非终止状态的 Pod,CPU Requests 的总和不能超过该值 |
limits.cpu | 所有非终止状态的 Pod,CPU Limits 的总和不能超过该值 |
memory | 所有非终止状态的 Pod,内存 Requests 的总和不能超过该值 |
requests.memory | 所有非终止状态的 Pod,内存 Requests 的总和不能超过该值 |
limits.memory | 所有非终止状态的 Pod,内存 Limits 的总和不能超过该值 |
5.3.2 存储资源配额(Volume Count Quota)
可以在给定的命名空间中限制所使用的存储资源(Storage Resources)的总量,目前支持的存储资源名称如表:
资源名称 | 描述 |
---|---|
requests.storage | 所有 PVC,存储资源的需求总量不能超过该值 |
persistentvolumeclaims | 在该命名空间中所允许的 PVC 总量 |
storage-class-name.storageclass.storage.k8s.io/requests.storage | 在所有与<storage-class-name> 相关的 PVC 请求的存储总量都不能超过该值,例如 gold.storageclass.storage.k8s.io/requests.storage: 500Gi 表示类型为 gold 的 storageClass 对应的 PVC 的申请存储总量最多可达 500Gi |
storage-class-name.storageclass.storage.k8s.io/persistentvolumeclaims | 所有与<storage-class-name> 相关的 PVC 总数都不超过该值。 |
ephemeral-storage、requests.ephemeral-storage、limits.ephemeral-storage | 本地临时存储(ephemeral-storage)的总量限制 |
5.3.3 对象数量配额(Object Count Quota)
指定类型的对象数量可以被限制,例如,可以通过资源配额来限制在命名空间中创建的 Pod 的最大数量。这种配置可以防止某些用户大量创建 Pod 而迅速耗尽整个集群的 Pod IP 和计算资源。下表列出 ResourceQuota 支持限制的对象类型。
资源名称 | 描述 |
---|---|
configmaps | 在该命名空间中允许存在的 ConfigMap 总数上限。 |
pods | 在该命名空间中能存在的非终止状态 Pod 的总数上限。Pod 的终止状态等价于 Pod 的 status.phase in (Failed, Successded) = true |
replicationcontrollers | 在该命名空间中能存在的 RC 的总数上限。 |
resourcequotas | 在该命名空间中能存在的资源配额的总数上限。 |
services | 在该命名空间中能存在的 Service 的总数上限。 |
services.loadbalancers | 在该命名空间中能存在的 LoadBalancer 类型的 Service 总数上限。 |
services.nodeports | 在该命名空间中能存在的 NodePort 类型的 Service 总数上限。 |
secrets | 在该命名空间中能存在的 Secret 的总数上限。 |
具体表示如下:
count/<resource>.<group>
: 用于非核心(core)组成的资源,例如count/deployments.apps
、count/cronjobs.batch
。count/resource
: 用于核心组的资源,例如count/services
、count/pods
。
5.4 配额的作用域(Quota Scopes)
对每项资源配额都可以单独配置一组作用域,配置了作用域的资源配额只会对符合其作用域的资源使用情况进行计量和限制,作用域范围超出了资源配额的请求都会被报验证错误。下表列出了 ResourceQuota 的 4 种作用域。
作用域 | 说明 |
---|---|
Terminating | 匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod |
NotTerminating | 匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod |
BestEffort | 匹配所有 Qos 是 BestEffort 的 Pod |
NotBestEffort | 匹配所有 Qos 不是 BestEffort 的 Pod |
PriorityClass | 匹配所有引用了所指定的优先级类的 Pods |
其中:
- BestEffort 作用域可以限定资源配额来追踪 Pod 资源的使用。
- 而 Terminating、NotTerminating、NotBestEffort、PriorityClass 除了可以追踪 Pod,还可以追踪 CPU、Limits.cpu、Limits.memory、memory、requests.cpu、 requests.memory 等资源的使用情况。
5.5 资源配额的定义
与 LimitRange 相似,ResourceQuota 也被设置在命名空间中。创建名为 myspace 的命名空间:
kubectl create namespace myspace
kubectl create namespace myspace
创建 ResourceQuota 配置文件 compute-resource.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
kubectl create -f compute-resource.yaml --namespace=myspace
kubectl create -f compute-resource.yaml --namespace=myspace
创建另一个名为 object-counts.yaml 的文件,用于设置对象数量的配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
创建该 ResourceQuota:
kubectl create -f object-counts.yaml --namespace=myspace
kubectl create -f object-counts.yaml --namespace=myspace
查看各 ResourceQuota 的详细信息
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
[root@master1 ]# kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
[root@master1 ]# kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
❌ 注意
资源配额与集群资源总量是完全独立的。资源配额是通过绝对的单位来配置的,这也就意味着如果在集群中新添加了节点,那么资源配额不会自动更新,而该资源配额所对应的命名空间中的对象也不能自动增加资源上限.
5.3 创建
#cat quota-cpu-memory.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-and-mem
spec:
hard:
requests.cpu: 1
requests.memory: 1Gi
limits.cpu: 1500m
limits.memory: 1500Mi
# kubectl apply -f quota-cpu-memory.yaml
resourcequota/cpu-and-mem created
#cat quota-cpu-memory.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-and-mem
spec:
hard:
requests.cpu: 1
requests.memory: 1Gi
limits.cpu: 1500m
limits.memory: 1500Mi
# kubectl apply -f quota-cpu-memory.yaml
resourcequota/cpu-and-mem created
查看
#kubectl describe resourcequotas cpu-and-mem
#kubectl describe resourcequotas cpu-and-mem
测试 resourcequota
- 创建
[root@kube-master yaml]# cat replicas-quota-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: replicas-quota-test
spec:
replicas: 10
selector:
matchLabels:
app: replicas-quota-test
template:
metadata:
labels:
app: replicas-quota-test
spec:
containers:
- name: replicas-quota-test
image: busybox
command: ["/bin/sh","-c","sleep 60000"]
resources:
limits:
cpu: "200m"
memory: "90Mi"
[root@kube-master yaml]# cat replicas-quota-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: replicas-quota-test
spec:
replicas: 10
selector:
matchLabels:
app: replicas-quota-test
template:
metadata:
labels:
app: replicas-quota-test
spec:
containers:
- name: replicas-quota-test
image: busybox
command: ["/bin/sh","-c","sleep 60000"]
resources:
limits:
cpu: "200m"
memory: "90Mi"
- 查看
[root@kube-master yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
replicas-quota-test-84bd8d9fb4-bnbm9 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-ctjdz 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-n2kv9 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-n445x 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-s8jt2 1/1 Running 0 7m6s
[root@kube-master yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
replicas-quota-test-84bd8d9fb4-bnbm9 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-ctjdz 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-n2kv9 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-n445x 1/1 Running 0 7m6s
replicas-quota-test-84bd8d9fb4-s8jt2 1/1 Running 0 7m6s
💡 说明
发现只运行了5个pod,原因是requests的cpu为200(requests值未设置时与limits相同),resourcequotas中requests.cpu的限制值为1500m,所以最多只能新建5个pod
限制可创建对象的个数
- 创建
[root@kube-master yaml]# cat quota-count.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: count-quota
spec:
hard:
pods: 10
replicationcontrollers: 5
secrets: 10
configmaps: 10
persistentvolumeclaims: 5
services: 5
services.loadbalancers: 1
services.nodeports: 2
ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2
[root@kube-master yaml]# cat quota-count.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: count-quota
spec:
hard:
pods: 10
replicationcontrollers: 5
secrets: 10
configmaps: 10
persistentvolumeclaims: 5
services: 5
services.loadbalancers: 1
services.nodeports: 2
ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2
该命名空间最多创建 10 个 pod、5 个 Replication Controller、10 个 Secret、10 个 ConfigMap、4 个 PVC、5 个 Service、1 个 LoadBalancer、2 个 NodePort 和 2 个 StorageClass 为 ssd 的 PVC。
pod | Replication Controller | Secret | ConfigMap | PVC | Service | LoadBalancer | NodePort | ssd PVC |
---|---|---|---|---|---|---|---|---|
10 | 5 | 10 | 10 | 4 | 5 | 1 | 2 | 2 |
- 查看
[root@kube-master yaml]# kubectl apply -f quota-count.yaml
resourcequota/count-quota created
[root@kube-master yaml]# kubectl describe resourcequotas count-quota
Name: count-quota
Namespace: default
Resource Used Hard
-------- ---- ----
configmaps 1 10
persistentvolumeclaims 0 5
pods 11 10
replicationcontrollers 0 5
secrets 1 10
services 3 5
services.loadbalancers 0 1
services.nodeports 1 2
ssd.storageclass.storage.k8s.io/persistentvolumeclaims 0 2
[root@kube-master yaml]# kubectl apply -f quota-count.yaml
resourcequota/count-quota created
[root@kube-master yaml]# kubectl describe resourcequotas count-quota
Name: count-quota
Namespace: default
Resource Used Hard
-------- ---- ----
configmaps 1 10
persistentvolumeclaims 0 5
pods 11 10
replicationcontrollers 0 5
secrets 1 10
services 3 5
services.loadbalancers 0 1
services.nodeports 1 2
ssd.storageclass.storage.k8s.io/persistentvolumeclaims 0 2
6.Pod 服务质量 QoS
容器的资源配置满足以下两个条件:
- Requests ≤ 节点可用资源
- Requests ≤ Limits
6.0 资源
可压缩资源
- Kubernetes 目前支持的可压缩资源是 CPU。
- Pod 可以得到 Requests 配置的 CPU 使用量,而能否使用超过 Requests 值的部分取决于系统的负载和调度。
- 空闲的 CPU 资源按照容器 Requests 值的比例分配。比如容器 A 的 CPU 配置为 Requests 1 Limits 10,容器 B 的 CPU 配置为 Requests 2 Limits 8。初始状态下容器可以用的 CPU 为 3cores,那么 A 和 B 恰好得到再其 Requests 中定义的 CPU 用量,即 1CPU 和 2CPU。如果 A 和 B 都需要更多的 CPU 资源,而恰好此时系统的其他任务释放了 1.5CPU,那么这 1.5CPU 将按照 A 和 B 的 Requests 值的比例 1:2 分配给 A 和 B,即最终 A 可使用 1.5CPU,B 可使用 3CPU。
- 如果 Pod 的 CPU 用来超过了在 Limits 10 中配置的 CPU 用量,那么 cgroups 会对 Pod 中容器的 CPU 用来进行限流(Throttled);如果 Pod 没有配置 Limits 10,那么 Pod 会尝试抢占所有空间的 CPU 资源。
不可压缩资源
- Kubernetes 目前支持的不可压缩资源是内存。
- Pod 可以得到在 Requests 中配置的内存。
- 如果 Pod 的内存用量小于它的 Requests 的配置,那么这个 Pod 可以正常运行(除非出现操作系统级别内存不足等严重问题)。
- 如果 Pod 的内存用量超过它的 Requests 的配置,那么这个 Pod 有可能会被 Kubernetes “杀掉”:
- 比如 Pod A 使用的内存量在 Requests ~ Limits 之间,同一机器上的另一个 Pod B 之前使用的内存小于 Requests 的值,此时 Pod B 压力增大,Pod B 向系统申请的总量不超过自己的 Requests 值的内存,那么 Pod A 可能会直接被 Kubernetes “杀掉”。
- 另一种情况是 Pod A 使用的内存量在 Requests ~ Limits 之间,此时 Kubernetes 将一个新的 Pod 调度到这台机器上,只有 Pod A 使用量超过自己的 Requests 值的内存,那么也可能会直接被 Kubernetes “杀掉”。
- 如果 Pod 的内存用量超过它的 Limits 值,那么操作系统内核会“杀掉”Pod 所有容器的所有进程中内存使用量最多的一个,直到内存不超过 Limits 时为止。
对调度策略的影响
- Kubernetes 的 kube-scheduler 通过计算 Pod 中所有容器的 Requests 总和来决定对 Pod 的调度。
- 不管是 CPU 还是内存,Kubernetes 调度器和 kubelet 都会确保节点上的所有 Pod 的 Requests 总和不会超过在该节点上可分配给容器使用的资源容量上限。
6.1 QoS 定义
QoS(QualityofService),可译为"服务质量等级",或者译作"服务质量保证",是作用在 Pod 上的一个配置,当
Kubernetes 创建一个 Pod 时,它就会给这个 Pod 分配一个 QoS 等级。
在 Kubernetes 的环境中,Kubernetes 允许节点的 Pod 过载使用资源,这意味着节点无法同时满足所有 Pod 以过载的方式运行。因此在内存资源紧缺的情况下,Kubernetes 需要借助 Pod 对象的服务质量和优先级等完成判定,进而挑选对应的 Pod 杀死。Kubernetes 根据 pod 的 Requests 和 Limits 属性,把 Pod 对象归类为三类: Guaranteed(完全可靠的)
、Burstable(弹性波动、较可靠的)
和 BestEffort
(尽力而为、不太可靠的),这三种依次递减的优先级来决定优先“杀掉”哪些容器。
优先级,Guaranteed > BurStabLe > BestEffort
6.2 QoS 类别
Guaranteed(完全可靠的)
如果 Pod 中的所有容器对所有资源类型都定义了 Limits 和 Requests,并且所有容器的 Limits 值都和 Requests 值相等(且都不为 0),那么该 Pod 的 QoS 级别就是 Guaranteed。
❌ 注意
在这种情况下,容器可以不定义 Requests,因为 Requests 值在未定义时默认等于 Limits。
Burstable(弹性波动、较可靠的)
Burstable 级别的 Pod 涉及两种情况:
- Pod 中的一部分容器在一种或多种类型的资源配置中定义了 Requests 值和 Limits 值(都不为 0),且 Requests 值小于 Limits 值。
- Pod 中的一部分容器未定义资源配置(Requests 和 Limits 都未定义)。
❌ 注意
容器未定义 Limits 时,Limits 值默认等于节点资源容量的上限。
BestEffort(尽力而为、不太可靠的)
如果 Pod 中所有容器都未定义资源配置(Requests 和 Limits 都未定义),那么该 Pod 的 QoS 级别就是 BestEffort。
当 Kubernetes 集群内存资源紧缺,优先杀死 BestEffort 类别的容器,因为系统不为该类资源提供任何服务保证,但此类资源最⼤的好处就是能够尽可能的使⽤资源.
如果系统中没有 BestEffort 类别的容器,接下来就轮到 Burstable 类别的容器,如果有多个 Burstable 类别的容器,就看谁的内存资源占⽤多,就优先⼲掉谁。⽐如 A 容器申请 1G 内存资源,实际使⽤了 95%,⽽ B 容器申请了 2G 内存资源,实际使⽤了 80%,但任然会优先⼲掉 A 容器,虽然 A 容器的⽤量少,但与⾃身的 Requests 值相⽐,它的占⽐要⼤于 B 容器。
对于 Guaranteed 类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者 00M 时没有其他更低优先级的 Pod 对象存在,才会干掉 Guaranteed 类容器.
6.3 QoS 的工作特点
在 Pod 的 CPU Requests 无法得到满足(比如节点的系统任务占用过多的 CPU 导致无法分配足够的 CPU 给容器使用)时,容器得到的 CPU 会被限流
由于内存是不可压缩的资源,所以针对内存资源紧缺的情况,会按照以下逻辑处理:
- BestEffort Pod 的优先级最低,在这类 Pod 中运行的进程会在系统内存紧缺时被第一优先“杀掉”。从另一个角度看,由于没有设置资源 Limits,所以在资源充足时它们可以充分利用所有闲置资源。
- Burstable Pod 的优先级居中,这类 Pod 在初始时会被分配较少的可靠资源,但可以按需申请更多资源。如果整个系统内存紧缺,又没有 BestEffort 容器可以被“杀掉”以释放资源,那么这类 Pod 中的进程可能会被“杀掉”。
- Guaranteed Pod 的优先级最高,而且一般情况下这类 Pod 只要不超过其资源 Limits 的限制就不会被“杀掉”。如果整个系统内存紧缺,又没有其他优先级更低的容器可以被“杀掉”以释放资源,那么这类 Pod 中的进程也可能会被“杀掉”。
6.4 OOM 计分规则
OOM(Out Of Memory)计分规则包括如下内容:
- OOM 计分的计算方法:计算进程所使用的内存在系统中所占的百分比,取其中不含百分号的数值,再乘以 10,该结果是进程 OOM 的基础分;将进程 OOM 基础分的分值再加上这个进程 OOM_SCORE_ADJ(分数调整)值,作为进程 OOM 的最终分值(除 root 启动的进程外)。在系统发生 OOM 时,OOM Killer 会优先“杀掉”OOM 计分更高的进程。
- 进程的 OOM 计分的基本分数范围是 0 ~ 1000,如果 A 进程的调整值 OOM_SCORE_ADJ 减去 B 进程的调整值的结果大于 1000,那么 A 进程的 OOM 计分最终值必然大于 B 进程,会优先“杀掉”A 进程。
- 不论调整 OOM_SCORE_ADJ 值为多少,任何进程的最终分值范围也是 0 ~ 1000。
在 Kubernetes 中,不同 QoS 的 OOM 计分调整值如表所示:
QoS | oom_score_adj |
---|---|
Guaranteed | -998 |
BestEffort | 1000 |
Burstable | min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999) |
驱逐
具体地说,当 Kubernetes 所管理的宿主机上不可压缩资源短缺时,就有可能触发 Eviction 驱逐。目前,Kubernetes 为你设置的 Eviction 的默认阈值如下所示:
memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.available<15%
memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.available<15%
当宿主机的 Eviction 阈值达到后,就会进入 MemoryPressure 或者 DiskPressure 状态,从而避免新的 Pod 被调度到这台宿主机上,然后 kubelet 会根据 QoS 的级别来挑选 Pod 进行驱逐,
具体驱逐优先级是:BestEffort -> Burstable -> Guaranteed。
QoS 的级别是通过 Linux 内核 OOM 分数值来实现的,OOM 分数值取值范围在-1000 ~1000 之间。在 Kubernetes 中,常用服务的 OOM 的分值如下:
-1000 => sshd等进程
-999 => Kubernetes 管理进程
-998 => Guaranteed Pod
0 => 其他进程 0
2~999 => Burstable Pod
1000 => BestEffort Pod
-1000 => sshd等进程
-999 => Kubernetes 管理进程
-998 => Guaranteed Pod
0 => 其他进程 0
2~999 => Burstable Pod
1000 => BestEffort Pod
OOM 分数越高,就代表这个 Pod 的优先级越低,在出现资源竞争的时候,就越早被杀掉,分数为-999 和-1000 的进程永远不会因为 OOM 而被杀掉。
❌ 注意
如果期望 Pod 尽可能的不被驱逐,就应当把 Pod 里的每一个 Container 的 requests 和 limits 都设置齐全,并且 requests 和 limits 值要相等。
6.5 案例
创建 Guaranteed 的 Pod
对于 QoS 类为 Guaranteed 的 Pod
Pod 中的每个容器都必须指定内存请求和内存限制,且 Pod 中每个容器内存请求必须等于内存限制
Pod 中的每个容器都必须指定 CPU 请求和 CPU 限制,且 Pod 中每个容器 CPU 请求必须等于 CPU 限制
1.创建⼀个 Pod,容器设置了内存请求和内存限制,值都是 200MiB。容器设置了 CPU 请求和 CPU 限制,值都是 700 milliCPU.
cat pod-qos-guaranteed.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-guaranteed
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
cpu: "500m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "128Mi"
cat pod-qos-guaranteed.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-guaranteed
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
cpu: "500m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "128Mi"
#查看
[root@kube-master ~]# kubectl describe pod pod-qos-guaranteed
。。。
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 500m
memory: 128Mi
。。。
QoS Class: Guaranteed
。。。
#查看
[root@kube-master ~]# kubectl describe pod pod-qos-guaranteed
。。。
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 500m
memory: 128Mi
。。。
QoS Class: Guaranteed
。。。
创建 Burstable 的 Pod
如果满⾜下⾯条件,将会指定 Pod 的 QoS 类为 Burstable:
Pod 不符合 Guaranteed QoS 类的标准
Pod 中⾄少⼀个容器指定了,内存或 CPU 的请求或限制
1.创建⼀个 Pod,容器设置了内存请求 100 MiB,以及内存限制 200MiB
cat pod-qos-burstable.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-burstable
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
memory: "128Mi"
limits:
memory: "128Mi"
cat pod-qos-burstable.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-burstable
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
memory: "128Mi"
limits:
memory: "128Mi"
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-burstable
。。。
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 500m
memory: 128Mi
。。。
QoS Class: Burstable
。。。
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-burstable
。。。
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 500m
memory: 128Mi
。。。
QoS Class: Burstable
。。。
创建 BestEffort 的 Pod
对于 QoS 类为 BestEffort 的 Pod,Pod 中的容器必须 没有设置内存和 CPU 限制或请求
1.创建⼀个 Pod,容器没有设置内存和 CPU 限制或请求
[root@kube-master yaml]# cat pod-qos-besteffort.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-besteffort
spec:
containers:
- name: nginx
image: nginx:latest
[root@kube-master yaml]# cat pod-qos-besteffort.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-besteffort
spec:
containers:
- name: nginx
image: nginx:latest
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-besteffort
...
QoS Class: BestEffort
...
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-besteffort
...
QoS Class: BestEffort
...
创建多容器 Pod
1.创建⼀个 Pod,⼀个容器指定了内存请求 200 MiB。 另外⼀个容器没有指定任何请求和限制。此 Pod 满⾜ Burstable QoS 类的标准。但它不满⾜ Guaranteed QoS 类标准,因为它的⼀个容器设有内存请求
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-mutil
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: '100Mi'
- name: redis
image: redis:latest
apiVersion: v1
kind: Pod
metadata:
name: pod-qos-mutil
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: '100Mi'
- name: redis
image: redis:latest
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-mutil
...
Limits:
memory: 100Mi
Requests:
memory: 100Mi
...
QoS Class: Burstable
...
#查看
[root@kube-master yaml]# kubectl describe pod pod-qos-mutil
...
Limits:
memory: 100Mi
Requests:
memory: 100Mi
...
QoS Class: Burstable
...
6.6 ResourceQuota 和 LimitRange 实践
根据集群用户数量来调整集群配置,以达到这个目的:能控制特定命名空间中的资源使用量,最终实现集群的公平使用和成本控制。
需要实现的功能如下:
- 限制运行状态的 Pod 的计算资源用量。
- 限制持久卷的数量以控制对存储的访问。
- 限制负载均衡器的数量以控制成本。
- 防止滥用网络端口这类稀缺资源。
- 提供默认的计算资源 Requests 以便系统做出更优化的调度。
1. 创建命名空间
创建名为 quota-example 的命名空间,namespace.yaml 文件内容如下:
apiVersion: v1
kind: Namespace
metadata:
name: quota-example
apiVersion: v1
kind: Namespace
metadata:
name: quota-example
- 创建
kubectl create -f namespace.yaml
#查看
kubectl get namespaces | grep -v 'kube'
kubectl create -f namespace.yaml
#查看
kubectl get namespaces | grep -v 'kube'
2.设置限定对象数量的资源配额
通过设置限定对数量的资源配额,可以控制持久存储卷、负载均衡器、NodePort 这些资源的数量。 创建名为 object-counts 的 ResourceQuota,object-counts.yaml 文件内容如下:
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
persistentvolumeclaims: "2"
services.loadbalancers: "2"
services.nodeports: "0"
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
persistentvolumeclaims: "2"
services.loadbalancers: "2"
services.nodeports: "0"
- 创建
kubectl create -f object-counts.yaml --namespace=quota-example
kubectl create -f object-counts.yaml --namespace=quota-example
- 查看
kubectl describe quota object-counts --namespace=quota-example
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
kubectl describe quota object-counts --namespace=quota-example
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
至此,配额系统会自动阻止那些使资源用量超过资源配额限定值的请求
3. 设置限定计算资源的资源配额*
创建一项限定计算资源的资源配额,以限制该命名空间中计算资源的使用总量。
创建名为 compute-resources 的 ResourceQuota,compute-resources.yaml 文件内容如下:
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
- 创建
kubectl create -f compute-resources.yaml --namespace=quota-example
kubectl create -f compute-resources.yaml --namespace=quota-example
- 查看
kubectl describe quota compute-resources --namespace=quota-example
Name: compute-resources
Namespace: quota-example
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
kubectl describe quota compute-resources --namespace=quota-example
Name: compute-resources
Namespace: quota-example
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
配额系统会自动防止在该命名空间中同时拥有超过4个非“终止态”的 Pod。此外,由于该项资源配额限制了 CPU 和 内存的 Limits 和 Requests 总量,因此会强制要求该命名空间中所有的容器都显式定义 CPU 和内存的 Limits、Requests(可使用默认值,Requests 默认等于 Limits)。
4. 配置默认的 Requests 和 Limits
在命名空间已经配置了限定计算资源配额的情况下,如果尝试在该命名空间中创建一个不指定 Requests 和 Limits 的 Pod,那么 Pod 的创建可能会失败。 下面是一个失败的例子。
- 创建
创建一个 Nginx 的 Deployment:
kubectl create deployment nginx --image=nginx --replicas=1 --namespace=quota-example
kubectl create deployment nginx --image=nginx --replicas=1 --namespace=quota-example
- 查看
查看创建的 Pod,会发现 Pod 没有创建成功:
kubectl get pods --namespace=quota-example
No resources found in quota-example namespace.
kubectl get pods --namespace=quota-example
No resources found in quota-example namespace.
kubectl get deployments --namespace=quota-example
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 0/1 0 0 2m38s
kubectl get deployments --namespace=quota-example
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 0/1 0 0 2m38s
再查看 Deployment 的详细信息:
kubectl describe deployments nginx --namespace=quota-example
kubectl describe replicasets nginx-6799fc88d8 --namespace=quota-example
kubectl describe deployments nginx --namespace=quota-example
kubectl describe replicasets nginx-6799fc88d8 --namespace=quota-example
提示创建失败,Master 拒绝这个 ReplicaSet 创建 Pod,因为在这个 Pod 中没有指定 CPU 和 内存的 Requests、Limits
为了避免这种失败,可以使用 LimitRange 为这个命名空间中所有 Pod 都提供一个资源配置的默认值
创建一个名为 limits 的 LimitRange,limits.yaml 文件内容如下:
apiVersion: v1
kind: LimitRange
metadata:
name: limits
spec:
limits:
- default:
cpu: 200m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
apiVersion: v1
kind: LimitRange
metadata:
name: limits
spec:
limits:
- default:
cpu: 200m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
- 创建资源
kubectl create -f limits.yaml --namespace=quota-example
kubectl create -f limits.yaml --namespace=quota-example
- 查看
kubectl describe limitranges --namespace=quota-example
kubectl describe limitranges --namespace=quota-example
在 LimitRange 创建成功后,若用户在该命名空间中创建了未指定资源限制的 Pod,系统就会自动为该 Pod 设置默认的资源限制。
例如,每个新建的未指定资源限制的 Pod 都等价于使用下面的资源限制:
kubectl run nginx --image=nginx --requests=cpu=100m,memory=256Mi --limits=cpu=200m,memory=512Mi --namespace=quota-example
kubectl run nginx --image=nginx --requests=cpu=100m,memory=256Mi --limits=cpu=200m,memory=512Mi --namespace=quota-example
7. Downward API
文档,https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/downward-api/
作用:让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息
DownwardAPI 可以让容器获取 Pod 的相关元数据信息,比如 Pod 名称,Pod 的 IP,Pod 的资源限制等,获取后通过 env、voLume 的方式将相关的环境信息注入到容器中,从而让容器通过环境变量这些信息,来设定容器的运行特性。
- 例如:Nginx 进程根据节点的 CPU 核心数量自动设定要启动的 worker 进程数
- 例如:JVM 虚拟根据 Pod 的内存资源限制,来设定对应容器的堆内存大小
- 例如:获取 Pod 名称,以 Pod 名称注册到某个服务,当 Pod 结束后,调用 prestop 清理对应名称的注册信息
7.1 可注⼊的元数据信息
使⽤ pod.spec.containers.env.valueFrom.fieldRef
可以注⼊的字段有:
metadata.name:Pod对象的名称
metadata.namespace:Pod对象隶属的名称空间
metadata.uid:Pod对象的UID
metadata.abels['<KEY>']:获取LabeL指定KEY对应的值
metadata.annotations['<KEY>']:获取Annotations对应KEY的值
status.podIP:Pod对象的IP地址
status.hostIP:节点IP
status.nodeName:节点名称
spec.serviceAccountName:Pod对象使用的ServiceAccount资源名称
metadata.name:Pod对象的名称
metadata.namespace:Pod对象隶属的名称空间
metadata.uid:Pod对象的UID
metadata.abels['<KEY>']:获取LabeL指定KEY对应的值
metadata.annotations['<KEY>']:获取Annotations对应KEY的值
status.podIP:Pod对象的IP地址
status.hostIP:节点IP
status.nodeName:节点名称
spec.serviceAccountName:Pod对象使用的ServiceAccount资源名称
使⽤pod.spec.containers.env.valueFrom.resourceFieldRef
可以注⼊的字段有:
requests.cpu
requests.memory
limits.cpu
limits.memory
requests.cpu
requests.memory
limits.cpu
limits.memory
7.2 环境变量⽅式注⼊元数据
1.创建 Pod 容器,将 Pod 相关环境变量注⼊到容器中,⽐如(pod 名称、命名空间、标签、以及 cpu、内存的请求和限制)
[root@kube-master yaml]# kubectl apply pod-downward.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-downward
labels:
app: pod-downward
spec:
containers:
- name: pod-downward
image: nginx:latest
command: ['/bin/sh', '-c', 'env']
resources:
limits:
cpu: '200m'
memory: '128Mi'
requests:
cpu: '200m'
memory: '64Mi'
env:
- name: THIS_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: THIS_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: THIS_POD_APP_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: THIS_CPU_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.cpu
- name: THIS_MEMORY_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.memory
divisor: 1Mi # 默认显示为字节,通过divisor调整显示单位为兆
apiVersion: v1
kind: Pod
metadata:
name: pod-downward
labels:
app: pod-downward
spec:
containers:
- name: pod-downward
image: nginx:latest
command: ['/bin/sh', '-c', 'env']
resources:
limits:
cpu: '200m'
memory: '128Mi'
requests:
cpu: '200m'
memory: '64Mi'
env:
- name: THIS_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: THIS_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: THIS_POD_APP_LABEL
valueFrom:
fieldRef:
fieldPath: metadata.labels['app']
- name: THIS_CPU_LIMIT
valueFrom:
resourceFieldRef:
resource: limits.cpu
- name: THIS_MEMORY_REQUEST
valueFrom:
resourceFieldRef:
resource: requests.memory
divisor: 1Mi # 默认显示为字节,通过divisor调整显示单位为兆
- 查看
[root@kube-master yaml]# kubectl logs pod-downward |grep THIS
THIS_CPU_LIMIT=1
THIS_POD_APP_LABEL=pod-downward
THIS_POD_NAME=pod-downward
THIS_MEMORY_REQUEST=64
THIS_POD_NAMESPACE=default
[root@kube-master yaml]# kubectl logs pod-downward |grep THIS
THIS_CPU_LIMIT=1
THIS_POD_APP_LABEL=pod-downward
THIS_POD_NAME=pod-downward
THIS_MEMORY_REQUEST=64
THIS_POD_NAMESPACE=default
7.3 存储卷⽅式注⼊元数据
向容器注入元数据信息的另外一种方式是使用 downwardAPI 存储卷,它将配置的字段数据映射为文件并可通过容器中的挂载进行访问
#查看帮助
kubectl explain pod.spec.volumes.downwardAPI
kubectl explain pod.spec.volumes.downwardAPI.items
kubectl explain pod.spec.volumes.downwardAPI.items.resourceFieldRef
#查看帮助
kubectl explain pod.spec.volumes.downwardAPI
kubectl explain pod.spec.volumes.downwardAPI.items
kubectl explain pod.spec.volumes.downwardAPI.items.resourceFieldRef
在 downwardAPI 存储卷中使用 fieldRef 引用如下两个数据源:
- metadata.labels: Pod 对象的所有标签信息,每行一个,格式为 label-key="escaped-label-value"
- metadata.annotations: Pod 对象的所有注解信息,每行一个,格式为 annotation-key="escaped-annotation-value"。
apiVersion: v1
kind: Pod
metadata:
labels: east-china
rack: rack-101
app: dapi-vol-pod
name: dapi-vol-pod
annotations:
annotation1: "test-value-1"
spec:
containers:
- name: volume-test-container
image: busybox
command: ["/bin/sh", "-c", "sleep 864000"]
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "256m"
volueMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: false
volumes:
- name: podinfo
downwardAPI:
defaultMode: 420
items:
- fieldRef:
fieldPath: metadata.namespace
path: pod_namespace
- fieldRef:
fieldPath: metadata.labels
path: pod_labels
- fieldRef:
fieldPath: metadata.annotations
path: pod_annotations
- resourceFieldRef:
containerName: volume-test-container
resource: requests.memory
divisor: "1Mi"
path: "mem_request"
apiVersion: v1
kind: Pod
metadata:
labels: east-china
rack: rack-101
app: dapi-vol-pod
name: dapi-vol-pod
annotations:
annotation1: "test-value-1"
spec:
containers:
- name: volume-test-container
image: busybox
command: ["/bin/sh", "-c", "sleep 864000"]
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "256m"
volueMounts:
- name: podinfo
mountPath: /etc/podinfo
readOnly: false
volumes:
- name: podinfo
downwardAPI:
defaultMode: 420
items:
- fieldRef:
fieldPath: metadata.namespace
path: pod_namespace
- fieldRef:
fieldPath: metadata.labels
path: pod_labels
- fieldRef:
fieldPath: metadata.annotations
path: pod_annotations
- resourceFieldRef:
containerName: volume-test-container
resource: requests.memory
divisor: "1Mi"
path: "mem_request"
#查看
kubectl exec dapi-vol-pod -- cat /etc/podinfo/pod_labels
#查看
kubectl exec dapi-vol-pod -- cat /etc/podinfo/pod_labels