k8s
  • Initial page
  • 序言
  • 前言
    • 发展历史
    • CNCF - 云原生计算基金会简介
    • Kubernetes与云原生应用的概念
  • 概念与原理
    • 基本概念总结
    • 开放接口
      • CRI - Container Runtime Interface
      • CNI - Container Network Interface
      • CSI - Container Storage Interface
    • 核心概念与原理
      • Kubernetes简介
      • Kubernetes架构与原理
      • 核心组件
      • 设计理念
      • 核心组件原理
        • etcd概念与原理
          • Etcd基于RAFT的一致性
          • Etcd v2 与 v3存储
        • kube-apiserver
        • kube-scheduler
        • kube-Controller Manager
        • Kubelet
        • kubectl常用命令
      • kubectl
      • kube-proxy
      • IPVS负载均衡
      • kube-dns
      • Federation-集群联邦
      • kubeadm
    • 资源对象与基本概念解析
    • 资源对象
      • Pod
        • Pod概述
        • Pod解析
        • Pod 的生命周期
        • 探针
        • Init 容器
        • Pause容器
        • Pod 安全策略
        • Pod hook
        • Pod Preset
        • pod其他设置
        • Pod中断与PDB
    • Kubernetes中的网络
      • 图解Kubernetes网络(一)
      • 图解Kubernetes网络(二)
      • 图解Kubernetes网络(三)
      • calico
      • flannel
    • 转发K8S后端服务的四种方式
    • 集群资源对象
      • Node
      • Namespace
      • Label
      • Annotation
      • Taint和Toleration(污点和容忍
      • 垃圾收集
      • Autoscaling
      • Horizontal Pod Autoscaling
        • Metrics-Server
        • Heapster
      • ReplicationController和ReplicaSet
    • 控制器资源对象
      • CronJob
      • Job
      • DaemonSet
      • Deployment
      • StatefulSet
    • 服务发现-资源对象
      • DNS原理讲解
      • Ingress 选型
      • Service
      • Ingress
    • 存储对象
      • ConfigMap
      • Volume
      • Persistent Volume(持久化卷)
      • StorageClass
      • 本地持久化存储
      • Secret
    • 策略对象
      • Resource Quota
      • SecurityContext
    • 身份对象
      • 认证
      • Service Account
      • RBAC——基于角色的访问控制
      • 准入控制
      • Network Policy
    • 资源调度
      • QoS(服务质量等级)
  • 插件扩展
    • Kubernetes的CI/CD
    • Dashboard
    • CoreDNS
    • 监控
      • 概述
      • 第1章 采集
        • Probes
        • Docker Stats
        • cAdvisor
        • Heapster
          • HPA
        • metrics-server
        • custom metrics自定义指标
        • kube-state-metrics
        • node-exporter
        • Prometheus
          • go 自定义metric
          • 本地存储
          • Prometheus概述
          • Prometheus基本架构
          • Prometheus部署方案
          • Prometheus的配置与服务发现
          • PromQL查询解析
          • Prometheus数据可视化
          • Prometheus存储机制
        • Sysdig
        • Untitled
      • 自定义监控
      • Custom-Metrics及Prometheus监控系统
      • grafana各种类型监控-实用
    • 日志
    • 存储
      • Kubernetes Ceph 工作原理详解
    • Metrics
    • GPU
    • Cluster AutoScaler
    • CI/CD
      • 基于DOCKER的CI工具—DRONE
      • DRONE安装指南
      • 如何使用DRONE
      • Drone
      • Jenkins
        • jenkins 集成 keycloak 认证
    • 50个免费的Kubernetes工具盘点
      • Kube集群部署工具
      • 监控工具
      • 测试工具
      • 安全工具
      • 实用的CLI工具
      • 开发工具
      • 无服务器/函数工具
      • 原生服务发现
      • 原生可视化与控制
    • Untitled
  • 领域应用
    • Istio
      • Helm安装
      • 安装并试用Istio service mesh
      • 示例应用部署
      • Bookinfo 应用-
      • 配置请求的路由规则
      • 故障注入
      • 流量转移
      • Istio流量管理实现机制深度解析
      • istio:监控能力介绍
      • Istio 04:Istio性能及扩展性介绍
      • Untitled
  • 实践
    • 大规模集群
    • 高可用
  • k8s运维排查
    • 常用命令
    • Kubernetes之YAML文件
      • yaml文件例子--pod
      • yaml文件例子--rc
    • Kubernetes运维
      • 集群管理
      • 集群与应用监控
      • 日志收集与管理
      • 常见问题定位
      • 权限管理RBAC
    • 排错概览
    • 集群排错
      • kubernetes集群管理常用命令一
    • Pod 排错
    • 网络排错
      • 容器内抓包定位网络问题
    • PV 排错
    • Windows 排错
    • 云平台排错
    • 集群安装脚本
    • 排错工具
    • 常见问题
      • k8s故障解决干货文档链接
      • 记一次Docker/Kubernetes上无法解释的连接超时原因探寻之旅
      • service没有负载均衡
      • kubernetes集群etcd空间配额2G的坑优化
    • K8S--100问
      • 解决 Docker 日志文件太大的问题
      • Kubernetes集群里容器之间的通讯方式
      • k8s 优化
      • lxcfs 在容器内显示容器的 CPU、内存状态
      • kubectl 创建 Pod流程
      • k8s网络-iptables
      • k8s底层网络原理
      • 网络排查
      • kubectl top 和 cadvisor metric ,docker state不一致的问题
      • 容器挂载数据卷的几种情况
      • 容器的终止流程
      • Kubernetes 中如何保证优雅地停止 Pod
      • K8S的apiVersion
      • 如何在Pod中执行宿主机上的命令
      • 创建 Pod 流程
      • k8s主要组件说明
      • 节点网络规划
      • Deployment管理方式
      • pod的分配方式
  • 深入浅出k8s
    • 说明
    • k8s发布策略介绍
    • oom kill原理讲解
    • Kubernetes 的架构设计与实现原理
  • 附录
    • CKA认证
    • 生态圈
    • 资讯快报
      • 2018态势回顾与2019年前景展望
      • Untitled
    • 学习资源
    • 参考文档
    • Kubernetes版本更新日志
      • Kubernetes 1.14 更新日志
      • Kubernetes 1.13 更新日志
      • Kubernetes1.12更新日志
      • Kubernetes1.10更新日志
      • Kubernetes1.11更新日志
  • 思维导图
    • k8s
    • DEVOPS
  • DEVOPS
    • 开源仓库-nexus
      • 一,nexus的安装
      • 二,使用nexus3配置docker私有仓库
      • 三,使用nexus3配置maven私有仓库
      • 四,nexus-3.14.0升级到3.15.2
      • 五,nexus3搭建golang私服
    • vpn
      • openvpn
    • Tcpdump 示例教程
    • Ipsec VPN-centos7使用strangwang搭建vpn
    • yum安装redis及常用指令
    • 数据库
      • mysql表操作
      • mysql 库常用操作及备份还原
      • MySQL 优化实施方案
    • NSQ
      • nsq问题解答
      • 选型
      • docker-compose部署 简单nsq 集群
    • 部署Redis集群
    • zookeeper安装及使用
    • Etcd
      • Untitled
      • Etcd配置
  • k8s系统完整部署
    • CentOS7.5 使用二进制程序部署Kubernetes1.12.2
    • 二进制的方式部署 K8S-1.16 高可用集群
    • CoreOS部署Kubernetes集群
    • EFK
      • 日志-kafka
      • logstash的部署、整合ELK+Filebeat
      • 应用日志收集
      • ES搭建
      • es集群部署
      • ElasticSearch技术原理
      • Elasticsearch操作
      • kibana
      • kibana简单使用
      • 非K8S主机部署Filebat
    • 镜像仓库-Harbor
    • Harbor 2.6.2安装
    • cURL 命令获取本机外网 IP
    • Shell 解析 JSON
    • 制作 gitbook 文档镜像,运行在 K8S 上
    • Kubernetes 之 MySQL 持久存储和故障转移
    • 如何删除etcd上的旧数据
    • Git 实战教程
  • 生活
    • 信合.阳光城
Powered by GitBook
On this page
  1. k8s运维排查
  2. K8S--100问

pod的分配方式

PreviousDeployment管理方式Next说明

Last updated 5 years ago

kubelet 就是基于 【pod 申请的资源】 + 【pod 的 QoS 级别】来最终为这个 pod 分配资源的。

而分配资源的根本方法就是基于 cgroup 的机制。

kubernetes 在拿到一个 pod 的资源申请信息后,针对每一种资源,他都会做如下几件事情:

•对 pod 中的每一个容器,都创建一个 container level cgroup(注:这一步真实情况是 kubernetes 向 docker daemon 发送命令完成的)。

• 然后为这个 pod 创建一个 pod level cgroup ,它会成为这个 pod 下面包含的所有 container level cgroup 的父 cgroup。

• 最终,这个 pod level cgroup 最终会根据这个 pod 的 QoS 级别,可能被划分到某一个 QoS level cgroup 中,成为这个 QoS level cgroup 的子 cgroup。

• 整个 QoS level cgroup 还是所有容器的根 cgroup - kubepods 的子 cgroup。

所以这个嵌套关系通过下述图片可以比较清晰的展示出来。

​

图中代表了一个 kubernetess 计算节点的 cgroup 的层次结构(对于 cpu、memory 来说 cgroup 层次结构是完全一致的)。可见,所有 pod 的 cgroup 配置都位于 kubepods 这个大的 cgroup 下,而之前介绍的 kube-reserved cgroup 和 system-reserved cgroup 和 kubepods cgroup 位于一级,他们 3 个会共享机器的计算资源。

我们首先看如何确定这个 container 对应的 container level cgroup 和它所在的 pod level cgroup。

Container level cgroup

首先,每一个 container 的 cgroup 的配置则是根据这个 container 对这种资源的 request、limit 信息来配置的。

我们分别看一下,针对 cpu、memory 两种资源,kubernetes 是如何为每一个容器创建 container 级别的 cgroup 的。

CPU 资源

首先是 CPU 资源,我们先看一下 CPU request。

CPU request 是通过 cgroup 中 CPU 子系统中的 cpu.shares 配置来实现的。

当你指定了某个容器的 CPU request 值为 x millicores 时,kubernetes 会为这个 container 所在的 cgroup 的 cpu.shares 的值指定为 x * 1024 / 1000。即:

cpu.shares = (cpu in millicores * 1024) / 1000

​

举个栗子,当你的 container 的 CPU request 的值为 1 时,它相当于 1000 millicores,所以此时这个 container 所在的 cgroup 组的 cpu.shares 的值为 1024。

这样做希望达到的最终效果就是:

即便在极端情况下,即所有在这个物理机上面的 pod 都是 CPU 繁忙型的作业的时候(分配多少 CPU 就会使用多少 CPU),仍旧能够保证这个 container 的能够被分配到 1 个核的 CPU 计算量。

其实就是保证这个 container 的对 CPU 资源的最低需求。

所以可见 cpu.request 一般代表的是这个 container 的最低 CPU 资源需求。但是其实仅仅通过指定 cpu.shares 还是无法完全达到上面的效果的,还需要对 QoS level 的 cgroup 进行同步的修改。至于具体实现原理我们在后面会详细介绍。

​

而针对 cpu limit,kubernetes 是通过 CPU cgroup 控制模块中的 cpu.cfs_period_us,cpu.cfs_quota_us 两个配置来实现的。kubernetes 会为这个 container cgroup 配置两条信息:

cpu.cfs_period_us = 100000 (i.e. 100ms) cpu.cfs_quota_us = quota = (cpu in millicores * 100000) / 1000

​

在 cgroup 的 CPU 子系统中,可以通过这两个配置,严格控制这个 cgroup 中的进程对 CPU 的使用量,保证使用的 CPU 资源不会超过 cfs_quota_us/cfs_period_us,也正好就是我们一开始申请的 limit 值。

可见通过 cgroup 的这个特性,就实现了限制某个容器的 CPU 最大使用量的效果。

​

Memory

​

针对内存资源,其实 memory request 信息并不会在 container level cgroup 中有体现。kubernetes 最终只会根据 memory limit 的值来配置 cgroup 的。

在这里 kubernetes 使用的 memory cgroup 子系统中的 memory.limit_in_bytes 配置来实现的。配置方式如下:

memory.limit_in_bytes = memory limit bytes

memory 子系统中的 limit_in_bytes 配置,可以限制一个 cgroup 中的所有进程可以申请使用的内存的最大量,如果超过这个值,那么根据 kubernetes 的默认配置,这个容器会被 OOM killed,容器实例就会发生重启。

可见如果是这种实现方式的话,其实 kubernetes 并不能保证 pod 能够真的申请到它指定的 memory.request 那么多的内存量,这也可能是让很多使用 kubernetes 的童鞋比较困惑的地方。因为 kubernetes 在对 pod 进行调度的时候,只是保证一台机器上面的 pod 的 memory.request 之和小于等于 node allocatable memory 的值。所以如果有一个 pod 的 memory.limit 设置的比较高,甚至没有设置,就可能会出现一种情况,就是这个 pod 使用了大量的内存(大于它的 request,但是小于它的 limit),此时鉴于内存资源是不可压缩的,其他的 pod 可能就没有足够的内存余量供其进行申请了。当然,这个问题也可以通过一个特性在一定程度进行缓解,这个会在下面介绍。

​

当然读者可能会有一个问题,如果 pod 没有指定 request 或者 limit 会怎样配置呢?

如果没有指定 limit 的话,那么 cfs_quota_us 将会被设置为 -1,即没有限制。而如果 limit 和 request 都没有指定的话,cpu.shares 将会被指定为 2,这个是 cpu.shares 允许指定的最小数值了。可见针对这种 pod,kubernetes 只会给他分配最少的 CPU 资源。

而对于内存来说,如果没有 limit 的指定的话,memory.limit_in_bytes 将会被指定为一个非常大的值,一般是 2^64 ,可见含义就是不对内存做出限制。

针对上面对 container level cgroup 的介绍,我们举个具体的栗子,假设一个 pod 名字叫做 pod-burstable-1 是由两个业务容器构成的 container1 container2,这两个 container 的资源配置分别如下:

- image: image1 name: container1 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 1 memory: 1Gi - image: image2 name: container2 resources: limits: cpu: 2 memory: 2Gi requests: cpu: 1 memory: 1Gi

所以可见这个 pod 所有容器的 request,limit 都已经被指定,但是 request 和 limit 并不完全相等,所以这个 pod 的 QoS 级别为 Burstable。

​

另外还有一个 pod 名字叫做 pod-guaranteed-1,它由一个 container 构成,资源配置如下:

- image: image3 name: container3 resources: limits: cpu: 1 memory: 1Gi requests: cpu: 1 memory: 1Gi

通过这个配置可见,它是一个 Guaranteed 级别的 Pod。

另外还有一个 pod 叫做 pod-besteffort-1 它有一个 container 构成,资源配置信息完全为空,那么这个 pod 就是 besteffort 级别的 pod。

所以通过上述描述的 cgroup 配置方式,这 3 个 pod 会创建 4 个 container cgroup 如下图所示:

​

​​

Pod level cgroup

创建完 container level 的 cgroup 之后,kubernetes 就会为同属于某个 pod 的 containers 创建一个 pod level cgroup。作为它们的父 cgroup。

至于为何要引入 pod level cgroup,主要是基于几点原因:

• 方便对 pod 内的容器资源进行统一的限制

• 方便对 pod 使用的资源进行统一统计

所以对于我们上面举的栗子,一个 pod 名称为 pod-burstable-1,它包含两个 container:container1、container2,那么这个 pod cgroup 的目录结构如下:

pod-burstable-1 | +- container1 | +- container2

注:真实情况下 pod cgroup 的名称是 pod<podID>,这里为了表示清楚,用 pod name 代替

那么为了保证这个 pod 内部的 container 能够获取到期望数量的资源,pod level cgroup 也需要进行相应的 cgroup 配置。而配置的方式也基本满足一个原则:

pod level cgroup 的资源配置应该等于属于它的 container 的资源需求之和。

但是,这个规则在不同的 QoS 级别的 pod 下也有些细节上的区别。所以针对 Guaranteed 和 Burstable 级别的 Pod,每一个 Pod 的 cgroup 配置都可以由下述 3 个公式来完成:

cpu.shares = sum(pod.spec.containers.resources.requests[cpu]) cpu.cfs_quota_us = sum(pod.spec.containers.resources.limits[cpu] memory.limit_in_bytes = sum(pod.spec.containers.resources.limits[memory])

从公式中可见,pod level cgroup 的 cpu.shares、 cpu.cfs_quota_us、memory.limit_in_bytes 最终都等于属于这个 pod 的 container 的这 3 值的和。

当然在 Burstable,Besteffort 的场景下,有可能 container 并没有指定 cpu.limit、memory.limit,此时 cpu.cfs_quota_us、memory.limit_in_bytes 将不会采用这个公式,因为此时相当于不会对 pod 的 cpu,memory 的使用量做最大值的限制,所以此时这两个配置也会参照上一节中说道的“如果 container 如果没有设置 request 和 limit 的话”处理的方式一样。

所以针对我们在上面的举的例子 pod-burstable-1,就是一个非常典型的 burstable pod,根据 burstable pod 的资源配置公式,kubernetes 会为这个 pod 创建一个 pod 级别的 cgroup。另外 pod-guaranteed-1 也会创建一个 cgroup,这两个 pod level cgroup 的配置如下图所示:

​

​Besteffort pod cgroup

上面我们讲到的 pod cgroup 配置规律是不能应用于 besteffort pod 的。

因为这个 QoS 级别的 pod 就像名字描述的那样,kubernetes 只能尽可能的保证你的资源使用,在资源被极端抢占的情况,这种 pod 的资源使用量应该被一定程度的限制,无论是 cpu,还是内存(当然这两种限制的机制完全不同)。

所以针对 besteffort 级别的 pod,由于这里面的所有容器都不包含 request,limit 信息,所以它的配置非常统一。

所以针对 cpu,整个 pod 的 cgroup 配置就只有下面:

cpu.shares = 2

可见这个配置的目标就是能够达到,它在机器 cpu 资源充足时能使用整个机器的 cpu,因为没有指定 limit。但是在 cpu 资源被极端抢占时,它能够被分配的 cpu 资源很有限,相当于 2 millicores。

针对内存,没有任何特殊配置,只是采用默认,虽然在这种情况下,这个 pod 可能会使用整个机器那么多的内存,但是 kubernetes eviction 机制会保证,内存不足时,优先删除 Besteffort 级别的 pod 腾出足够的内存资源。

​

QoS level cgroup

前面也提过,在 kubelet 启动后,会在整个 cgroup 系统的根目录下面创建一个名字叫做 kubepods 子 cgroup,这个 cgroup 下面会存放所有这个节点上面的 pod 的 cgroup。从而达到了限制这台机器上所有 Pod 的资源的目的。

在 kubepods cgroup 下面,kubernetes 会进一步再分别创建两个 QoS level cgroup,名字分别叫做:

• burstable

• besteffort

通过名字也可以推断出,这两个 QoS level 的 cgroup 肯定是作为各自 QoS 级别的所有 Pod 的父 cgroup 来存在的。

那么问题就来了:

• guaranteed 级别的 pod 的 pod cgroup 放在哪里了呢?

• 这两个 QoS level cgroup 存在的目的是什么?

首先第一个问题,所有 guaranteed 级别的 pod 的 cgroup 其实直接位于 kubepods 这个 cgroup 之下,和 burstable、besteffort QoS level cgroup 同级。主要原因在于 guaranteed 级别的 pod 有明确的资源申请量(request)和资源限制量(limit),所以并不需要一个统一的 QoS level 的 cgroup 进行管理或限制。

针对 burstable 和 besteffort 这两种类型的 pod,在默认情况下,kubernetes 则是希望能尽可能地提升资源利用率,所以并不会对这两种 QoS 的 pod 的资源使用做限制。

但是在很多场景下,系统管理员还是希望能够尽可能保证 guaranteed level pod 这种高 QoS 级别的 pod 的资源,尤其是不可压缩资源(如内存),不要被低 QoS 级别的 pod 提前使用,导致高 QoS 级别的 pod 连它 request 的资源量的资源都无法得到满足。

所以,kubernetes 才引入了 QoS level cgroup,主要目的就是限制低 QoS 级别的 pod 对不可压缩资源(如内存)的使用量,为高 QoS 级别的 pod 做资源上的预留。三种 QoS 级别的优先级由高到低为 guaranteed > burstable > besteffort。

那么到底如何实现这种资源预留呢?主要是通过 kubelet 的 experimental-qos-reserved 参数来控制,这个参数能够控制以怎样的程度限制低 QoS 级别的 pod 的资源使用,从而对高级别的 QoS 的 pod 实现资源上的预留,保证高 QoS 级别的 pod 一定能够使用到它 request 的资源。

目前只支持对内存这种不可压缩资源的预留情况进行指定。比如 experimental-qos-reserved=memory=100%,代表我们要 100% 为高 QoS level 的 pod 预留资源。

所以针对这个场景,对于内存资源来说,整个 QoS Level cgroup 的配置规则如下:

burstable/memory.limit_in_bytes = Node.Allocatable - {(summation of memory requests of `Guaranteed` pods)*(reservePercent / 100)} besteffort/memory.limit_in_bytes = Node.Allocatable - {(summation of memory requests of all `Guaranteed` and `Burstable` pods)*(reservePercent / 100)}

​

从公式中可见,burstable 的 cgroup 需要为比他等级高的 guaranteed 级别的 pod 的内存资源做预留,所以默认情况下,如果没有指定这个参数,burstable cgroup 中的 pod 可以把整个机器的内存都占满,但是如果开启这个特性,burstable cgroup 的内存限制就需要动态的根据当前有多少 guaranteed 级别 pod 来进行动态调整了。

besteffort 也是类似,但是不一样的地方在于 besteffort 不仅要为 guaranteed 级别的 pod 进行资源预留,还要为 burstable 级别的 pod 也进行资源的预留。

所以举个栗子,当前机器的 allocatable 内存资源量为 8G,我们为这台机器的 kubelet 开启 experimental-qos-reserved 参数,并且设置为 memory=100%。如果此时创建了一个内存 request 为 1G 的 guaranteed level 的 pod,那么此时这台机器上面的 burstable QoS level cgroup 的 memory.limit_in_bytes 的值将会被设置为 7G,besteffort QoS level cgroup 的 memory.limit_in_bytes 的值也会被设置为 7G。

​

而如果此时又创建了一个 burstable level 的 pod,它的内存申请量为 2G,那么此时 besteffort QoS level cgroup 的 memory.limit_in_bytes 的值也会被调整为 5G。

内存虽然搞定了,但是对于 cpu 资源反而带来一些麻烦。

针对 besteffort 的 QoS,它的 cgroup 的 CPU 配置还是非常简单:

besteffort/cpu.shares = 2

但是针对 burstable 的 QoS,由于所有的 burstable pod 现在都位于 kubepods 下面的 burstable 这个子组下面,根据 cpu.shares 的背后实现原理,位于不同层级下面的 cgroup,他们看待同样数量的 cpu.shares 配置可能最终获得不同的资源量。比如在 Guaranteed 级别的 pod cgroup 里面指定的 cpu.shares=1024,和 burstable 下面的某个 pod cgroup 指定 cpu.shares=1024 可能最终获取的 cpu 资源并不完全相同。这个是因为 cpu.shares 自身机制导致的。

所以为了能够解决这个问题,kubernetes 也必须动态调整 burstable cgroup 的 cpu.shares 的配置,如下文档中描述的那样:

burstable/cpu.shares = max(sum(Burstable pods cpu requests, 2)

来保证,相同的 cpu.shares 配置,对于 guaranteed 级别的 pod 和 burstable 的 pod 来说是完全一样的。

至于为什么这样做我们将在后面进行详细的解释。

所以对于我们上面的例子,3 个 pod 分别为 guaranteed,burstable,besteffort 级别的,假设当前机器的 kubelet 开启了 experimental-qos-reserved 参数并且指定为 memory=100%。假设这 3 pod 运行在一台 3 核 8G 内存的机器上面,那么此时整个机器的 cgroup 配置将如下:

​

​

通过这一系列的配置后,我们达到的效果就是:

• 在机器 cpu 资源空闲时,pod-guaranteed-1 这个 pod 最多可以使用 1 核 cpu 的计算力。pod-burstable-1 这个 pod 最多可以使用 3 核的 cpu 计算力,pod-besteffort-1 这个 pod 可以把机器剩余的计算力跑满。

• 当机器 cpu 资源被抢占的时候,比如 pod-guaranteed-1、pod-burstable-1 这两种资源都在 100% 的使用 cpu 的时候,pod-guaranteed-1 仍旧可以获取 1 核的 cpu 计算力,pod-burstable-1 仍旧可以获取 2 核的计算力。但是 pod-besteffort-1 仅仅能获取 2 milicores 的 cpu 计算力,是 pod-burstable-1 的千分之一。

• 该机器的 besteffort 级别的 pod,能够使用的最大内存量为[机器内存 8G] - [sum of request of burstable 2G] - [sum of request of guaranteed 1G] = 5G

• 该机器的 burstable 级别的 pod,能够使用的最大内存量为 [机器内存 8G] - [sum of request of guaranteed 1G] = 7G

CPU Request 的实现

CPU 资源的 request 量代表这个容器期望获取的最小资源量。它是通过 cgroup cpu.shares 特性来实现的。但是这个 cpu.shares 真实代表的这个 cgroup 能够获取机器 CPU 资源的【比重】,并非【绝对值】。

比如某个 cgroup A 它的 cpu.shares = 1024 并不代表这个 cgroup A 能够获取 1 核的计算资源,如果这个 cgroup 所在机器一共有 2 核 CPU,除了这个 cgroup 还有另外 cgroup B 的 cpu.shares 的值为 2048 的话,那么在 CPU 资源被高度抢占的时候,cgroup A 只能够获取 2 * (1024/(1024 + 2048)) 即 2/3 的 CPU 核资源。

那么 kubernetes 又是如何实现,无论是什么 QoS 的 pod,只要它的某个容器的 cpu.shares = 1024,那么它就一定能够获取 1 核的计算资源的呢?

实现的方式其实就是通过合理的对 QoS level cgroup,Pod level cgroup 进行动态配置来实现的。

我们还可以用上面的栗子继续描述,假设目前这 3 个 Pod 就位于一个有 3 个 CPU 核的物理机上面。此时这台机器的 CPU cgroup 的配置会变成下面的样子:

•kubepods cgroup 的 cpu.shares 将会被设置为 3072。

•pod-guaranteed-1 中的 pod cgroup 的 cpu.shares 将会被设置为 1024,pod cgroup 内的 container3 的 container cgroup 的 cpu.shares 将会被设置为 1024。

•pod-burstable-1 所在 burstable QoS level cgroup cpu.shares 将会被设置为 2048

•pod-burstable-1 的 pod cgroup 的 cpu.shares 是 2048

•pod-burstable-1 中的 container1 的 cpu.shares 是 1024

•pod-burstable-1 中的 container2 的 cpu.shares 是 1024

所以此时的层次结构如下图:

​

​

因为 besteffort 的 cpu.shares 的值仅仅为 2,可以忽略。

所以此时在计算 container1、container2、container3 在 CPU 繁忙时的 CPU 资源时,就可以按照下述公式来进行计算:

• container3 = (1024/1024) * (1024/(1024+2048)) * 3 = 1

• container1 = (1024/(1024+1024)) * (2048/2048) * (2048/1024+2048) * 3 = 1

• container2 = (1024/(1024+1024)) * (2048/2048) * (2048/1024+2048) * 3 = 1

可见,kubernetes 是通过巧妙的设置 kubepods cgroup 的 cpu.shares,以及合理的更新 burstable QoS level cgroup 的配置来实现 cpu.shares 就等于容器可以获取的最小 CPU 资源的效果的。

​

参考引用

[1]Kubernetes Resource Model:

[2]Kubernetes Container and pod resource limits Issue:

[3]Core Metrics in kubelet:

[4]Kubernetes Monitor Architecture:

[5]Standalone of cadvisor:

[6] Kubernetes Node Allocatable Resource:

[7]

[8]编辑于 2018-06-22

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/resources.md
https://github.com/kubernetes/kubernetes/issues/168
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/core-metrics-pipeline.md
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/monitoring_architecture.md
https://github.com/kubernetes/kubernetes/issues/18770
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/node-allocatable.md#phase-2---enforce-allocatable-on-pods
https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/pod-resource-management.md
https://zhuanlan.zhihu.com/p/38359775