K8S资源限制与QoS

K8S资源限制与Qos

Kubernetes资源限额是用来限制容器在命名空间内可以使用的CPU和内存资源的机制。通过设置资源请求和限制,可以确保应用在运行时不会超出预设的资源范围,从而实现资源的公平分配和高效利用。资源限额帮助防止某个应用过度消耗资源,保护集群的整体性能和稳定性。

以下是一些常见场景及对应的资源配额措施:

  1. 多租户环境:为每个团队或项目设置命名空间级别的资源配额,以限制CPU和内存使用,防止资源争用。
  2. 高负载应用:对处理高并发请求的应用设置资源请求和限制,确保它们在高负载下仍能稳定运行。
  3. 开发和测试环境:为开发和测试环境设置较低的资源限额,以减少对生产环境的影响,防止测试用例消耗过多资源。
  4. 数据处理任务:针对数据处理或批量任务,设置适当的并发限制和资源配额,确保任务在资源受限的情况下也能有效执行。
  5. 长时间运行的服务:对需要长期运行的服务设置合理的资源请求,确保它们在资源竞争中有足够的可用性。

创建新的命名空间进行测试,避免影响当前集群

[root@master-01 ~]# kubectl create namespace resource-test
namespace/resource-test created

编辑ResourceQuota文件,并创建资源

[root@master-01 ~]# cat resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  namespace: resource-test
  name: resource-test
  labels:
    app: resourcequota
spec:
  hard:
    pods: 5
    requests.cpu: 0.5
    requests.memory: 512Mi
    limits.cpu: 5
    limits.memory: 16Gi
    configmaps: 2
    requests.storage: 40Gi
    persistentvolumeclaims: 20
    replicationcontrollers: 20
    secrets: 20
    services: 50
    services.loadbalancers: "2"
    services.nodeports: "10"
[root@master-01 ~]# kubectl create -f resource-quota.yaml
resourcequota/resource-test created
字段 含义
pods 限制最多启动Pod的个数
requests.cpu 限制最高CPU请求数
requests.memory 限制最高内存的请求数
limits.cpu 限制最高CPU的limit上限
limits.memory 限制最高内存的limit上限

查看资源状态

[root@master-01 ~]# kubectl get -f resource-quota.yaml
NAME            AGE   REQUEST                                                                                                                                                                                                                                                      LIMIT
resource-test   9s    configmaps: 1/2, persistentvolumeclaims: 0/20, pods: 2/5, replicationcontrollers: 0/20, requests.cpu: 100m/500m, requests.memory: 0/512Mi, requests.storage: 0/40Gi, secrets: 0/20, services: 2/50, services.loadbalancers: 0/2, services.nodeports: 0/10   limits.cpu: 500m/5, limits.memory: 0/16Gi
[root@master-01 ~]# kubectl get resourcequotas -n resource-test
NAME            AGE   REQUEST                                                                                                                                                                                                                                                   LIMIT
resource-test   5s    configmaps: 1/2, persistentvolumeclaims: 0/20, pods: 0/5, replicationcontrollers: 0/20, requests.cpu: 0/500m, requests.memory: 0/512Mi, requests.storage: 0/40Gi, secrets: 0/20, services: 0/50, services.loadbalancers: 0/2, services.nodeports: 0/10   limits.cpu: 0/5, limits.memory: 0/16Gi

尝试创建2个ConfigMap,由于限制创建的个数,所以在创建第3个ConfigMap时,会出现提示,并且无法创建

[root@master-01 ~]# kubectl create configmap test-cm0 --from-file=resource-quota.yaml -n resource-test
configmap/test-cm0 created
[root@master-01 ~]# kubectl create configmap test-cm1 --from-file=resource-quota.yaml -n resource-test
error: failed to create configmap: configmaps "test-cm1" is forbidden: exceeded quota: resource-test, requested: configmaps=1, used: configmaps=2, limited: configmaps=2

尝试在resource-test命名空间下创建Deployment控制器,其中包含3个Pod

[root@master-01 ~]# kubectl create deployment resource-test0 --image=registry.cn-guangzhou.aliyuncs.com/caijxlinux/nginx:v1.15.1 --replicas=3 --namespace=resource-test
deployment.apps/resource-test0 created

