自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

生產(chǎn)環(huán)境 Kubernetes 中出現(xiàn)了很多 Evicted Pod,我該怎么辦呢?

系統(tǒng) Linux
本文會(huì)分析為什么為產(chǎn)生 Evicted 實(shí)例、為什么 Evicted 實(shí)例沒有被自動(dòng)清理以及如何進(jìn)行自動(dòng)清理。

 [[439064]]

線上被驅(qū)逐實(shí)例數(shù)據(jù)

最近在線上發(fā)現(xiàn)很多實(shí)例處于 Evicted 狀態(tài),通過 pod yaml 可以看到實(shí)例是因?yàn)楣?jié)點(diǎn)資源不足被驅(qū)逐,但是這些實(shí)例并沒有被自動(dòng)清理,平臺(tái)的大部分用戶在操作時(shí)看到服務(wù)下面出現(xiàn) Evicted 實(shí)例時(shí)會(huì)以為服務(wù)有問題或者平臺(tái)有問題的錯(cuò)覺,影響了用戶的體驗(yàn)。而這部分 Evicted 狀態(tài)的 Pod 在底層關(guān)聯(lián)的容器其實(shí)已經(jīng)被銷毀了,對(duì)用戶的服務(wù)也不會(huì)產(chǎn)生什么影響,也就是說只有一個(gè) Pod 空殼在 k8s 中保存著,但需要人為手動(dòng)清理。本文會(huì)分析為什么為產(chǎn)生 Evicted 實(shí)例、為什么 Evicted 實(shí)例沒有被自動(dòng)清理以及如何進(jìn)行自動(dòng)清理。

kubernetes 版本:v1.17 

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

Evicted 實(shí)例狀態(tài): 

  1. status:  
  2.   message: 'Pod The node had condition: [DiskPressure]. '  
  3.   phase: Failed  
  4.   reason: Evicted  
  5.   startTime: "2021-09-14T10:42:32Z" 

實(shí)例被驅(qū)逐的原因

kubelet 默認(rèn)會(huì)配置節(jié)點(diǎn)資源不足時(shí)驅(qū)逐實(shí)例的策略,當(dāng)節(jié)點(diǎn)資源不足時(shí) k8s 會(huì)停止該節(jié)點(diǎn)上實(shí)例并在其他節(jié)點(diǎn)啟動(dòng)新實(shí)例,在某些情況下也可通過配置 --eviction-hard= 參數(shù)為空來禁用驅(qū)逐策略,在之前的生產(chǎn)環(huán)境中我們也確實(shí)這么做了。

節(jié)點(diǎn)資源不足導(dǎo)致實(shí)例被驅(qū)逐

k8s 中產(chǎn)生 Evicted 狀態(tài)實(shí)例主要是因?yàn)楣?jié)點(diǎn)資源不足實(shí)例主動(dòng)被驅(qū)逐導(dǎo)致的,kubelet eviction_manager 模塊會(huì)定期檢查節(jié)點(diǎn)內(nèi)存使用率、inode 使用率、磁盤使用率、pid 等資源,根據(jù) kubelet 的配置當(dāng)使用率達(dá)到一定閾值后會(huì)先回收可以回收的資源,若回收后資源使用率依然超過閾值則進(jìn)行驅(qū)逐實(shí)例操作。

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

kubelet 中 pod 的 stats 數(shù)據(jù)一部分是通過 cAdvisor 接口獲取到的,一部分是通過 CRI runtimes 的接口獲取到的。

  •  memory.available:當(dāng)前節(jié)點(diǎn)可用內(nèi)存,計(jì)算方式為 cgroup memory 子系統(tǒng)中 memory.usage_in_bytes 中的值減去 memory.stat 中 total_inactive_file 的值;
  •  nodefs.available:nodefs 包含 kubelet 配置中 --root-dir 指定的文件分區(qū)和 /var/lib/kubelet/ 所在的分區(qū)磁盤使用率;
  •  nodefs.inodesFree:nodefs.available 分區(qū)的 inode 使用率;
  •  imagefs.available:鏡像所在分區(qū)磁盤使用率;
  •  imagefs.inodesFree:鏡像所在分區(qū)磁盤 inode 使用率;
  •  pid.available:/proc/sys/kernel/pid_max 中的值為系統(tǒng)最大可用 pid 數(shù);

kubelet 可以通過參數(shù) --eviction-hard 來配置以上幾個(gè)參數(shù)的閾值,該參數(shù)默認(rèn)值為 imagefs.available<15%,memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,當(dāng)達(dá)到閾值時(shí)會(huì)驅(qū)逐節(jié)點(diǎn)上的容器。

kubelet 驅(qū)逐實(shí)例時(shí)與資源處理相關(guān)的已知問題

1、kubelet 不會(huì)實(shí)時(shí)感知到節(jié)點(diǎn)內(nèi)存數(shù)據(jù)的變化

