aws/k8s, eks study

EKS Pod Failed: Evicted

gepp 2023. 5. 4. 14:02

 

Issue example:

Reason:         Evicted
Message:        Pod The node had condition: [DiskPressure].

 

멀쩡하게 running 중이던 Pod 의 상태가 Evicted 로 여러 Pod로 늘어나 있는 경우, 어떤 이유에 의해 새  Pod를 예약할 수 없는 상태일 때 발생한다.

여기서 Message 를 보면 DiskPressure 조건에 의해 실패하였으며 해당 경우에는 노드의 사용 가능한 디스크 공간이 부족하거나 소진되어 쿠버네티스 시스템에서 해당 노드에 새 포드를 예약할 수 없어 포드가 해당 노드에서 제거된 것을 알 수 있다.

시스템은 디스크 공간을 확보하고 클러스터의 전반적인 안정성을 보장하기 위해 노드의 기존 포드를 제거할 수 있다.

 

해당 DiskPressure 조건에 미치려면 몇가지 경우의 수가 있다.

  1. 해당 노드의 disk usage 문제
    1. 노드의 디스크 공간 체크, 부족시 불필요한 파일 삭제 및 더 많은 스토리지 용량 추가 등으로 해결
  2. 해당 노드의 사용중인 inode usage 문제
    1. df -i 로 inode 용량 확인
  3. 처리되는 파일 갯수의 문제 (Max open files)
    1. 아래 명령어로 확인
cat /proc/$(pgrep kubelet)/limits | grep "Max open files"

             결과 값:

# cat /proc/$(pgrep kubelet)/limits | grep "Max open files"
Max open files            1000000              1000000              files

            2. 높은 경우, kubelet 프로세스의 최대 열린 파일 수를 늘려본다. 해당 노드의 kubelet conf 파일에 적절한 Limit 값을 설정하면 된다.

                설정 파일 위치: /etc/systemd/system/kubelet.service.d/

                추가 값 예시: LimitNOFILE=1000000

[Service] 섹션에 해당 값을 추가한다. 추가 후에는 데몬을 리로드하고 kubelet 을 재기동한다.

sudo systemctl daemon-reload
sudo systemctl restart kubelet

kubelet 의 eviction threshold 를 확인하려면 해당 워커노드의 /etc/kubernetes/ 에 kubelet 관련 파일의 "evictionHard" 부분을 확인할 수 있다.

  "evictionHard": {
    "memory.available": "100Mi",
    "nodefs.available": "10%",
    "nodefs.inodesFree": "5%"
  },

nodefs.available은 disk pressure과 관련있고 위에서는 10%로 설정되어있다. 즉, 해당 노드에서 사용 가능한 파일 시스템 공간의 비율이 10% 미만으로 떨어지면 Kubernetes가 노드에서 포드를 evicted한다.

 

공식문서 참고:

Minimum eviction reclaim

In some cases, pod eviction only reclaims a small amount of the starved resource. This can lead to the kubelet repeatedly hitting the configured eviction thresholds and triggering multiple evictions.

You can use the --eviction-minimum-reclaim flag or a kubelet config file to configure a minimum reclaim amount for each resource. When the kubelet notices that a resource is starved, it continues to reclaim that resource until it reclaims the quantity you specify.

For example, the following configuration sets minimum reclaim amounts:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
  memory.available: "500Mi"
  nodefs.available: "1Gi"
  imagefs.available: "100Gi"
evictionMinimumReclaim:
  memory.available: "0Mi"
  nodefs.available: "500Mi"
  imagefs.available: "2Gi"

 

이외 기존 Evicted Pod들을 아래 명령어로 Running 상태인 pod 제외하고 제거할 수 있다.

kubectl get pods -n <namespace> --field-selector=status.phase=Failed | grep Evicted | awk '{if($3!="Running") print $1}' | xargs kubectl delete pod -n <namespace>

또는 깔끔하게 해당 포드의 deployment 파일 replica 수롤 조정하여 재 배포한다.

replicas 를 0개로 했다가 다시 증가시킨다.

