目前来说,资源隔离尚且属于容器级别,CPU 和 内存 资源的配置需要在 Pod 中的容器上进行,每种资源均可由 "requests" 属性定义其请求的确保可用值,即容器运行可能用不到这些额度的资源,但用到时必须要确保有如此多的资源可用,而 "limits" 属性则用于限制资源可用的最大值,即硬限制。
一个简单的资源需求示例:
- name: JAVA_OPTS value: >- -Xms1536M -Xmx1536M -Xmn512M -Xss300K -XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -Duser.timezone=GMT+08 - name: OTHER_OPTS value: >- -javaagent:/sidecar/jmx_exporter/jmx_prometheus_javaagent.jar=6060:/sidecar/jmx_exporter_config/sample-config.yml resources: limits: cpu: '2' memory: 2Gi requests: cpu: '0' memory: 2Gi
容器资源需求仅能达到为其保证可用的最少资源量的目的,它并不会限制容器的可用资源上限,因此对因应用程序自身存在 Bug 等多种原因而导致的系统资源被长时间占用的情况则无计可施,这就需要通过 limits 属性为容器定义资源的最大可用量。申请分配超过 limits 属性定义的硬限制的内存资源时,它将会被 OOM killer 杀死,不过,随后可能会被其控制器进程所重启,例如,容器进程的 Pod 对象会被杀死并重启(重启策略为 Always 或 OnFailure 时),或者是容器进程的子进程被其父进程所重启。
Kubernetes 系统上运行的关键型业务相关的 Pod 时必须使用 requests 属性为容器定义资源的确保可用量。Kubernetes 的调度器会根据容器的 requests 属性中定义的资源需求量来判定仅哪些节点可接收运行相关的 Pod 资源,而对一个节点的资源来说,每运行一个 Pod 对象,其 request 中定义的请求量都要被预留,直到被所有 Pod 对象瓜分完毕为止。与 requests 不同的是,limits 并不会影响 Pod 的调度结果,也就是说,一个节点上的所有 Pod 对象的 limits 数量之和可以大于节点所拥有的资源量,即支持资源过载使用(overcommitted)。
另外需要说明的是,Kubernetes 仅会确保 Pod 能够获得它们请求(requests)的 CPU 时间额度,它们能否获得额外(throttled)的 CPU 时间,则取决于其他正在使用的作业对 CPU 资源的占用情况。例如:对于总数为 1000m 的 CPU 资源来说,容器A 请求使用 200m,容器B 请求使用 500m,在不超过它们各自的最大限额的前提下,余下的 300m 在双方都需要时会以 2:5(200m:500m)的方式进行配置。
前面曾提到过,Kubernetes 允许节点资源对 limits 的过载使用,这意味着节点无法同时满足其上的所有 Pod 对象以资源满载的方式运行。于是,在内存资源紧缺时,应该以何种次序先后终止哪些 Pod 对象? Kubernetes 无法自行对此作出决策,它需要借助于 Pod 对象的优先级完成判定。根据 Pod 对象的 requests 和 limits 属性,Kubernetes 将 Pod 对象归类到 BestEffort、Burstable 和 Guaranteed 三个服务质量(Quality of Service,QoS)类别下,具体说明如下: