JAVA面试题分享二百四十七:Kubernetes之kubelet驱逐策略详解

目录

Kubernetes为何需要驱逐Pod

Kubelet Eviction 策略的工作机制

kubelet的驱逐策略

1. 软驱逐(Soft Eviction Thresholds)

2. 硬驱逐(Hard Eviction Thresholds)

3. Pod驱逐流程

4. 资源紧缺时,驱逐Pod的优先级规则:

5. 修改kubelet默认的驱逐阈值方法

6. 处理产生大量Eviction状态Pod的方法


Kubernetes为何需要驱逐Pod

在可用计算资源较少时,kubelet为保证节点稳定性,会主动地结束一个或多个pod以回收短缺地资源,这在处理内存和磁盘这种不可压缩资源时,驱逐pod回收资源的策略,显得尤为重要

  • 可压缩资源: CPU,可压缩资源不会导致pod驱逐,因为在资源紧缺时系统内核会重新分配权重

  • 不可压缩资源: 内存 磁盘

Kubelet Eviction 策略的工作机制

  • kubelet预先监控本节点的资源使用,防止资源被耗尽,保证节点稳定性

  • kubelet会预先Fail N(>=1)个Pod,以回收出现紧缺的资源

  • kubelet在Fail一个pod时,kill掉pod内所有container,并设置pod.status.phase = Failed

  • kubelet按照事先设定好的Eviction Threshold来触发驱逐动作,实现资源回收

驱逐信号

序号驱逐信号解释
01memory.availablenode.status.capacity[memory] - node.stats.memory.workingSet
02nodefs.availablenode.stats.fs.available
03nodefs.inodesFreenode.stats.fs.inodesFree
04imagefs.availablenode.stats.runtime.imagefs.available
05imagefs.inodesFreenode.stats.runtime.imagefs.inodesFree
06allocatableMemory.availablepod.allocatable - pod.workingSet
07pid.availablenode.MaxPID - node.NumOfRunningProcesses

上表主要涉及三个方面,memory、file system和pid, 其中kubelet支持2种file system类型的驱逐:

  1. nodefs:kubelet 用来存储 pods 或 volume 和 daemon logs 的信息等

  2. Imagesfs:用来存储 docker 镜像层或容器层数据的路径(readOnly layer and write layer)

kubelet的驱逐策略

k8s中定义了两种驱逐策略,一种为软驱逐,一种为硬驱逐
1. 软驱逐(Soft Eviction Thresholds)
软驱逐机制表示,当node的 内存/磁盘 空间达到一定的阈值后,观察一段时间,如果改善到低于阈值就不进行驱逐,若这段时间一直高于阈值就进行驱逐,一般有如下三个参数配合使用:
  • eviction-soft:触发软驱逐策略的阀值

  • eviction-soft-grace-period:触发软驱逐策略的阀值后等待的时间,如果在此时间内还未恢复到阀值以下,则会开始驱逐pod

  • eviction-max-pod-grace-period:达到软阈值之后,到驱逐一个 Pod 之前的最大宽限时间(单位s)

2. 硬驱逐(Hard Eviction Thresholds)
  • 硬驱逐简单粗暴,没有宽限期,一旦达到阈值配置,kubelet立马回收关联的短缺资源,将pod kill掉,而不是优雅终止
  • 源代码定义目录 pkg/kubelet/apis/config/v1beta1/defaults_linux.go

//go:build linux
// +build linux

/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

// DefaultEvictionHard includes default options for hard eviction.
var DefaultEvictionHard = map[string]string{
    "memory.available":  "100Mi",
    "nodefs.available":  "10%",
    "nodefs.inodesFree": "5%",
    "imagefs.available": "15%",
}
3. Pod驱逐流程
  •  kubelet在节点对应的配置文件路径 /var/lib/kubelet/config.yaml

    当资源使用情况触发了驱逐条件时,kubelet会启动一个任务去轮流停止运行中的pod,直到资源使用状况恢复到阈值以下。以硬驱逐为例,整体流程是:
  1. 每隔一段时间从cadvisor中获取资源使用情况,和定义的阀值进行对比,在 kubelet 中 --node-status-update-frequency 参数来定义获取上报的频率,默认为10s

    • 首先从运行中的pod里找到QoS策略最开放的类型 pod

    • 然后根据 Pod 调度请求的被耗尽资源的消耗量来结合进行驱逐

  2. 检查资源是否到达阀值以内,若还未满足,则再进行第二步

Qos驱逐等级

当一个pod被创建,kubernetes会赋予它们以下类型的值之一:

  • Guaranteed

  • Burstable

  • BestEffor

    三种Qos类型优先级(由高到低): Guaranteed >  Burstable >  BestEffort, 从上到下,它们的质量会越来越低,质量越高,该pod就会尽量被保护,不被驱逐

