k8s 资源限制

k8s 资源限制

Kubernetes 对资源的限制实际上是通过 CGROUP 来控制的,CGROUP 是容器的一组用来控制内核如果运行进程的相关属性集合。针对内存、CPU、和各种设备都有对应的 CGROUP

默认情况下,Pod 运行没有 CPU 和内存的限额。这意味着系统中任何 Pod 将能够执行该节点所有的运算资源,消耗足够多的 CPU 和内存。一般会针对某些应用的 Pod 资源进行资源限制,这个资源限制是通过 resources 的 requests 和 limits 来实现

spec:
  containers:
  - image: wangyanglinux/myapp:v1
    name: auth
    resources:
      limits:
        cpu: "4"
        memory: 2Gi
      requests:
        cpu: 250m
        memory: 250Mi

requests 要分配的资源,limits 为最高请求的资源,可以理解为初始值和最大值

1.1 资源限制 - 名称空间

1.1.1 计算资源配额

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
  namespace: spark-cluster
spec:
  hard:
    requests.cpu: "20"		#20个核心
    requests.memory: 100Gi
    limits.cpu: "40"		#40个核心
    limits.memory: 200Gi

1.1.2 配置对象数量配额限制

apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
  namespace: spark-cluster
spec:
  hard:
    pods: "20"		#最大创建的pod数量
    configmaps: "10"		#configmap数量
    persistentvolumeclaims: "4"		#pvc
    replicationcontrollers: "20"		#rc最大10个
    secrets: "10"
    services: "10"
    services.loadbalancers: "2"

1.1.3 配置 CPU 和 内存 limitrange

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
  namespace: example
spec:
  limits:
  - default:  # 默认限制值,如果在当前命名空间没做限制的话
      memory: 512Mi
      cpu: 2
    defaultRequest:  # 默认请求值
      memory: 256Mi
      cpu: 0.5
    max:  # 最大的资源限制
      memory: 800Mi
      cpu: 3
    min:  # 最小限制
      memory: 100Mi
      cpu: 0.3
    maxLimitRequestRatio:  # 超售值
      memory: 2
      cpu: 2
    type: Container # Container / Pod / PersistentVolumeClaim

2.1 指定内存请求和内存限制

//配置文件中的args部分在容器启动时为容器提供参数。"--vm-bytes", "150M"参数告诉容器尝试分配 150 MiB 的内存
apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
//创建 Pod
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example
//验证 Pod 容器是否正在运行
kubectl get pod memory-demo --namespace=mem-example
//查看 Pod 的详细信息:
kubectl get pod memory-demo --output=yaml --namespace=mem-example

//输出显示 Pod 中的一个 Container 的内存请求为 100 MiB,内存限制为 200 MiB
...
resources:
  requests:
    memory: 100Mi
  limits:
    memory: 200Mi
...

//查看内存
kubectl top pod memory-demo --namespace=mem-example

//删除你的 Pod:
kubectl delete pod memory-demo --namespace=mem-exampl

3.1 超过容器的内存限制

如果节点有可用内存,容器可能会超出其内存请求。但是一个容器不允许使用超过它的内存限制。如果 Container 分配的内存超过其限制,则该 Container 将成为终止的候选者。如果 Container 继续消耗超出其限制的内存,则 Container 将被终止。如果可以重新启动终止的容器,则 kubelet 会重新启动它,就像任何其他类型的运行时故障一样。

在本练习中,您将创建一个尝试分配超过其限制的内存的 Pod。以下是 Pod 的配置文件,该 Pod 有一个 Container,其内存请求为 50 MiB,内存限制为 100 MiB:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

在args配置文件部分,您可以看到 Container 将尝试分配 250 MiB 的内存,这远高于 100 MiB 的限制

//创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

//查看 Pod 的详细信息:
kubectl get pod memory-demo-2 --namespace=mem-example

//此时,容器可能正在运行或被终止。重复前面的命令,直到 Container 被杀死
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          24s

//获取容器状态的更详细视图:
kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

//输出显示 Container 因为内存不足(OOM)而被杀死:
lastState:
   terminated:
     containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
     exitCode: 137
     finishedAt: 2017-06-20T20:52:19Z
     reason: OOMKilled
     startedAt: null

//本练习中的 Container 可以重启,所以 kubelet 会重启它。重复此命令几次,可以看到Container被反复杀死并重新启动:
kubectl get pod memory-demo-2 --namespace=mem-example

//输出显示容器被杀死,重新启动,再次被杀死,再次重新启动,等等:
kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          37s

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-2   1/1       Running   2          40s

//查看有关 Pod 历史记录的详细信息:
kubectl describe pod memory-demo-2 --namespace=mem-example

//输出显示 Container 反复启动和失败
.. Normal  Created   Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff   Back-off restarting failed container

//查看有关集群节点的详细信息:
kubectl describe nodes

//输出包括由于内存不足情况而被杀死的 Container 的记录
Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

//删除你的 Pod:
kubectl delete pod memory-demo-2 --namespace=mem-example

4.1 指定对您的节点来说太大的内存请求

内存请求和限制与容器相关联,但将 Pod 视为具有内存请求和限制是很有用的。Pod 的内存请求是 Pod 中所有 Container 的内存请求的总和。同样,Pod 的内存限制是 Pod 中所有容器的限制之和。

Pod 调度基于请求。只有当 Node 有足够的可用内存来满足 Pod 的内存请求时,才会安排 Pod 在 Node 上运行。

在本练习中,您将创建一个 Pod,该 Pod 的内存请求非常大,以至于超过了集群中任何节点的容量。这是一个 Pod 的配置文件,它有一个 Container 请求 1000 GiB 内存,这可能超过了集群中任何节点的容量

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-3
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "1000Gi"
      limits:
        memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
//创建 Pod:
kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

//查看 Pod 状态:
kubectl get pod memory-demo-3 --namespace=mem-example

//输出显示 Pod 状态为 PENDING。即 Pod 不会被调度在任何 Node 上运行,它会无限期地保持在 PENDING 状态:
kubectl get pod memory-demo-3 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-3   0/1       Pending   0          25s

//查看有关 Pod 的详细信息,包括事件:
kubectl describe pod memory-demo-3 --namespace=mem-example

//输出显示,由于节点内存不足,无法调度容器:
Events:
  ...  Reason            Message
       ------            -------
  ...  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient memory (3).
  
  
//删除你的 Pod:
kubectl delete pod memory-demo-3 --namespace=mem-example

5.1 内存单元

内存资源以字节为单位。您可以将内存表示为普通整数或带有以下后缀之一的定点整数:E、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Ki。例如,以下表示大致相同的值

128974848, 129e6, 129M, 123Mi

6.1 如果不指定内存限制

如果您不为 Container 指定内存限制,则适用以下情况之一:

  • Container 对其使用的内存量没有上限。容器可以使用它正在运行的节点上的所有可用内存,这反过来又可以调用 OOM Killer。此外,在 OOM Kill 的情况下,没有资源限制的容器将有更大的机会被杀死。

  • Container 在具有默认内存限制的命名空间中运行,并且自动为 Container 分配了默认限制。集群管理员可以使用 LimitRange 来指定内存限制的默认值

posted @ 2022-08-10 13:29  liwenchao1995  阅读(735)  评论(0编辑  收藏  举报