k8s Evicted pod

线上 pod 被驱逐

最近线上发现有些实例pod处于 Evicted 状态。
通过 查看 pod 信息,发现是资源不够导致pod被驱逐;

$ kubectl get pod -n nsop| grep -i Evicted
cloud-1023955-84421-49604-5-deploy-c-7748f8fd8-hjqsh        0/1     Evicted   0          73d
cloud-1023955-84421-49604-5-deploy-c-7748f8fd8-mzd8x        0/1     Evicted   0          81d
cloud-1237162-276467-199844-2-deploy-7bdc7c98b6-26r2r       0/1     Evicted   0          18d

# 示例状态
status:
  message: 'Pod The node had condition: [DiskPressure]. '
  phase: Failed
  reason: Evicted
  startTime: "2021-09-14T10:42:32Z"

实例被驱逐的原因

kubelet 默认会配置节点资源不足时驱逐实例的策略,当节点资源不足时 k8s 会停止该节点上实例并在其他节点启动新实例,在某些情况下也可通过配置 --eviction-hard= 参数为空来禁用驱逐策略

删除 pod

$ kubectl get po -n nsop  --field-selector 'status.phase!=Running' -o json| kubectl delete -f -

节点资源不足导致实例被驱逐

k8s 中产生 Evicted 状态实例主要是因为节点资源不足实例主动被驱逐导致的,kubelet eviction_manager 模块会定期检查节点内存使用率、inode 使用率、磁盘使用率、pid 等资源,根据 kubelet 的配置当使用率达到一定阈值后会先回收可以回收的资源,若回收后资源使用率依然超过阈值则进行驱逐实例操作。

Eviction Signal Description
memory.available memory.available := node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.available nodefs.available := node.stats.fs.available
nodefs.inodesFree nodefs.inodesFree := node.stats.fs.inodesFree
imagefs.available imagefs.available := node.stats.runtime.imagefs.available
imagefs.inodesFree imagefs.inodesFree := node.stats.runtime.imagefs.inodesFree
pid.available pid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc
  • memory.available:当前节点可用内存,计算方式为 cgroup memory 子系统中 memory.usage_in_bytes 中的值减去 memory.stat 中 total_inactive_file 的值;
  • nodefs.available:nodefs 包含 kubelet 配置中 --root-dir 指定的文件分区和 /var/lib/kubelet/ 所在的分区磁盘使用率;
  • nodefs.inodesFree:nodefs.available 分区的 inode 使用率;
  • imagefs.available:镜像所在分区磁盘使用率;
  • imagefs.inodesFree:镜像所在分区磁盘 inode 使用率;
  • pid.available:/proc/sys/kernel/pid_max 中的值为系统最大可用 pid 数;

kubelet 可以通过参数 --eviction-hard 来配置以上几个参数的阈值,该参数默认值为 imagefs.available<15%,memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,当达到阈值时会驱逐节点上的容器。

kubelet 驱逐实例时与资源处理相关的已知问题

1、kubelet 不会实时感知到节点内存数据的变化

kubelet 定期通过 cadvisor 接口采集节点内存使用数据,当节点短时间内内存使用率突增,此时 kubelet 无法感知到也不会有 MemoryPressure 相关事件,但依然会调用 OOMKiller 停止容器。可以通过为 kubelet 配置 --kernel-memcg-notification 参数启用 memcg api,当触发 memory 使用率阈值时 memcg 会主动进行通知;

memcg 主动通知的功能是 cgroup 中已有的,kubelet 会在 /sys/fs/cgroup/memory/cgroup.event_control 文件中写入 memory.available 的阈值,而阈值与 inactive_file 文件的大小有关系,kubelet 也会定期更新阈值,当 memcg 使用率达到配置的阈值后会主动通知 kubelet,kubelet 通过 epoll 机制来接收通知。

2、kubelet memory.available 不会计算 active page

kubelet 通过内存使用率驱逐实例时,内存使用率数据包含了 page cache 中 active_file 的数据,在某些场景下会因 page cache 过高导致内存使用率超过阈值会造成实例被驱逐,