满足以下条件的pod将会被赋予 Guaranteed QoS类型:

  • pod中每个容器都必须包含内存请求和限制,并且值相等

  • pod中每个容器都必须包含cpu请求和限制,并且值相等 sample

kind: Deployment
apiVersion: apps/v1
metadata:
  name: nginx-qos-example
  namespace: default
  labels:
    app: nginx-qos-example
  annotations:
    deployment.kubernetes.io/revision: '1'
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-qos-example
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-qos-example
    spec:
      containers:
        - name: nginx
          image: 'nginx:1.19.7'
          resources:
            limits:
              cpu: 500m
              memory: 128Mi
            requests:
              cpu: 500m
              memory: 128Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      securityContext: {}
      schedulerName: default-scheduler
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  revisionHistoryLimit: 10
  progressDeadlineSeconds: 600

当符合以下条件时,一个pod会被赋予Burstable类型的QoS

  • Pod不符合 Guaranteed 类型的QoS要求

  • pod至少设置了内存或者cpu请任一

一个pod即没有内存限制或请求也没有cpu限制或请求,则会被赋予BestEffort

查看某个Pod的Qos优先级方法:

kubectl -n default get pod nginx-qos-example-78cf8dd6f-qmkt2 -o jsonpath='{.status.qosClass}'
Guaranteed%
4. 资源紧缺时,驱逐Pod的优先级规则:
  • 当 pod qos=BestEffort 时,消耗最多紧缺资源的 Pod 最先驱逐

  • 当 pod qos=Burstable 时,请求(request的值)最多紧缺资源的 Pod 会被驱逐,如果没有 Pod 超出他们的请求(比如说mem request的值为1G,但实际使用量并没有超过1G),会驱逐资源消耗量最大的 Pod

  • 当 pod qos=Guaranteed 时,请求(request的值)最多紧缺资源的 Pod 被驱逐,如果没有 Pod 超出他们的请求,会驱逐资源消耗量最大的 Pod

  • 如果当磁盘空间/inodes紧缺时,就会通过 QoS 的等级基础上,选择消耗最多磁盘空间inodes的 Pod 进行驱逐

5. 修改kubelet默认的驱逐阈值方法

硬驱逐阈值的设置

将策略加入到 /var/lib/kubelet/config.yaml即kubelet启动参数即可:
evictionHard:
  memory.available:  "2048Mi"
  imagefs.available: "5G"
  nodefs.available: "5G"
  nodefs.inodesFree: "5%"

软驱逐阈值的设置

将策略加入到 /var/lib/kubelet/config.yaml即kubelet启动参数即可:
evictionSoft:
  memory.available:  "4096Mi"
  imagefs.available: "10G"
  nodefs.available: "10G"
  nodefs.inodesFree: "10%"
evictionSoftGracePeriod:
  memory.available:  "60s"
  imagefs.available: "60s"
  nodefs.available: "60s"
  nodefs.inodesFree: "60s"

结合硬驱逐+软驱逐最后完整的/var/lib/kubelet/config.yaml配置

evictionSoft:
  memory.available:  "4096Mi"
  imagefs.available: "10G"
  nodefs.available: "10G"
  nodefs.inodesFree: "10%"
evictionSoftGracePeriod:
  memory.available:  "60s"
  imagefs.available: "60s"
  nodefs.available: "60s"
  nodefs.inodesFree: "60s"
evictionHard:
  memory.available:  "2048Mi"
  imagefs.available: "5G"
  nodefs.available: "5G"
  nodefs.inodesFree: "5%"

重启kubelet使其配置生效

systemctl restart kubelet

查看当前节点kubelet生效配置内容

执行kubectl proxy

Starting to serve on 127.0.0.1:8001

查看节点配置

