目录node
apiVersion: v1 kind: Pod metadata: name: pod-demo labels: app: myapp tier: fronted spec: containers: - name: myapp image: ikubernetes/stress-ng command: ["/usr/bin/stress-ng", "-m 1", "-c 1", "--metrics-brief"] resources: requests: cpu: "200m" memory: "128Mi" limits: cpu: "500m" memory: "200Mi"
kubectl exec pod-demo -- top
这是一个CPU为2核的节点, 分配给容器500m的CPU, 也就是0.5个CPU, 因此看到的进程CPU占用率约为26%
docker
若是Pod中全部Container的全部Resource的limit
和request
都相等且不为0,则这个Pod的QoS Class就是Guaranteed。api
注意,若是一个容器只指明了limit,而未指明request,则代表request的值等于limit的值。app
containers: name: foo resources: limits: cpu: 10m memory: 1Gi name: bar resources: limits: cpu: 100m memory: 100Mi requests: cpu: 100m memory: 100Mi
至少有一个容器设置CPU或内存资源的requests属性post
若是Pod中全部容器的全部Resource的request和limit都没有赋值,则这个Pod的QoS Class就是Best-Effort..net
containers: name: foo resources: name: bar resources:
Guaranteed > Burstable > Best-Effort code
Pod 使用的资源最重要的是 CPU、内存和磁盘 IO,这些资源能够被分为可压缩资源(CPU)
和不可压缩资源(内存,磁盘 IO)
。blog
可压缩资源(CPU)
不会致使pod被驱逐排序
由于当 Pod 的 CPU 使用量不少时,系统能够经过从新分配权重来限制 Pod 的 CPU 使用进程
不可压缩资源(内存)
则会致使pod被驱逐
于不可压缩资源来讲,若是资源不足,也就没法继续申请资源(内存用完就是用完了),此时 Kubernetes 会从该节点上驱逐必定数量的 Pod,以保证该节点上有充足的资源。
下面是 kubelet 默认的关于节点存储的驱逐触发条件:
当 imagefs
使用量达到阈值时,kubelet 会尝试删除不使用的镜像来清理磁盘空间。
当 nodefs
使用量达到阈值时,kubelet 就会拒绝在该节点上运行新 Pod,并向 API Server 注册一个 DiskPressure condition。而后 kubelet 会尝试删除死亡的 Pod 和容器来回收磁盘空间,若是此时 nodefs
使用量仍然没有低于阈值,kubelet 就会开始驱逐 Pod。kubelet 驱逐 Pod 的过程当中不会参考 Pod 的 QoS
,只是根据 Pod 的 nodefs 使用量来进行排名,并选取使用量最多的 Pod 进行驱逐。因此即便 QoS 等级为 Guaranteed
的 Pod 在这个阶段也有可能被驱逐(例如 nodefs 使用量最大)。若是驱逐的是 Daemonset
,kubelet 会阻止该 Pod 重启,直到 nodefs 可用量超过阈值。
若是一个 Pod 中有多个容器,kubelet 会根据 Pod 中全部容器的 nodefs 使用量之和来进行排名。即全部容器的
container_fs_usage_bytes
指标值之和。
Pod Name | Pod QoS | nodefs usage |
---|---|---|
A | Best Effort | 800M |
B | Guaranteed | 1.3G |
C | Burstable | 1.2G |
D | Burstable | 700M |
E | Best Effort | 500M |
F | Guaranteed | 1G |
当 nodefs 的使用量超过阈值时,kubelet 会根据 Pod 的 nodefs 使用量来对 Pod 进行排名,首先驱逐使用量最多的 Pod。排名以下图所示:
Pod Name | Pod QoS | nodefs usage |
---|---|---|
B | Guaranteed | 1.3G |
C | Burstable | 1.2G |
F | Guaranteed | 1G |
A | Best Effort | 800M |
D | Burstable | 700M |
E | Best Effort | 500M |
下面是 kubelet 默认的关于节点内存资源的驱逐触发条件:
当内存使用量超过阈值时,kubelet 就会向 API Server 注册一个 MemoryPressure condition,此时 kubelet 不会接受新的 QoS 等级为 Best Effort
的 Pod 在该节点上运行,并按照如下顺序来驱逐 Pod:
request
指定的值request
指定的值之差。按照这个顺序,能够确保 QoS 等级为 Guaranteed
的 Pod 不会在 QoS 等级为 Best Effort
的 Pod 以前被驱逐,但不能保证它不会在 QoS 等级为 Burstable
的 Pod 以前被驱逐。
若是一个 Pod 中有多个容器,kubelet 会根据 Pod 中全部容器相对于 request 的内存使用量与之和来进行排名。即全部容器的 (
container_memory_usage_bytes
指标值与container_resource_requests_memory_bytes
指标值的差)之和。
Pod Name | Pod QoS | Memory requested | Memory limits | Memory usage |
---|---|---|---|---|
A | Best Effort | 0 | 0 | 700M |
B | Guaranteed | 2Gi | 2Gi | 1.9G |
C | Burstable | 1Gi | 2Gi | 1.8G |
D | Burstable | 1Gi | 2Gi | 800M |
E | Best Effort | 0 | 0 | 300M |
F | Guaranteed | 2Gi | 2Gi | 1G |
当节点的内存使用量超过阈值时,kubelet 会根据 Pod 相对于 request
的内存使用量来对 Pod 进行排名。排名以下所示:
Pod Name | Pod QoS | Memory requested | Memory limits | Memory usage | 内存相对使用量 |
---|---|---|---|---|---|
C | Burstable | 1Gi | 2Gi | 1.8G | 800M |
A | Best Effort | 0 | 0 | 700M | 700M |
E | Best Effort | 0 | 0 | 300M | 300M |
B | Guaranteed | 2Gi | 2Gi | 1.9G | -100M |
D | Burstable | 1Gi | 2Gi | 800M | -200M |
F | Guaranteed | 2Gi | 2Gi | 1G | -1G |
当内存资源不足时,kubelet 在驱逐 Pod 时只会考虑 requests 和 Pod 的内存使用量,不会考虑 limits。
由于 kubelet 默认每 10
秒抓取一次 cAdvisor 的监控数据,因此有可能在 kubelet 驱逐 Pod 回收内存以前发生内存使用量激增的状况,这时就有可能触发内核 OOM killer。这时删除容器的权利就由kubelet 转交到内核 OOM killer 手里,但 kubelet 仍然会起到必定的决定做用,它会根据 Pod 的 QoS 来设置其 oom_score_adj
值:
QoS | oom_score_adj |
---|---|
Guaranteed | -998 |
Burstable | min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999) |
pod-infra-container | -998 |
kubelet, docker daemon, systemd service | -999 |
若是该节点在 kubelet 经过驱逐 Pod 回收内存以前触发了 OOM 事件,OOM killer 就会采起行动来下降系统的压力,它会根据下面的公式来计算 oom_score
的值:
容器使用的内存占系统内存的百分比 + oom_score_adj = oom_score>
OOM killer 会杀掉 oom_score_adj
值最高的容器,若是有多个容器的 oom_score_adj
值相同,就会杀掉内存使用量最多的容器(实际上是由于内存使用量最多的容器的 oom_score 值最高)。关于 OOM 的更多内容请参考:Kubernetes 内存资源限制实战。
假设某节点运行着 4 个 Pod,且每一个 Pod 中只有一个容器。每一个 QoS 类型为 Burstable
的 Pod 配置的内存 requests 是 4Gi
,节点的内存大小为 30Gi
。每一个 Pod 的 oom_score_adj
值以下所示:
Pod Name | Pod QoS | oom_score_adj |
---|---|---|
A | Best Effort | 1000 |
B | Guaranteed | -998 |
C | Burstable | 867(根据上面的公式计算) |
D | Best Effort | 1000 |
当调用 OOM killer 时,它首先选择 oom_score_adj
值最高的容器(1000),这里有两个容器的 oom_score_adj
值都是 1000,OOM killer 最终会选择内存使用量最多的容器。
每 10 秒抓取一次
cAdvisor 的监控数据,因此可能在资源使用量低于阈值时,kubelet 仍然在驱逐 Pod。