kubelet 定期通過 cadvisor 接口采集節(jié)點(diǎn)內(nèi)存使用數(shù)據(jù),當(dāng)節(jié)點(diǎn)短時(shí)間內(nèi)內(nèi)存使用率突增,此時(shí) kubelet 無法感知到也不會(huì)有 MemoryPressure 相關(guān)事件,但依然會(huì)調(diào)用 OOMKiller 停止容器??梢酝ㄟ^為 kubelet 配置 --kernel-memcg-notification 參數(shù)啟用 memcg api,當(dāng)觸發(fā) memory 使用率閾值時(shí) memcg 會(huì)主動(dòng)進(jìn)行通知;

memcg 主動(dòng)通知的功能是 cgroup 中已有的,kubelet 會(huì)在 /sys/fs/cgroup/memory/cgroup.event_control 文件中寫入 memory.available 的閾值,而閾值與 inactive_file 文件的大小有關(guān)系,kubelet 也會(huì)定期更新閾值,當(dāng) memcg 使用率達(dá)到配置的閾值后會(huì)主動(dòng)通知 kubelet,kubelet 通過 epoll 機(jī)制來接收通知。

2、kubelet memory.available 不會(huì)計(jì)算 active page

kubelet 通過內(nèi)存使用率驅(qū)逐實(shí)例時(shí),內(nèi)存使用率數(shù)據(jù)包含了 page cache 中 active_file 的數(shù)據(jù),在某些場景下會(huì)因 page cache 過高導(dǎo)致內(nèi)存使用率超過閾值會(huì)造成實(shí)例被驅(qū)逐,

由于在內(nèi)存緊張時(shí) inactive_file 會(huì)被內(nèi)核首先回收,但在內(nèi)存不足時(shí),active_file 也會(huì)被內(nèi)核進(jìn)行回收,社區(qū)對(duì)此機(jī)制也有一些疑問,針對(duì)內(nèi)核回收內(nèi)存的情況比較復(fù)雜,社區(qū)暫時(shí)還未進(jìn)行回應(yīng),詳情可以參考 kubelet counts active page cache against memory.available (maybe it shouldn’t?)[1]。

kubelet 計(jì)算節(jié)點(diǎn)可用內(nèi)存的方式如下: 

  1. #!/bin/bash  
  2. #!/usr/bin/env bash  
  3. # This script reproduces what the kubelet does  
  4. # to calculate memory.available relative to root cgroup.  
  5. # current memory usage  
  6. memory_capacity_in_kb=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}')  
  7. memory_capacity_in_bytes=$((memory_capacity_in_kb * 1024))  
  8. memory_usage_in_bytes=$(cat /sys/fs/cgroup/memory/memory.usage_in_bytes)  
  9. memory_total_inactive_file=$(cat /sys/fs/cgroup/memory/memory.stat | grep total_inactive_file | awk '{print $2}')  
  10. memory_working_set=${memory_usage_in_bytes}  
  11. if [ "$memory_working_set" -lt "$memory_total_inactive_file" ];  
  12. then  
  13.     memory_working_set=0  
  14. else  
  15.     memory_working_set=$((memory_usage_in_bytes - memory_total_inactive_file))  
  16. fi  
  17. memory_available_in_bytes=$((memory_capacity_in_bytes - memory_working_set))  
  18. memory_available_in_kb=$((memory_available_in_bytes / 1024))  
  19. memory_available_in_mb=$((memory_available_in_kb / 1024))  
  20. echo "memory.capacity_in_bytes $memory_capacity_in_bytes"  
  21. echo "memory.usage_in_bytes $memory_usage_in_bytes"  
  22. echo "memory.total_inactive_file $memory_total_inactive_file"  
  23. echo "memory.working_set $memory_working_set"  
  24. echo "memory.available_in_bytes $memory_available_in_bytes"  
  25. echo "memory.available_in_kb $memory_available_in_kb"  
  26. echo "memory.available_in_mb $memory_available_in_mb" 

驅(qū)逐實(shí)例未被刪除原因分析

源碼中對(duì)于 Statefulset 和 DaemonSet 會(huì)自動(dòng)刪除 Evicted 實(shí)例,但是對(duì)于 Deployment 不會(huì)自動(dòng)刪除。閱讀了部分官方文檔以及 issue,暫未找到官方對(duì) Deployment Evicted 實(shí)例未刪除原因給出解釋。