但是可以观察到对应命名空间下并无创建的Pod,此时使用describe命令也无法查看Deployment控制器无法创建Pod的原因。读者需要describe Deployment控制器下对应的Replicaset控制器才能发现原因。是因为使用了resourcequota资源后,需要指定Pod的CPU和Memory限制。

[root@master-01 ~]# kubectl get pods -n resource-test
No resources found in resource-test namespace.
[root@master-01 ~]# kubectl get deployments.apps -n resource-test
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
resource-test0     0/3     0            0           9m33s
[root@master-01 ~]# kubectl describe deployments.apps -n resource-test resource-test-0
...省略部分输出...
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  115s  deployment-controller  Scaled up replica set resource-test-2-5df655c95 to 3
[root@master-01 ~]# kubectl describe replicasets.apps resource-test0-6f6f5479b7 -n resource-test
...省略部分输出...
Events:
  Type     Reason        Age                  From                   Message
  ----     ------        ----                 ----                   -------
  Warning  FailedCreate  5m44s                replicaset-controller  Error creating: pods "resource-test-6f6f5479b7-78hh2" is forbidden: failed quota: resource-test: must specify limits.cpu for: nginx; limits.memory for: nginx; requests.cpu for: nginx; requests.memory for: nginx

重新设置Pod的资源限制

[root@master-01 ~]# kubectl set resources deployment resource-test0 --limits=cpu=1,memory=512Mi --requests=cpu=500m,memory=256Mi -n resource-test
deployment.apps/resource-test0 resource requirements updated

再次观察Pod的创建状态,此时可以发现Pod已正常创建,但是只创建2个,是因为规划的资源数量只满足创建2个Pod

[root@master-01 ~]# kubectl get rs -n resource-test
NAME                        DESIRED   CURRENT   READY   AGE
resource-test0-7c48fb8b7d   3         2         2       5m52s
[root@master-01 ~]# kubectl describe rs -n resource-test resource-test0-5db45b5775
...省略部分输出...
  Warning  FailedCreate      41s (x9 over 43s)  replicaset-controller  (combined from similar events): Error creating: pods "resource-test0-5db45b5775-sh82m" is forbidden: exceeded quota: resource-test, requested: requests.memory=256Mi, used: requests.memory=512Mi, limited: requests.memory=512Mi

LimitRange

LimitRange 是 Kubernetes 中的一个对象,用于限制 Pod 和容器在特定命名空间中能够请求和使用的资源范围。它可以帮助集群管理员通过定义最小和最大资源请求、资源限制以及默认值,来避免过度消耗资源,确保资源的合理分配。

作用
  1. 设置资源请求和限制的最小/最大值: LimitRange 可以定义容器的 CPU、内存等资源的最小和最大请求值及限制值。这有助于防止 Pod 请求过少或过多资源,避免资源不足或资源浪费。
  2. 为资源未显式指定的 Pod 设置默认请求/限制值: 如果 Pod 没有为某些资源(如 CPU 或内存)显式指定请求或限制值,LimitRange 可以为这些资源自动应用默认的请求和限制。
  3. 控制存储资源: LimitRange 还可以限制持久存储卷的大小,以防止用户在命名空间中请求过大的存储资源。
