如何限制Kubernetes资源(CPU和内存)

时间:2020-01-09 10:41:07  来源:igfitidea点击:

默认情况下,当我们创建Pod时,它有权使用主机上的所有系统资源,除非我们对允许的资源添加了限制,或者Container在具有默认CPU限制的命名空间中运行,并且Container会自动分配了默认限制。现在,Linux内核具有可用于限制CPU和内存的cgroup。 docker run使用cgroup来实现这些限制。因此,当我们指定Pod时,我们还可以选择提供容器可能需要的资源限制,以避免过度使用。要指定的最常见资源是CPU和内存(RAM)。

当我们实现这种资源限制时,然后在创建Pod的阶段,调度程序将使用此信息来根据资源的可用性来决定将Pod放置在哪个节点上。 kubelet还至少保留专门用于该容器的系统资源的请求量。

不同的Kubernetes资源类型

在撰写本教程时,有不同的资源类型可以针对Pod和Container施加请求和限制:

  • 中央处理器

  • 记忆

  • 大页面(Kubernetes v1.14或者更高版本)

CPU和内存统称为计算资源,或者仅称为资源。计算资源是可请求,分配和消耗的可测量数量

Pod和容器的资源请求和限制

通常,当我们谈论这种阈值限制时,我们必须有一个软性限制和硬性限制。因此,我们可以为各个Pod和Containers的允许资源定义一个软限制值,以及一个上限,超过该上限将拒绝使用。在Kubernetes中,这种软限制被定义为请求,而硬限制被定义为限制

如果运行Pod的节点有足够的可用资源,则容器有可能(允许)使用比该资源指定的"请求"更多的资源。但是,容器不能使用超过其资源limit的值。

Pod的每个容器可以指定以下一项或者多项:

  • spec.containers []。resources.limits.cpu

  • spec.containers []。resources.limits.memory`

  • spec.containers []。resources.limits.hugepages- <size>

  • spec.containers []。resources.requests.cpu

  • spec.containers []。resources.requests.memory`

  • spec.containers []。resources.requests.hugepages- <size>

说明:

如果容器指定了自己的内存限制,但未指定内存请求,则Kubernetes会自动分配与该限制匹配的内存请求。同样,如果容器指定了自己的CPU限制,但未指定CPU请求,则Kubernetes会自动分配与该限制匹配的CPU请求。

了解资源单位

我们在Kubernetes中使用了一个不同的单位来测量CPU和内存:

定义CPU限制

  • CPU资源的限制和请求以cpu为单位进行度量。

  • Kubernetes中的一个cpu相当于云提供商的1个vCPU/Core和裸机Intel处理器上的1个超线程。

  • 每当我们指定CPU请求或者限制时,我们都会根据CPU内核数来指定它们。

  • 因为通常我们希望将Pod的使用要求或者限制为整个CPU内核的一部分,所以我们可以将CPU的这一部分指定为小数或者毫内核值。

  • 例如,值为0.5表示核心的一半。

  • 还可以使用毫核心值配置请求或者限制。由于单核有1,000毫微微升,因此我们可以将一半的CPU指定为500 m。

  • 可以指定的最小CPU数量为1 m或者0.001.

定义内存限制

  • 限制和对内存的请求以字节为单位。

  • 我们可以使用以下后缀之一将内存表示为纯整数或者定点数字:E,P,T,G,M,K。

  • 我们还可以使用2的幂次方:Ei,Pi,Ti,Gi,Mi,Ki

Kubernetes支持的存储单元

名称字节后缀名称字节后缀
库洛比特1000Kkibibyte1024Ki
兆字节1000*2M兆字节1024*2Mi
千兆字节1000*3G千兆字节1024*3Gi
太字节1000*4T太字节1024*4Ti
千兆字节1000*5P千兆字节1024*5Pi
字节1000*6E字节1024*6Ei