kubectl scale deployment <your-deployment-name> --replicas=0 -n monitoring

재 배포 전에 Back-off 에러가 발생하여 로그를 확인해보니 아래 에러가 발생하였다.

msg="Error loading config (--config.file=/etc/config/prometheus.yml)" err="parsing YAML file /etc/config/prometheus.yml: yaml: unmarshal errors:\n  line 14: field metrics_path not found in type struct { Targets []string \"yaml:\\\"targets\\\"\"; Labels model.LabelSet \"yaml:\\\"labels\\\"\" }"

컨테이너 두개중 컨피그맵을 통째로 /etc/config 에 맵핑한 것은 정상인데 두번째 컨테이너의 /etc/config/blahblah.yml 로 마운트한 부분 값과 관련하여 yaml: unmarshal 에러가 발생했다.

관련 서비스 컨피그맵의 해당 yml 아래 metrics_path 를 확인하여 syntax 에러를 수정하고 재 배포 후 해결되었다.

 

Before:

      - job_name: actuator
        static_configs:
          - targets: [eap-was.eap.svc:30001]
            metric_path: '/actuator/prometheus'

After: (metrics_path 위치 변경)

- job_name: actuator
  metrics_path: /actuator/prometheus
  static_configs:
  - targets:

 

이외 추가로 알게된 Tip:

  • DaemonSet YAML 을 이전 generation 버전으로 롤백하려고 할때 -

1. 롤백 가능한 버전을 아래 명령어를 이용해 확인한다.

kubectl rollout history daemonset <daemonset-name> -n <namespace>

2. 해당 원하는 버전으로 롤백한다.

kubectl rollout undo daemonset <daemonset-name> -n <namespace> --to-revision=1

--to-revision 에 원하는 버전 값을 입력할 수 있다.

 

  • 기존 중복된 리소스로 인해 helm install 이 실패시 

에러 메시지 예:

helm install <serviced> <service>/<serviced>  --namespace <your namespace>
Error: INSTALLATION FAILED: rendered manifests contain a resource that already exists. Unable to continue with install: ClusterRoleBinding "serviced" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata; label validation

해당 리소스 삭제 후 재 설치한다.

kubectl delete clusterrolebinding <servicd name> -n <your namespace>

 

Pod selection for kubelet eviction: https://kubernetes.io/docs/concepts/scheduling-eviction/node-pressure-eviction/

 

Node-pressure Eviction

Node-pressure eviction is the process by which the kubelet proactively terminates pods to reclaim resources on nodes. The kubelet monitors resources like memory, disk space, and filesystem inodes on your cluster's nodes. When one or more of these resources

kubernetes.io

Pod selection for kubelet eviction 
If the kubelet's attempts to reclaim node-level resources don't bring the eviction signal below the threshold, the kubelet begins to evict end-user pods.
The kubelet uses the following parameters to determine the pod eviction order:
Whether the pod's resource usage exceeds requestsPod PriorityThe pod's resource usage relative to requests
As a result, kubelet ranks and evicts pods in the following order:
BestEffort or Burstable pods where the usage exceeds requests. These pods are evicted based on their Priority and then by how much their usage level exceeds the request.Guaranteed pods and Burstable pods where the usage is less than requests are evicted last, based on their Priority.
Note: The kubelet does not use the pod's QoS class to determine the eviction order. You can use the QoS class to estimate the most likely pod eviction order when reclaiming resources like memory. QoS does not apply to EphemeralStorage requests, so the above scenario will not apply if the node is, for example, under DiskPressure.

 

+

Node conditions 

The kubelet reports node conditions to reflect that the node is under pressure because hard or soft eviction threshold is met, independent of configured grace periods.

The kubelet maps eviction signals to node conditions as follows:

 

ETC.

kube-controller-manager.service

ExecStart=/usr/local/bin/kube-controller-manater \\
	--address=0.0.0.0 \\
    --cluster-cidr=x.x.x.x/x \\
    --cluster-name=<name> \\
    ....
    
    --node-monitor-period=5s
    --node-monitor-grace-period=40s
    --pod-eviction-timeout=5m0s
    
    ...