curl -sSL http://127.0.0.1:8001/api/v1/nodes/{nodeName}/proxy/configz | jq
{
  "kubeletconfig": {
    "enableServer": true,
    "staticPodPath": "/etc/kubernetes/manifests",
    "syncFrequency": "1m0s",
    "fileCheckFrequency": "20s",
    "httpCheckFrequency": "20s",
    "address": "0.0.0.0",
    "port": 10250,
    "tlsCertFile": "/var/lib/kubelet/pki/kubelet.crt",
    "tlsPrivateKeyFile": "/var/lib/kubelet/pki/kubelet.key",
    "rotateCertificates": true,
    "authentication": {
      "x509": {
        "clientCAFile": "/etc/kubernetes/pki/ca.crt"
      },
      "webhook": {
        "enabled": true,
        "cacheTTL": "2m0s"
      },
      "anonymous": {
        "enabled": false
      }
    },
    "authorization": {
      "mode": "Webhook",
      "webhook": {
        "cacheAuthorizedTTL": "5m0s",
        "cacheUnauthorizedTTL": "30s"
      }
    },
    "registryPullQPS": 5,
    "registryBurst": 10,
    "eventRecordQPS": 5,
    "eventBurst": 10,
    "enableDebuggingHandlers": true,
    "healthzPort": 10248,
    "healthzBindAddress": "127.0.0.1",
    "oomScoreAdj": -999,
    "clusterDomain": "cluster.local",
    "clusterDNS": [
      "10.91.0.10"
    ],
    "streamingConnectionIdleTimeout": "4h0m0s",
    "nodeStatusUpdateFrequency": "10s",
    "nodeStatusReportFrequency": "5m0s",
    "nodeLeaseDurationSeconds": 40,
    "imageMinimumGCAge": "2m0s",
    "imageGCHighThresholdPercent": 85,
    "imageGCLowThresholdPercent": 80,
    "volumeStatsAggPeriod": "1m0s",
    "cgroupsPerQOS": true,
    "cgroupDriver": "systemd",
    "cpuManagerPolicy": "none",
    "cpuManagerReconcilePeriod": "10s",
    "memoryManagerPolicy": "None",
    "topologyManagerPolicy": "none",
    "topologyManagerScope": "container",
    "runtimeRequestTimeout": "2m0s",
    "hairpinMode": "promiscuous-bridge",
    "maxPods": 110,
    "podPidsLimit": -1,
    "resolvConf": "/etc/resolv.conf",
    "cpuCFSQuota": true,
    "cpuCFSQuotaPeriod": "100ms",
    "nodeStatusMaxImages": 50,
    "maxOpenFiles": 1000000,
    "contentType": "application/vnd.kubernetes.protobuf",
    "kubeAPIQPS": 5,
    "kubeAPIBurst": 10,
    "serializeImagePulls": true,
    "evictionHard": {
      "imagefs.available": "5G",
      "memory.available": "2048Mi",
      "nodefs.available": "5G",
      "nodefs.inodesFree": "5%"
    },
    "evictionSoft": {
      "imagefs.available": "10G",
      "memory.available": "4096Mi",
      "nodefs.available": "10G",
      "nodefs.inodesFree": "10%"
    },
    "evictionSoftGracePeriod": {
      "imagefs.available": "60s",
      "memory.available": "60s",
      "nodefs.available": "60s",
      "nodefs.inodesFree": "60s"
    },
    "evictionPressureTransitionPeriod": "5m0s",
    "enableControllerAttachDetach": true,
    "makeIPTablesUtilChains": true,
    "iptablesMasqueradeBit": 14,
    "iptablesDropBit": 15,
    "failSwapOn": true,
    "memorySwap": {},
    "containerLogMaxSize": "10Mi",
    "containerLogMaxFiles": 5,
    "configMapAndSecretChangeDetectionStrategy": "Watch",
    "enforceNodeAllocatable": [
      "pods"
    ],
    "volumePluginDir": "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/",
    "logging": {
      "format": "text",
      "flushFrequency": 5000000000,
      "verbosity": 0,
      "options": {
        "json": {
          "infoBufferSize": "0"
        }
      }
    },
    "enableSystemLogHandler": true,
    "shutdownGracePeriod": "0s",
    "shutdownGracePeriodCriticalPods": "0s",
    "enableProfilingHandler": true,
    "enableDebugFlagsHandler": true,
    "seccompDefault": false,
    "memoryThrottlingFactor": 0.8,
    "registerNode": true
  }
}
6. 处理产生大量Eviction状态Pod的方法

当资源不够或发生争夺有pod被驱逐后,pod的状态会变为Eviction,如果资源一直无法协调过来,或者资源真的不够用了,那么会产生大量的Eviction状态的Pod,会影响整个集群的使用。

此配置其实是由 kube-contoller-manager 来管理的,所以想要修改要修改kube-contoller-manager.yaml的参数,一般在/etc/kubernetes/manifests/kube-contoller-manager.yaml添加

--terminated-pod-gc-threshold=5
spec:
  containers:
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
    - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    - --bind-address=0.0.0.0
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --cluster-cidr=10.241.0.0/16
    - --cluster-name=uat-pressure-k8s
    - --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
    - --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
    - --controllers=*,bootstrapsigner,tokencleaner
    - --kubeconfig=/etc/kubernetes/controller-manager.conf
    - --leader-elect=true
    - --terminated-pod-gc-threshold=5
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --root-ca-file=/etc/kubernetes/pki/ca.crt
    - --service-account-private-key-file=/etc/kubernetes/pki/sa.key
    - --service-cluster-ip-range=10.91.0.0/16
    - --use-service-account-credentials=true

此值设定了Eviction pod最大的产生个数,默认为12500,最小改为1,若为0,则表示没有限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值