使用场景
  1. 多租户环境: 在多租户的 Kubernetes 环境下,不同团队或项目共享集群资源。通过 LimitRange,管理员可以确保每个团队不会请求过多或过少的资源,从而避免资源争用或浪费。

  2. 预防资源耗尽: 通过为资源请求设置最小值,防止容器请求过少的资源导致性能问题或容器不稳定。通过设置最大值,可以防止某些容器独占过多资源而影响其他容器的正常运行。

  3. 设置默认值: 如果用户在 Pod 定义中没有设置 CPU 或内存的请求和限制,LimitRange 可以为这些资源指定默认值,确保所有容器都有合理的资源分配。

    [root@master-01 ~]# vim limitrange.yaml
    apiVersion: v1
    kind: LimitRange
    metadata:
     name: cpu-mem-limit-range
    spec:
     limits:
     - default:
         cpu: "1"                   # 1 个 CPU 核心,字符串形式
         memory: 512Mi              # 512 MiB 内存
       defaultRequest:
         cpu: "500m"                # 0.5 个 CPU 核心,单位为 millicores (m)
         memory: 256Mi              # 256 MiB 内存
       type: Container              # 作用于容器级别

    创建资源并查看资源状态

    [root@master-01 ~]# kubectl create -f limitrange.yaml
    limitrange/cpu-mem-limit-range created
    [root@master-01 ~]# kubectl get limitranges
    NAME                  CREATED AT
    cpu-mem-limit-range   2024-10-17T16:53:52Z
    [root@master-01 ~]# kubectl describe limitranges
    Name:       cpu-mem-limit-range
    Namespace:  default
    Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
    ----        --------  ---  ---  ---------------  -------------  -----------------------
    Container   cpu       -    -    500m             1              -
    Container   memory    -    -    256Mi            512Mi          -

    创建Deployment控制器,并且不指定CPU和Memory的参数,观察创建后是否自动配置

    [root@master-01 ~]# kubectl create deployment default-limit --image=registry.cn-guangzhou.aliyuncs.com/caijxlinux/nginx:v1.15.1 --replicas=2
    deployment.apps/default-limit created
    [root@master-01 ~]# kubectl get pods
    NAME                             READY   STATUS    RESTARTS       AGE
    cluster-test-665f554bcc-bhmgt    1/1     Running   70 (26m ago)   3d10h
    default-limit-67587d779b-5qhsl   1/1     Running   0              4s
    default-limit-67587d779b-h9c8l   1/1     Running   0              4s
    [root@master-01 ~]# kubectl describe pod default-limit-67587d779b-5qhsl
    ...省略部分输出...
       Limits:
         cpu:     1
         memory:  512Mi
       Requests:
         cpu:        500m
         memory:     256Mi

    进一步对资源的分配进行控制,限制Container最大/最小CPU和Memory数量

    [root@master-01 ~]# vim limitrange.yaml
    apiVersion: v1
    kind: LimitRange
    metadata:
     name: cpu-mem-limit-range
    spec:
     limits:
     - default:
         cpu: "1"                   # 默认限制为 1 个 CPU 核心
         memory: 512Mi              # 默认限制 512 MiB 内存
       defaultRequest:
         cpu: "500m"                # 默认请求 0.5 个 CPU 核心
         memory: 512Mi              # 默认请求 256 MiB 内存
       max:
         cpu: "2"                   # CPU 限制的最大值为 2 个核心
         memory: 1Gi                # 内存限制的最大值为 1 GiB
       min:
         cpu: "200m"                # CPU 请求的最小值为 200 millicores
         memory: 500Mi              # 内存请求的最小值为 500 MiB
       type: Container              # 作用于容器级别

    在resource-test命名空间下创建资源并查看资源状态

    [root@master-01 ~]# kubectl create -f limitrange.yaml -n resource-test
    limitrange/cpu-mem-limit-range created
    [root@master-01 ~]# kubectl describe limitranges -n resource-test
    Name:       cpu-mem-limit-range
    Namespace:  resource-test
    Type        Resource  Min    Max  Default Request  Default Limit  Max Limit/Request Ratio
    ----        --------  ---    ---  ---------------  -------------  -----------------------
    Container   memory    500Mi  1Gi  512Mi            512Mi          -
    Container   cpu       200m   2    500m             1              -

    修改该命名空间下的Deploymnt控制器的requests的值小于Limitatranges Min值

    [root@master-01 ~]# kubectl edit deployments.apps -n resource-test resource-test0
             requests:
               cpu: 100m
               memory: 256M
    deployment.apps/resource-test0 edited

    可以观察到Deployment控制器创建了新的Replicaset控制器,但是容器无法创建并出现报错,提示容器requests的值小于最小值的限制

    [root@master-01 ~]# kubectl get rs -n resource-test
    NAME                        DESIRED   CURRENT   READY   AGE
    resource-test0-5996f55858   0         0         0       77m
    resource-test0-5db45b5775   5         2         2       67m
    resource-test0-6ddf9fff67   3         0         0       7m10s
    resource-test0-7c48fb8b7d   0         0         0       73m
    [root@master-01 ~]# kubectl describe rs -n resource-test resource-test0-6ddf9fff67
    ...省略部分输出...
     Warning  FailedCreate  4s (x4 over 22s)  replicaset-controller  (combined from similar events): Error creating: pods "resource-test0-6ddf9fff67-2gwxj" is forbidden: [minimum cpu usage per Container is 200m, but request is 100m, minimum memory usage per Container is 500Mi, but request is 256Mi]

    配置Limitrange对存储空间大小的限制

    [root@master-01 ~]# vim limitrange.yaml
    apiVersion: v1
    kind: LimitRange
    metadata:
     name: cpu-mem-limit-range
    spec:
     limits:
     - default:
         cpu: "1"                   # 默认限制为 1 个 CPU 核心
         memory: 512Mi              # 默认限制 512 MiB 内存
       defaultRequest:
         cpu: "500m"                # 默认请求 0.5 个 CPU 核心
         memory: 512Mi              # 默认请求 256 MiB 内存
       max:
         cpu: "2"                   # CPU 限制的最大值为 2 个核心
         memory: 1Gi                # 内存限制的最大值为 1 GiB
       min:
         cpu: "200m"                # CPU 请求的最小值为 200 millicores
         memory: 500Mi              # 内存请求的最小值为 500 MiB
       type: Container              # 作用于容器级别
     - max:
         storage: 2Gi               # PVC 最大存储限制
       min:
         storage: 1Gi               # PVC 最小存储限制
       type: PersistentVolumeClaim  # 作用于持久存储卷

    在resource-test命名空间下创建资源并查看资源状态

    [root@master-01 ~]# kubectl replace -f limitrange.yaml -n resource-test
    limitrange/cpu-mem-limit-range replaced
    [root@master-01 ~]# kubectl describe limitranges -n resource-test cpu-mem-limit-range
    Name:       cpu-mem-limit-range
    Namespace:  resource-test
    Type        Resource  Min    Max  Default Request  Default Limit  Max Limit/Request Ratio
    ----        --------  ---    ---  ---------------  -------------  -----------------------
    Container   memory    500Mi  1Gi  512Mi            512Mi          -
    Container   cpu       200m   2    500m             1              -

    尝试创建大小为5G的PVC资源,此时由于资源的限制,PVC创建失败

    [root@master-01 ~]# kubectl create -f pvc.yaml -n resource-test
    Error from server (Forbidden): error when creating "pvc.yaml": persistentvolumeclaims "myclaim" is forbidden: maximum storage usage per PersistentVolumeClaim is 2Gi, but request is 5Gi

    当修改大小为1G时,PVC创建成功

    [root@master-01 ~]# cat pvc.yaml | grep storage:
         storage: 1Gi
    [root@master-01 ~]# kubectl create -f pvc.yaml -n resource-test
    persistentvolumeclaim/myclaim created