如何管理具有资源限制的Pod

  • 当Kubelet启动容器时,CPU和内存限制将传递给容器运行时,然后运行时负责管理该容器的资源使用情况。

  • 如果我们使用的是Docker,则将CPU限制(以milicores为单位)乘以100,以得到允许容器每100毫秒使用一次的CPU时间。如果CPU处于负载状态,则一旦容器使用了其配额,它就必须等待下一个100毫秒的时间才能继续使用CPU。

  • 在cgroup中运行的不同进程之间共享CPU资源的方法称为完全公平调度程序或者CFS;这是通过在不同cgroup之间划分CPU时间来实现的。

  • 这通常意味着将一定数量的片分配给cgroup。如果一个cgroup中的进程处于空闲状态,并且不使用其分配的CPU时间,则这些共享将可供其他cgroup中的进程使用。

  • 如果达到内存限制,则容器运行时将使用OOM终止容器(并且可能会重新启动)。

  • 如果容器使用的内存超过了请求的数量,则当节点何时开始耗尽内存时,它将成为逐出的候选对象。

这是一个容器被OOM杀死的示例:

Nov 28 23:27:36 worker-1.example.com kernel: Memory cgroup out of memory: Kill process 1331 (mysqld) score 2250 or sacrifice child
Nov 28 23:27:36 worker-1.example.com kernel: Killed process 1331 (mysqld) total-vm:1517000kB, anon-rss:126500kB, file-rss:42740kB, shmem-rss:0kB

示例:定义容器的CPU和内存限制

在定义资源限制时,最好使用单独的名称空间,以使在本练习中创建的资源与群集的其余部分隔离。

[root@controller ~]# kubectl create namespace cpu-limit
namespace/cpu-limit created

验证新创建的NS

[root@controller ~]# kubectl get ns
NAME              STATUS   AGE
cpu-limit         Active   46s
default           Active   24h
kube-node-lease   Active   24h
kube-public       Active   24h
kube-system       Active   24h

在此示例中,我们将创建一个Pod,其中包含2个具有MySQL数据库和Wordpress的容器,并带有一些CPU和内存预留空间。

[root@controller ~]# cat pod-resource-limit.yml
apiVersion: v1
kind: Pod
metadata:
  name: frontend
  namespace: cpu-limit
spec:
  containers:
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

接下来,我们使用以下YAML文件创建pod:

[root@controller ~]# kubectl create -f pod-resource-limit.yml
pod/frontend created

监视新创建的容器的状态:

[root@controller ~]# kubectl get pods  -n cpu-limit -o wide
NAME                         READY   STATUS              RESTARTS   AGE   IP          NODE                   NOMINATED NODE   READINESS GATES
frontend                     0/2     ContainerCreating   0          38s   <none>      worker-1.example.com   <none>           <none>

创建容器可能需要一些时间,并在几秒钟内进行验证:

[root@controller ~]# kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE    IP          NODE                   NOMINATED NODE   READINESS GATES
frontend                    2/2     Running   1          3m6s   10.36.0.2   worker-1.example.com   <none>           <none>

我们可以使用kubectl describe检查Pod的详细信息:

[root@controller ~]# kubectl describe pods frontend
Name:         frontend
Namespace:    cpu-limit
Priority:     0
Node:         worker-1.example.com/192.168.43.49
Start Time:   Sat, 28 Nov 2017 23:31:10 +0530
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.36.0.2
IPs:
  IP:  10.36.0.2
Containers:
...
    State:          Running
      Started:      Sat, 28 Nov 2017 23:31:51 +0530
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     500m
      memory:  128Mi
    Requests:
      cpu:        250m
      memory:     64Mi
    Environment:  <none>

如果未指定CPU限制

如果我们没有为容器指定CPU限制,则适用以下情况之一:

  • 容器在可以使用的CPU资源上没有上限。容器可以使用运行它的节点上所有可用的CPU资源。

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

删除pod

要删除cpu-limit名称空间的pod部分,我们可以使用:

[root@controller ~]# kubectl delete pods -n cpu-limit frontend
pod "frontend" deleted