kubernetes集群节点资源预留

本文介绍了在Kubernetes集群中避免节点资源被Pods完全消耗的方法,通过为系统组件和kubelet设置资源预留,保证节点稳定运行。讨论了内存、磁盘资源预留的配置,包括evictionThreshold和resourcelimit,以及测试和调整资源预留参数的过程。
摘要由CSDN通过智能技术生成

问题

默认kubelet没有配置资源预留,host上所有的资源(cpu, 内存, 磁盘) 都是可以给 pod 使用的。而当一个节点上的 pod 将资源吃满时,系统层面可能会干掉 k8s 核心组件进程, 从而导致改节点 not ready,此时 k8s 会将改节点的所有 pod 调度到其他节点重建,如果其他节点资源也不够,那么其他节点也会 not ready,进而引起集群雪崩效应。

如何避免

通过为 k8s 设置 kube 组件资源预留和 system 系统资源预留,保证节点的 pod 不会吃满节点资源

目前支持cpu, memory, ephemeral-storage 三种资源预留。

  1. cpu: cpu是配置cpu shares,实际上对应的是cpu的优先级,简单来说,这个在cpu繁忙时,它能有更高优先级获取更多cpu资源。
  2. memory: k8s默认不使用 swap,这里指的就是实际的内存
  3. ephemeral-storagekubernetes1.8开始引入的一个资源限制的对象,kubernetes 1.10版本中kubelet默认已经打开的了,到目前1.11还是beta阶段,主要是用于对本地临时存储使用空间大小的限制,如对podempty dir/var/lib/kubelet、日志、容器可读写层的使用大小的限制。