服务质量QOS

Kubernetes 中的 QoS (Quality of Service,服务质量) 是一种机制,用来为不同的 Pod 提供资源保障和优先级划分,帮助集群在资源紧张时更好地管理和分配 CPU 和内存资源。通过 QoS,Kubernetes 可以确保关键的应用在资源争用情况下得到优先照顾,并提供不同的资源保障级别。

Kubernetes 使用 Pod 的 资源请求(requests)和 资源限制(limits)来定义 QoS 类别。这些类别帮助 Kubernetes 决定哪些 Pod 在资源压力下应该优先获得资源或首先被驱逐(evicted)。

字段 含义
Guaranteed(保证) 最高服务质量,当 Pod 中所有容器的 资源请求资源限制 都被设置且相等时,Pod 会被归类为 Guaranteed。当宿主机内存不够时,会先kill掉QoS为BestEffort和Burstable的Pod,如果内存还是不够,才会kill掉QoS为Guaranteed,该级别Pod的资源占用量一般比较明确,即requests的cpu和memory和limits的cpu和memory配置的一致。适用于关键应用或高优先级的服务,需要确保获得足够的 CPU 和内存资源,即使在资源紧张的情况下也不会被驱逐。
Burstable(突发型) 如果 Pod 设置了资源请求但没有为所有容器都设置资源限制,或者资源请求和限制的值不同,那么这个 Pod 会被归类为 Burstable。服务质量低于Guaranteed,当宿主机内存不够时,会先kill掉QoS为BestEffort的Pod,如果内存还是不够之后就会kill掉QoS级别为Burstable的Pod,用来保证QoS质量为Guaranteed的Pod,该级别Pod一般知道最小资源使用量,但是当机器资源充足时,还是想尽可能的使用更多的资源,即limits字段的cpu和memory大于requests的cpu和memory的配置。适用于对资源要求较灵活的应用。在资源充足时允许超出基本需求进行突发使用,而在资源紧张时优先确保基本需求。
BestEffort(尽力而为) 如果 Pod 没有设置任何资源请求或限制,它会被归类为 BestEffort。这种情况下,Pod 没有任何资源保证,是最容易被驱逐的。当宿主机内存不够时,首先kill的就是该QoS的Pod,用以保证Burstable和Guaranteed级别的Pod正常运行。适用于对资源需求不敏感的服务或者开发阶段的应用。
QoS 使用场景
  1. 生产环境中的关键应用: 对于像数据库、支付系统等关键业务应用,保证高可用性和资源稳定性至关重要。可以通过将它们的 Pod 设置为 Guaranteed 来确保其获得稳定的资源,避免因资源争用导致性能下降或宕机。
  2. 允许突发性能的应用: 对于一些非关键的应用或后台服务,可以使用 Burstable,确保它们在正常情况下获得足够的资源,同时在资源允许时支持突发性能。如果资源紧张,它们仍会保持基础服务不被打断。
  3. 开发、测试阶段的应用: 开发和测试环境中的应用可以使用 BestEffort,在不需要高资源保证的情况下运行。这有助于更高效地利用资源,降低集群运行成本。

