在管理集群的时候我们常常会遇到资源不足的情况,在这种情况下我们要保证整个集群可用,并且尽可能减少应用的损失。根据该问题提出以下两种方案:一种为优化kubelet参数,另一种为脚本化诊断处理。
优化kubelet参数通过k8s资源表示、节点资源配置及kubelet参数设置、应用优先级和资源动态调整这几个方面来介绍。k8s资源表示为yaml文件中如何添加requests和limites参数。节点资源配置及kubelet参数设置描述为一个node上面资源配置情况,从而来优化kubelet参数。应用优先级描述为当资源不足时,优先保留那些pod不被驱逐。资源动态调整描述为运算能力的增减,如:HPA 、VPA和Cluster Auto Scaler。
spec: template: ... spec: containers: ... resources: limits: cpu: "1" memory: 1000Mi requests: cpu: 20m memory: 100Mi
动态调整的思路:应用的实际流量会不断变化,因此使用率也是不断变化的,为了应对应用流量的变化,我们应用能够自动调整应用的资源。比如在线商品应用在促销的时候访问量会增加,我们应该自动增加 pod 运算能力来应对;当促销结束后,有需要自动降低 pod 的运算能力防止浪费。
运算能力的增减有两种方式:改变单个 pod 的资源,已经增减 pod 的数量。这两种方式对应了 kubernetes 的 HPA 和 VPA和Cluster Auto Scaler。
节点资源的配置一般分为 2 种:
allocatable的值即对应 describe node 时看到的allocatable容量,pod 调度的上限
计算公式:节点上可配置值 = 总量 - 预留值 - 驱逐阈值
Allocatable = Capacity - Reserved(kube+system) - Eviction Threshold
以上配置均在kubelet 中添加,涉及的参数有:
--kube-reserved=cpu=200m,memory=250Mi \ --system-reserved=cpu=200m,memory=250Mi \ --eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10% \ --eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15% \ --eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m \ --eviction-max-pod-grace-period=120 \ --eviction-pressure-transition-period=30s \ --eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
以上配置均为百分比,举例:
以2核4GB内存40GB磁盘空间的配置为例,Allocatable是1.6 CPU,3.3Gi 内存,25Gi磁盘。当pod的总内存消耗大于3.3Gi或者磁盘消耗大于25Gi时,会根据相应策略驱逐pod。
Allocatable = 4Gi - 250Mi -250Mi - 4Gi*5% = 3.3Gi
(1) 配置 k8s组件预留资源的大小,CPU、Mem
指定为k8s系统组件(kubelet、kube-proxy、dockerd等)预留的资源量, 如:--kube-reserved=cpu=1,memory=2Gi,ephemeral-storage=1Gi。 这里的kube-reserved只为非pod形式启动的kube组件预留资源,假如组件要是以static pod(kubeadm)形式启动的,那并不在这个kube-reserved管理并限制的cgroup中,而是在kubepod这个cgroup中。 (ephemeral storage需要kubelet开启feature-gates,预留的是临时存储空间(log,EmptyDir),生产环境建议先不使用) ephemeral-storage是kubernetes1.8开始引入的一个资源限制的对象,kubernetes 1.10版本中kubelet默认已经打开的了,到目前1.11还是beta阶段,主要是用于对本地临时存储使用空间大小的限制,如对pod的empty dir、/var/lib/kubelet、日志、容器可读写层的使用大小的限制。
(2)配置 系统守护进程预留资源的大小(预留的值需要根据机器上容器的密度做一个合理的值)
含义:为系统守护进程(sshd, udev等)预留的资源量, 如:--system-reserved=cpu=500m,memory=1Gi,ephemeral-storage=1Gi。 注意,除了考虑为系统进程预留的量之外,还应该为kernel和用户登录会话预留一些内存。
(3)配置 驱逐pod的硬阈值
含义:设置进行pod驱逐的阈值,这个参数只支持内存和磁盘。 通过--eviction-hard标志预留一些内存后,当节点上的可用内存降至保留值以下时, kubelet 将会对pod进行驱逐。 配置:--eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10%
(4)配置 驱逐pod的软阈值
--eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15%
(5)定义达到软阈值之后,持续时间超过多久才进行驱逐
--eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m
(6)驱逐pod前最大等待时间=min(pod.Spec.TerminationGracePeriodSeconds, eviction-max-pod-grace-period),单位为秒
--eviction-max-pod-grace-period=120
(7)至少回收的资源量
--eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
(8)防止波动,kubelet 多久才上报节点的状态
--eviction-pressure-transition-period=30s
(9)centos7配置示例:
查看kubelet Service文件
[root@cwztapp001 kubelet.service.d]# cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf # Note: This dropin only works with kubeadm and kubelet v1.11+ [Service] Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" # This is a file that "kubeadm init" and "kubeadm join" generate at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env # This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use # the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file. EnvironmentFile=-/etc/default/kubelet Environment="KUBELET_EXTRA_ARGS=--node-ip=192.168.30.100 --hostname-override=cwztapp001" ExecStart= ExecStart=/usr/local/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS You have mail in /var/spool/mail/root
根据kubelet Service配置文件可以看出kubelet参数配置文件为/var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: cacheTTL: 0s enabled: true x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook webhook: cacheAuthorizedTTL: 0s cacheUnauthorizedTTL: 0s clusterDNS: - 169.254.25.10 clusterDomain: cluster.local cpuManagerReconcilePeriod: 0s evictionHard: memory.available: 5% evictionMaxPodGracePeriod: 120 evictionPressureTransitionPeriod: 30s evictionSoft: memory.available: 10% evictionSoftGracePeriod: memory.available: 2m featureGates: CSINodeInfo: true ExpandCSIVolumes: true RotateKubeletClientCertificate: true VolumeSnapshotDataSource: true fileCheckFrequency: 0s healthzBindAddress: 127.0.0.1 healthzPort: 10248 httpCheckFrequency: 0s imageMinimumGCAge: 0s kind: KubeletConfiguration kubeReserved: cpu: 200m memory: 250Mi maxPods: 110 nodeStatusReportFrequency: 0s nodeStatusUpdateFrequency: 0s rotateCertificates: true runtimeRequestTimeout: 0s staticPodPath: /etc/kubernetes/manifests streamingConnectionIdleTimeout: 0s syncFrequency: 0s systemReserved: cpu: 1000m memory: 250Mi volumeStatsAggPeriod: 0s
当资源不足时,配置了如上驱逐参数,pod之间的驱逐顺序是怎样的呢?以下描述设置不同优先级来确保集群中核心的组件不被驱逐还正常运行,OOM 的优先级如下,pod oom 值越低,也就越不容易被系统杀死。:
BestEffort Pod > Burstable Pod > 其它进程(内核init进程等) > Guaranteed Pod > kubelet/docker 等 > sshd 等进程
kubernetes 把 pod 分成了三个 QoS 等级,而其中和limits和requests参数有关:
request是否配置 | limits是否配置 | 两者的关系 | Qos | 说明 |
---|---|---|---|---|
是 | 是 | requests=limits | Guaranteed | 所有容器的cpu和memory都必须配置相同的requests和limits |
是 | 是 | request<limit | Burstable | 只要有容器配置了cpu或者memory的request和limits就行 |
是 | 否 | Burstable | 只要有容器配置了cpu或者memory的request就行 | |
否 | 是 | Guaranteed/Burstable | 如果配置了limits,k8s会自动把对应资源的request设置和limits一样。如果所有容器所有资源都配置limits,那就是Guaranteed;如果只有部分配置了limits,就是Burstable | |
否 | 否 | Best Effort | 所有的容器都没有配置资源requests或limits |
说明:
动态地资源调整通过 kubelet 驱逐程序进行的,但需要和应用优先级配合使用才能达到很好的效果,否则可能驱逐集群中核心组件。
什么叫脚本化诊断处理呢?它的含义为:当集群中的某台机器资源(一般指memory)用到85%-90%时,脚本自动检查到且该节点为不可调度。缺点为:背离了资源动态调整中CLuster Auto Scaler特点。