Pod资源配置管理

109 阅读5分钟

kubernetes资源管理概述

pod是最小的原子调度单位,所有和调度以及资源管理的相关属性都应该是pod对象的字段。其中cpu和内存配置是最重要的,比如下面的配置

apiVersion: v1
kind: Pod
metadata:
  name: web-site-pod
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"

在kubernetes中,cpu资源被称为可压缩资源,其特点是当可压缩资源不足时,pod只会饥饿但是不退出;

内存这样的资源被称为不可压缩资源,当不可压缩资源不足时,pod会因为OOM(Out-Of-Memory)被内核杀掉

因为pod可以由多个container组成,所以cpu和内存资源的限额是要配置在每个container上。

  • cpu限制单位是cpu个数,也可以是分数,单位是cpu limits
  • 内存县直单位是bytes1Mi=1024*1024;1M=1000*1000

kubernetes里Pod的CPU和内存资源,还分为limitsrequests两种情况

spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory

在调度的时候,kube-scheduler只会按照requests的值进行计算

在真正设置Cgroups限制的时候,kubelet则会按照limits的值来进行设置

kubernetes的requests+limits的做法实际上的作用是:用户在提交pod时,可以声明一个相对较小的requests值供调度器使用,而kubernetes真正设置给容器cgroup的是相对较大的limits值

kubernetes的QoS模型

不同的requests和limits设置方式,会将这个pod划分到不同的QoS级别中

Guaranteed

当pod里的每个container全部同时设置了requests和limits,并且requests和limits值相等的时候,这个pod就属于Guaranteed类型

apiVersion: v1
kind: Pod
metadata:
  name: qos-pod
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

当这个pod创建之后,它的qosClass字段会被kubernetes自动设置为Guraranteed,

注意当pod只设置了limits而没有设置requests的时候,kubernetes会自动为他设置和limits相同的requests值,这也属于guaranteed情况

Burstable

当pod不满足guaranteed条件,但是至少有一个container设置了requests,这个pod就会被划分到Burstable类别

apiVersion: v1
kind: Pod
metadata:
  name: qos-pod-2
spec:
  containers:
  - name: qos-demo-2-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

BestEffort

如果一个Pod既没有设置requests,也没有设置limits,那么它的QoS类别就是BestEffort

apiVersion: v1
kind: Pod
metadata:
  name: qos-pod-3
spec:
  containers:
  - name: qos-demo-3-ctr
    image: nginx

QoS划分类别场景和Eviction

如上qos分为了guaranteed、burstable、besteffort这三种类别,QoS划分场景是在宿主机资源紧张的时候,kubelet对pod进行Eviction资源回收时需要用到的。

具体来说是当kubernetes所管理的宿主机上不可压缩资源(比如内存)短缺时,就有可能触发Eviction,比如可用内存memory.available,可用的宿主机磁盘空间nodefs.available,容器运行时镜像存储空间imagefs.available

目前,Kubernetes设置的Eviction的默认阈值如下所示,

memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.available<15%

但是各个触发条件在kubelet里都是可配置的

kubelet --eviction-hard=imagefs.available<10%,memory.available<500Mi,nodefs.available<5%,nodefs.inodesFree<5% --eviction-soft=imagefs.available<30%,nodefs.available<10% --eviction-soft-grace-period=imagefs.available=2m,nodefs.available=2m --eviction-max-pod-grace-period=600

Eviction在Kubernetes里其实分为Soft和Hard两种模式

soft类型的Eviction允许设置一段优雅退出时间;

hard类型的Eviction会在阈值到达之后立刻开始。

Kubernetes计算Eviction阈值的数据来源,主要依赖于从Cgroups读取到的值,以及使用cAdvisor监控到的数据。

当宿主机的Eviction阈值达到后,就会进入MemoryPressure或者DiskPressure状态,从而避免新的Pod被调度到这台宿主机上。

而当Eviction发生的时候,kubelet会挑选哪些pod进行删除曹祖哦,会参考pod的QoS类别

  • 首先是BestEffort类别的pod
  • 然后是Burstable类别,并且发生饥饿的资源使用量已经超出了requests的pod
  • 最后是Guaranteed类别。kubernetes会保证只有当Guaranteed类别的pod资源使用量超过了其limits限制,或者宿主机本身正处于memeory pressure状态时,Guaranteed的pod才会被选中进行Eviction操作

对于同QoS类别的Pod来说,Kubernetes还会根据Pod的优先级来进行进一步地排序和选择

cpuset

在使用容器的时候,可以通过设置cpuset把容器绑定到某个CPU的核上,而不是像cpushare那样共享CPU的计算能力。

这种情况下,由于操作系统在CPU之间进行上下文切换的次数大大减少,容器里应用的性能会得到大幅提升。

操作方式分两步

  • 第1步,要保证pod时Guaranteed类型的QoS类型
  • 第2步,需要将Pod的CPU资源的requests和limits设置为同一个相等的整数值即可,比如下面的例子
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
      requests:
        memory: "200Mi"
        cpu: "2"

这时候,该Pod就会被绑定在2个独占的CPU核上。当然,具体是哪两个CPU核,是由kubelet分配的。

ResourceQuota准入控制器

ResourceQuota是一个准入控制器,准入控制器是一段代码,会在请求通过认证和鉴权之后、和对象被持久化到etcd之前这个阶段拦截到达apiserver的请求,准入控制器可以执行验证和变更操作。

在创建了Namespace之后,可以通过ResourceQuota来限制Namespace中资源的使用,包括cpu、内存、存储等

示例如下

apiVersion: v1
kind: Namespace
metadata:
  name: ns2
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mytest-quota
  namespace: ns2
spec:
  hard:
    requests.cpu: 2
    requests.memory: 2Gi
    limits.cpu: 4
    limits.memory: 4Gi
root@k8s-master:~# kubectl apply -f a.yaml
namespace/ns2 created
resourcequota/mytest-quota created
root@k8s-master:~# kubectl get resourcequota -n ns2
NAME           AGE   REQUEST                                     LIMIT
mytest-quota   13s   requests.cpu: 0/2, requests.memory: 0/2Gi   limits.cpu: 0/4, limits.memory: 0/4Gi

注意如果namespace配置了资源限制,那么在创建pod时必须使用resources选项进行限制,比如下面创建pod示例

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx
  name: web-nginx
  namespace: ns2
spec:
  containers:
  - name: web-nginx
    image: nginx
    ports:
    - containerPort: 80 
    resources:
      limits:
        memory: "2Gi"
        cpu: "2"
      requests:
        memory: "1000Mi"
        cpu: "500m"