创建qos-example命名空间

[root@master-01 ~]# kubectl create namespace qos-example
namespace/qos-example created

创建QoS类型为Guaranteed的Pod。要求:Pod中的每个容器必须指定limits.memory和requests.memory,并且两者需要相等;Pod中的每个容器必须指定limits.cpu和limits.memory,并且两者需要相等。

[root@master-01 ~]# vim guaranteed.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: registry.cn-guangzhou.aliyuncs.com/caijxlinux/nginx:v1.15.1
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

创建资源并查看资源状态

[root@master-01 ~]# kubectl create -f guaranteed.yaml
pod/qos-demo created
[root@master-01 ~]# kubectl get pods -n qos-example
NAME       READY   STATUS    RESTARTS   AGE
qos-demo   1/1     Running   0          2m11s

通过describe命令查看Pod对应的QoS类型为Guaranteed

[root@master-01 ~]# kubectl describe pod -n qos-example qos-demo
...省略部分输出...
QoS Class:                   Guaranteed
...省略部分输出...

创建QoS类型为Burstable的Pod。要求:Pod不符合Guaranteed的配置要求;Pod中至少有一个容器配置了requests.cpu或requests.memory

[root@master-01 ~]# vim burstable.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: qos-example
spec:
  containers:
    - name: qos-demo-2-ctr
      image: registry.cn-guangzhou.aliyuncs.com/caijxlinux/nginx:v1.15.1
      resources:
        limits:
          memory: "200Mi"
        requests:
          memory: "100Mi"

创建资源并查看资源状态

[root@master-01 ~]# kubectl create -f burstable.yaml
pod/qos-demo-2 created

通过describe命令查看Pod对应的QoS类型为Burstable

[root@master-01 ~]# kubectl describe pods -n qos-example qos-demo-2
...省略部分输出...
QoS Class:                   Burstable

创建QoS类型为BestEffort的Pod

[root@master-01 ~]# vim besteffort.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: qos-example
spec:
  containers:
    - name: qos-demo-3-ctr
      image: registry.cn-guangzhou.aliyuncs.com/caijxlinux/nginx:v1.15.1

创建资源并查看资源状态

[root@master-01 ~]# kubectl create -f besteffort.yaml
pod/qos-demo-3 created

通过describe命令查看Pod对应的QoS类型为BestEffort

[root@master-01 ~]# kubectl describe pod -n qos-example qos-demo-3
...省略部分输出...
QoS Class:                   BestEffort