Node CapacityNode的所有硬件资源,kube-reserved是给kube组件预留的资源,system-reserved是给System进程预留的资源, eviction-thresholdkubelet eviction的阈值设定,allocatable才是真正scheduler调度Pod时的参考值(保证Node上所有Podsrequest resource不超过Allocatable

Node Allocatable Resource = Node Capacity - Kube-reserved - system-reserved - eviction-threshold

      Node Capacity
---------------------------
|     kube-reserved       |
|-------------------------|
|     system-reserved     |
|-------------------------|
|    eviction-threshold   |
|-------------------------|
|                         |
|      allocatable        |
|   (available for pods)  |
|                         |
|                         |
---------------------------

eviction-threshold实际上是对pod limit_resource的补充,因为limit_resource只能针对单个pod做资源限制,当这个pod达到限制的阀值后,kubelet便会oom_killer掉这个pod,而eviction-threshold根据事先设定的Eviction Thresholds来触发Eviction,调用算法筛选出合适的几个podkill掉一个或多个pod回收资源,被eviction掉的pod会被kube-scheduler在其他节点重新调度起来

eviction-threshold 分为两类:

Soft Eviction Thresholds

达到触发值后,发送信号给 pod, 并不是马上去驱逐pod,而是等待一个缓冲时间 grace period,

配置 eviction-soft 必须指定 grace period

Hard Eviction Thresholds

达到触发值后,直接筛选出对应的pod kill

配置

  • --enforce-node-allocatable,默认为pods,要为kube组件和System进程预留资源,则需要设置为pods,kube-reserved,system-reserve
  • --cgroups-per-qosEnabling QoS and Pod level cgroups,默认开启。开启后,kubelet将会管理所有workload Podscgroups
  • --cgroup-driver,默认为cgroupfs,另一可选项为systemd。取决于容器运行时使用的cgroup driverkubelet与其保持一致。比如你配置docker使用systemd cgroup driver,那么kubelet也需要配置--cgroup-driver=systemd
  • --kube-reserved,用于配置为kube组件(kubelet,kube-proxy,dockerd等)预留的资源量,比如--kube-reserved=cpu=1000m,memory=8Gi,ephemeral-storage=16Gi
  • --kube-reserved-cgroup,如果你设置了--kube-reserved,那么请一定要设置对应的cgroup,并且该cgroup目录要事先创建好,否则kubelet将不会自动创建导致kubelet启动失败。比如设置为kube-reserved-cgroup=/system.slice/kubelet.service
  • --system-reserved,用于配置为System进程预留的资源量,比如--system-reserved=cpu=500m,memory=4Gi,ephemeral-storage=4Gi
  • --system-reserved-cgroup,如果你设置了--system-reserved,那么请一定要设置对应的cgroup,并且该cgroup目录要事先创建好,否则kubelet将不会自动创建导致kubelet启动失败。比如设置为system-reserved-cgroup=/system.slice
  • --eviction-hard,用来配置kubelethard eviction条件,只支持memoryephemeral-storage两种不可压缩资源。当出现MemoryPressure时,Scheduler不会调度新的Best-Effort QoS Pods到此节点。当出现DiskPressure时,Scheduler不会调度任何新Pods到此节点。

配置示例

[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/var/lib/kubelet
# CPUAccounting=true
# MemoryAccounting=true
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/pids/system.slice/kubelet.service
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/cpu/system.slice/kubelet.service
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/cpuacct/system.slice/kubelet.service
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/cpuset/system.slice/kubelet.service
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/memory/system.slice/kubelet.service
ExecStartPre=/usr/bin/mkdir -p /sys/fs/cgroup/systemd/system.slice/kubelet.service
ExecStart=/usr/local/bin/kubelet \
  --cgroup-driver=systemd \
  --enforce-node-allocatable=pods,kube-reserved,system-reserved \
  --kube-reserved-cgroup=/system.slice/kubelet.service \
  --system-reserved-cgroup=/system.slice \
  --kube-reserved=cpu=1000m,memory=2Gi,ephemeral-storage=1Gi \
  --system-reserved=cpu=1000m,memory=2Gi,ephemeral-storage=1Gi \
  --max-pods=100 \
  --eviction-hard=imagefs.available<15%,memory.available<300Mi,nodefs.available<10%,nodefs.inodesFree<3% \
  --eviction-max-pod-grace-period=40 \
  --eviction-minimum-reclaim=memory.available=1Gi,nodefs.available=5Gi,imagefs.available=5Gi \
  --eviction-soft-grace-period=memory.available=30s,nodefs.available=2m,imagefs.available=2m,nodefs.inodesFree=2m \
  --eviction-soft=imagefs.available<20%,memory.available<1Gi,nodefs.available<15%,nodefs.inodesFree<5% \
  --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig \
  --rotate-certificates \
  --cert-dir=/etc/kubernetes/ssl \
  --cluster_dns=10.96.0.2 \
  --cluster_domain=cluster.local. \
  --hairpin-mode=promiscuous-bridge \
  --allow-privileged=true \
  --fail-swap-on=false \
  --serialize-image-pulls=false \
  --logtostderr=true \
  --network-plugin=cni \
  --cni-conf-dir=/etc/cni/net.d \
  --cni-bin-dir=/opt/cni/bin \
  --v=1
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

注意: 如果设置完资源预留,重启 kubelet 之后,发现 node 变成 not readykubectl describe node 查看, 报错为:

failed to write 6442450944 to memory.limit_in_bytes: write /sys/fs/cgroup/memory/system.slice/memory.limit_in_bytes: device or resource busy

是因为实际系统内存使用量大于 --system-reserved=cpu=1000m,memory=6Gi 的配置,将 6g 改大之后重启kubelet即可,当然具体改为多少,要看节点上实际系统占用内存(笔者测试机上装有 ceph, 所以系统部分所需内存较大)

测试

环境

hostnamerolecpumemory–kube-reserved=cpu–kube-reserved=memory–system-reserved=cpu–system-reserved=memory
k8s1master1247G1000m2Gi1000m15Gi
k8s2master3231G1000m2Gi1000m8Gi
k8s3node1662G1000m2Gi1000m8Gi

describe node

# k8s1
Addresses:
  InternalIP:  10.10.1.223
  Hostname:    k8s1
Capacity:
 cpu:                12
 ephemeral-storage:  574727312Ki
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             49425780Ki # k8s1 实际总内存: 47G
 pods:               110
Allocatable:
 cpu:                10
 ephemeral-storage:  523226238919
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             31292788Ki # k8s1 节点可以分配给 pod 的总内存: 30G
 pods:               110
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests            Limits
  --------           --------            ------
  cpu                8023m (80%)         35643m (356%)
  memory             32389500928 (101%)  75199505664 (234%)
  ephemeral-storage  0 (0%)              0 (0%)
  
# k8s2
Capacity:
 cpu:                32
 ephemeral-storage:  459378800Ki
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             32906916Ki
 pods:               110
Allocatable:
 cpu:                30
 ephemeral-storage:  416921050436
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             22113956Ki
 pods:               110
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests          Limits
  --------           --------          ------
  cpu                8123m (27%)       30203m (100%)
  memory             22098028Ki (99%)  60566922496 (267%)
  ephemeral-storage  0 (0%)            0 (0%)
  
# k8s3
Capacity:
 cpu:                16
 ephemeral-storage:  575257712Ki
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             65916188Ki
 pods:               110
Allocatable:
 cpu:                14
 ephemeral-storage:  523715055558
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             55123228Ki
 pods:               110
...
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests          Limits
  --------           --------          ------
  cpu                12785m (91%)      71410m (510%)
  memory             54820406Ki (99%)  155630527744 (275%)
  ephemeral-storage  0 (0%)            0 (0%)

k8s1 节点实际总内存 47G,减去 --kube-reserved=memory=2Gi, 再减去 --system-reserved=memory=15Gi, 为 k8s1 可以分配给 pod 的总内存 30G,并且该 30G 就是节点 resource requests 的上限

可以看到为 kube 和系统配置的资源预留确实生效了

再看下节点 podrequests

在这里插入图片描述

kube-scheduler 根据 pod 设置的 resource requestspod 选取合适的节点,现在 3台节点上requests 都满了,故无法再为新的 pod 调度,这时候新建 pod 会处于 Pending 状态,describe pod 会显示

Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 Insufficient memory.

而实际上各节点的 free -h 输出如下:

# k8s1
root@k8s1:~# free -h
              total        used        free      shared  buff/cache   available
Mem:            47G         25G         14G         13M        7.7G         21G
Swap:            0B          0B          0B

# k8s2
root@k8s2:~# free -h
              total        used        free      shared  buff/cache   available
Mem:            31G         27G        210M         13M        4.2G        5.1G
Swap:            0B          0B          0B

# k8s3
root@k8s3:~# free -h
              total        used        free      shared  buff/cache   available
Mem:            62G         36G         12G        134M         14G         29G
Swap:            0B          0B          0B

会发现实际上,除去 --kube-reserved=memory--system-reserved=memory ,还有可用内存。

所以我们将上图中那些resource requests设置不合理的podrequests memory 设置小一点,就可以调度新的 pod

所以这里要清楚,k8s 通过 pod 配置的 resource requests 值来调度 pod 到资源有余的合适的节点,而节点可用的总资源就是节点实际总资源减去为 kubesystem 预留的资源

使用 kubectl top pod -A 查看 pod 实际资源使用,这里面显示的值就是 resource limit oom killer 依据的值

root@k8s1:/opt/kubespray# kubectl top pod
NAME                      CPU(cores)   MEMORY(bytes)
whoami-5b4bb9c787-m2vdt   0m           3Mi

注意:kubectl top node 显示的资源值,并不是节点上所有pod所使用资源的总和

参考

从一次集群雪崩看Kubelet资源预留的正确姿势

kubernetes集群节点资源预留

为系统守护进程预留计算资源

Configure Out of Resource Handling

从kubectl top看K8S监控

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值