由于在内存紧张时 inactive_file 会被内核首先回收,但在内存不足时,active_file 也会被内核进行回收,社区对此机制也有一些疑问,针对内核回收内存的情况比较复杂,社区暂时还未进行回应,详情可以参考 kubelet counts active page cache against memory.available (maybe it shouldn’t?)[1]

kubelet 计算节点可用内存的方式如下:

#!/bin/bash
#!/usr/bin/env bash

# This script reproduces what the kubelet does
# to calculate memory.available relative to root cgroup.

# current memory usage
memory_capacity_in_kb=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}')
memory_capacity_in_bytes=$((memory_capacity_in_kb * 1024))
memory_usage_in_bytes=$(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)
memory_total_inactive_file=$(cat /sys/fs/cgroup/memory/memory.stat | grep total_inactive_file | awk '{print $2}')

memory_working_set=${memory_usage_in_bytes}
if [ "$memory_working_set" -lt "$memory_total_inactive_file" ];
then
    memory_working_set=0
else
    memory_working_set=$((memory_usage_in_bytes - memory_total_inactive_file))
fi

memory_available_in_bytes=$((memory_capacity_in_bytes - memory_working_set))
memory_available_in_kb=$((memory_available_in_bytes / 1024))
memory_available_in_mb=$((memory_available_in_kb / 1024))

echo "memory.capacity_in_bytes $memory_capacity_in_bytes"
echo "memory.usage_in_bytes $memory_usage_in_bytes"
echo "memory.total_inactive_file $memory_total_inactive_file"
echo "memory.working_set $memory_working_set"
echo "memory.available_in_bytes $memory_available_in_bytes"
echo "memory.available_in_kb $memory_available_in_kb"
echo "memory.available_in_mb $memory_available_in_mb"

驱逐实例未被删除原因分析

源码中对于 Statefulset 和 DaemonSet 会自动删除 Evicted 实例,但是对于 Deployment 不会自动删除。阅读了部分官方文档以及 issue,暂未找到官方对 Deployment Evicted 实例未删除原因给出解释。

posted @   Star-Hitian  阅读(167)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 海阔天空 Beyond
  2. 2 此生过半 Audio artist
  3. 3 让我欢喜让我忧 Audio artist
  4. 4 P.I.M.P. Audio artist
  5. 5 Extasy Audio artist
海阔天空 - Beyond
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 黄家驹

作曲 : 黄家驹

编曲 : Beyond/梁邦彦

制作人 : Beyond/梁邦彦

今天我 寒夜里看雪飘过

怀着冷却了的心窝漂远方

风雨里追赶 雾里分不清影踪

天空海阔你与我

可会变 (谁没在变)

多少次 迎着冷眼与嘲笑

从没有放弃过心中的理想

一刹那恍惚 若有所失的感觉

不知不觉已变淡

心里爱 (谁明白我)

原谅我这一生不羁放纵爱自由

也会怕有一天会跌倒

背弃了理想 谁人都可以

哪会怕有一天只你共我

今天我 寒夜里看雪飘过

今天我 寒夜里看雪飘过

怀着冷却了的心窝漂远方

风雨里追赶 雾里分不清影踪

天空海阔你与我

可会变 (谁没在变)

原谅我这一生不羁放纵爱自由

也会怕有一天会跌倒

背弃了理想 谁人都可以

哪会怕有一天只你共我

仍然自由自我 永远高唱我歌

仍然自由自我 永远高唱我歌

走遍千里

原谅我这一生不羁放纵爱自由

也会怕有一天会跌倒

背弃了理想 谁人都可以

哪会怕有一天只你共我

背弃了理想 谁人都可以

哪会怕有一天只你共我

原谅我这一生不羁放纵爱自由

也会怕有一天会跌倒

背弃了理想 谁人都可以

哪会怕有一天只你共我

录音 : Shunichi Yokoi

录音 : Shunichi Yokoi

混音 : Shunichi Yokoi

录音室 : Greenbird St./Tokyu Fun St./West Side St.(Tokyo/From Jan/to Apr./1993)

母带工程师 : Setsu Hisai at Tokyu Fun St.

弦乐 : 桑野圣乐团 (Kuwano Strings)

OP : Amuse Inc. & Fun House Inc.

SP : Amuse H.K. Ltd.