statefulset:pkg/controller/statefulset/stateful_set_control.go 

  1. // Examine each replica with respect to its ordinal  
  2. for i :range replicas {  
  3.     // delete and recreate failed pods  
  4.     if isFailed(replicas[i]) {  
  5.         ssc.recorder.Eventf(set, v1.EventTypeWarning, "RecreatingFailedPod",  
  6.             "StatefulSet %s/%s is recreating failed Pod %s",  
  7.             set.Namespace,  
  8.             set.Name,  
  9.             replicas[i].Name)  
  10.         if err :ssc.podControl.DeleteStatefulPod(set, replicas[i]); err != nil {  
  11.             return &status, err  
  12.         }  
  13.         if getPodRevision(replicas[i]) == currentRevision.Name {  
  14.             status.CurrentReplicas--  
  15.         } 
  16.          if getPodRevision(replicas[i]) == updateRevision.Name {  
  17.             status.UpdatedReplicas--  
  18.         }  
  19.         ...... 

daemonset:pkg/controller/daemon/daemon_controller.go 

  1. func (dsc *DaemonSetsController) podsShouldBeOnNode(  
  2.   ......  
  3. ) (nodesNeedingDaemonPods, podsToDelete []string) {  
  4.   ......  
  5.     switch {  
  6.   ......  
  7.     case shouldContinueRunning:  
  8.     ......  
  9.         for _, pod :range daemonPods {  
  10.             if pod.DeletionTimestamp != nil {  
  11.                 continue  
  12.             }  
  13.             if pod.Status.Phase == v1.PodFailed {  
  14.                 // This is a critical place where DS is often fighting with kubelet that rejects pods.  
  15.                 // We need to avoid hot looping and backoff.  
  16.                 backoffKey :failedPodsBackoffKey(ds, node.Name)  
  17.                 ...... 

解決方案

1、團(tuán)隊(duì)里面有了一套 k8s 集群事件采集的鏈路,我們通過消費(fèi) k8s 中 pod 的相關(guān)事件來進(jìn)行處理,消費(fèi)事件時(shí)過濾 pod 中與 Evicted 實(shí)例相關(guān)的事件然后處理即可。

Evicted 實(shí)例判斷邏輯: 

  1. const (  
  2.  podEvictedStatus = "Evicted"  
  3.  
  4. // 判斷如果為 Evicted 狀態(tài)的實(shí)例且 Pod 中容器數(shù)為 0 時(shí)直接刪除 pod  
  5. if strings.ToLower(status) == strings.ToLower(podEvictedStatus) && len(pod.Status.ContainerStatuses) == 0 {  

2、社區(qū)有人提供通過在 kube-controller-manager 中配置 podgc controller –terminated-pod-gc-threshold 參數(shù)來自動(dòng)清理: 

  1. Podgc controller flags:  
  2.       --terminated-pod-gc-threshold int32  
  3.                 Number of terminated pods that can exist before the terminated pod garbage collector starts deleting terminated pods. If  
  4.                 <= 0, the terminated pod garbage collector is disabled. (default 12500) 

該參數(shù)配置的是保留的異常實(shí)例數(shù),默認(rèn)值為 12500,但 podgc controller 回收 pod 時(shí)使用強(qiáng)殺模式不支持實(shí)例的優(yōu)雅退出,因此暫不考慮使用。

3、其他處理方式可以參考社區(qū)中提供的 Kubelet does not delete evicted pods[2]。

總結(jié)

由于在之前的公司中對(duì)于穩(wěn)定性的高度重視,線上節(jié)點(diǎn)并未開啟驅(qū)逐實(shí)例的功能,因此也不會(huì)存在 Evicted 狀態(tài)的實(shí)例,當(dāng)節(jié)點(diǎn)資源嚴(yán)重不足時(shí)會(huì)有告警人工介入處理,以及還會(huì)有二次調(diào)度、故障自愈等一些輔助處理措施。本次針對(duì) Evicted 相關(guān)實(shí)例的分析,發(fā)現(xiàn) k8s 與操作系統(tǒng)之間存在了很多聯(lián)系,如果要徹底搞清楚某些機(jī)制需要對(duì)操作系統(tǒng)的一些原理有一定的了解。 

 

責(zé)任編輯:龐桂玉 來源: 奇妙的Linux世界
相關(guān)推薦

2021-12-09 11:46:53

DockerIPLinux

2018-08-20 19:39:14

區(qū)塊鏈職業(yè)崗位

2020-09-29 12:15:13

生死鎖MySQL

2022-02-06 00:16:53

加密貨幣比特幣以太坊

2019-06-03 10:53:49

MySQL硬盤數(shù)據(jù)庫

2020-07-21 10:05:48

技術(shù)研發(fā)指標(biāo)

2011-10-17 12:30:43

2022-05-19 08:01:49

PostgreSQL數(shù)據(jù)庫

2022-09-05 09:02:01

服務(wù)器CPU服務(wù)

2018-01-28 20:39:39

戴爾

2009-11-03 08:56:02

linux死機(jī)操作系統(tǒng)

2022-12-19 11:31:57

緩存失效數(shù)據(jù)庫

2022-07-05 11:48:47

MySQL死鎖表鎖

2022-04-22 10:30:07

框架JavaScript前端

2011-06-30 17:58:30

網(wǎng)站被K

2020-12-18 09:23:41

KubernetesDocker

2011-11-18 10:52:00

2022-07-05 14:19:30

Spring接口CGLIB

2022-10-14 08:18:07

Guavaweb應(yīng)用

2011-11-16 10:02:48

DNSDNS記錄DNS記錄消失
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)