Amazon EKS에서 포드 상태 문제를 해결하려면 어떻게 해야 하나요?

9분 분량
0

Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스 또는 관리형 노드 그룹에서 실행 중인 Amazon Elastic Kubernetes Service(Amazon EKS) 포드가 멈춰 있습니다. 포드를 실행 중 상태가 되게 하고 싶습니다.

해결 방법

중요: 다음 단계는 Amazon EC2 인스턴스 또는 관리형 노드 그룹에서 시작된 포드에만 적용됩니다. 이 단계는 AWS Fargate에서 시작한 포드에는 적용되지 않습니다.

포드의 상태 확인

1.    포드의 상태를 가져오려면 다음 명령을 실행합니다.

$ kubectl get pod

2.    포드의 이벤트 기록에서 정보를 가져오려면 다음 명령을 실행합니다.

$ kubectl describe pod YOUR_POD_NAME

참고: 다음 단계에서 다루는 예제 명령은 기본 네임스페이스에 있습니다. 다른 네임스페이스의 경우 명령 -n YOURNAMESPACE을 추가합니다.

3.    포드의 상태에 따라 포드가 보류 중(Pending) 상태에 있음, 포드가 대기 중(Waiting) 상태에 있음, 포드가 CrashLoopBackOff 상태에 있음 섹션 중 하나에서 단계를 완료합니다.

Pod가 보류 중 상태에 있음

보류 중 상태의 포드는 노드에 예약할 수 없습니다. 리소스가 부족하거나 hostPort를 사용하여 발생할 수 있습니다. 자세한 내용은 포드 단계를 Kubernetes 설명서에서 참조하세요.

작업자 노드에서 사용 가능한 리소스가 충분하지 않은 경우 불필요한 파드를 삭제하는 것이 좋습니다. 작업자 노드에 더 많은 리소스를 추가할 수도 있습니다. 클러스터의 리소스가 부족할 때 Kubernetes Cluster Autoscaler를 사용하여 작업자 노드 그룹을 자동으로 조정할 수 있습니다.

CPU 부족

$ kubectl describe pod frontend-cpu                               
Name:         frontend-cpu
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  22s (x14 over 13m)  default-scheduler  0/3 nodes are available: 3 Insufficient cpu.

메모리 부족

$ kubectl describe pod frontend-memory
Name:         frontend-memory
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                 From               Message
  ----     ------            ----                ----               -------
  Warning  FailedScheduling  80s (x14 over 15m)  default-scheduler  0/3 nodes are available: 3 Insufficient memory.

포드에 대하여 hostPort를 정의한 경우 다음 모범 사례를 따르십시오.

  • 필요한 경우가 아니라면 hostPort를 지정하지 마십시오. hostIP, hostPortprotocol 조합은 고유해야 합니다.
  • hostPort를 지정하는 경우 작업자 노드와 동일한 수의 포드를 예약합니다.

참조: Pod를 hostPort에 바인딩할 때 Pod를 예약할 수 있는 위치의 개수가 제한되어 있습니다.

다음 예시에서는 Pending(보류 중) 상태인 frontend-port-77f67cff67-2bv7w에 대한 describe 명령의 출력을 보여 줍니다. 요청된 호스트 포트가 클러스터의 작업자 노드에서 사용할 수 없기 때문에 포드가 예약되지 않았습니다.

포트를 사용할 수 없음

$ kubectl describe pod frontend-port-77f67cff67-2bv7w                                            
Name:           frontend-port-77f67cff67-2bv7w
Namespace:      default
Priority:       0
Node:           <none>
Labels:         app=frontend-port
                pod-template-hash=77f67cff67
Annotations:    kubernetes.io/psp: eks.privileged
Status:         Pending
IP:             
IPs:            <none>
Controlled By:  ReplicaSet/frontend-port-77f67cff67
Containers:
  app:
    Image:      nginx
    Port:       80/TCP
    Host Port:  80/TCP
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  11s (x7 over 6m22s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.

노드에 포드가 허용할 수 없는 테인트가 있어 포드를 예약할 수 없는 경우, 예제 출력은 다음과 유사하다.

$ kubectl describe pod nginx                                                  
Name:         nginx
Namespace:    default
Priority:     0
Node:         <none>
Labels:       run=nginx
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Pending
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  8s (x10 over 9m22s)  default-scheduler  0/3 nodes are available: 3 node(s) had taint {key1: value1}, that the pod didn't tolerate.

다음 명령을 사용하여 노드 테인트를 확인할 수 있습니다.

$ kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints             
NAME                                                TAINTS
ip-192-168-4-78.ap-southeast-2.compute.internal     [map[effect:NoSchedule key:key1 value:value1]]
ip-192-168-56-162.ap-southeast-2.compute.internal   [map[effect:NoSchedule key:key1 value:value1]]
ip-192-168-91-249.ap-southeast-2.compute.internal   [map[effect:NoSchedule key:key1 value:value1]]

노드 테인트를 유지하려면PodSpec에서 파드에 대한 톨러레이션을 지정할 수 있다. 자세한 내용은 개념 섹션을 쿠버네티스 문서에서 참조하세요.

또는

테인트 값 끝에 **-**를 추가하여 노드 테인트를 제거합니다.

$ kubectl taint nodes NODE_Name key1=value1:NoSchedule-

이전 단계를 시도한 후에도 여전히 포드가 보류 중(Pending) 상태인 경우 추가 문제 해결 섹션의 단계를 완료합니다.

컨테이너가 대기 상태입니다.

[대기 중] 상태의 포드는 작업자 노드(예: Amazon EC2 인스턴스)에서 예약되지만 이 노드에서 실행할 수는 없습니다.

잘못된 Docker 이미지 또는 잘못된 리포지토리 이름으로 인해 포드가 [대기 중] 상태일 수 있습니다. 이미지가 없거나 권한이 부족하여 포드가 [대기 중] 상태일 수도 있습니다.

잘못된 도커 이미지 또는 리포지토리 이름이 있는 경우 다음을 완료하세요.

1.    Docker Hub, Amazon Elastic Container Registry(Amazon ECR) 또는 다른 컨테이너 이미지 리포지토리에 로그인하여 이미지와 리포지토리 이름이 올바른지 확인합니다.

2.    리포지토리 또는 리포지토리의 이미지를 Pod 사양에 지정된 리포지토리 또는 이미지 이름과 비교합니다.

이미지가 없거나 권한이 없는 경우 다음을 완료하십시오.

1.    지정된 이미지를 리포지토리에서 사용할 수 있는지, 이미지를 가져올 수 있도록 올바른 권한이 구성되어 있는지 확인합니다.

2.    이미지를 가져올 수 있는지 확인하고, 일반적인 네트워킹 및 리포지토리 권한 문제를 배제하려면 이미지를 수동으로 가져옵니다. Docker를 사용하여 Amazon EKS 작업자 노드에서 이미지를 가져와야 합니다. 예를 들면 다음과 같습니다.

$ docker pull yourImageURI:yourImageTag

3.    이미지가 존재하는지 확인하려면 Docker Hub 또는 Amazon ECR에 이미지와 태그가 모두 있는지 확인합니다.

참고: Amazon ECR을 사용하는 경우, 리포지토리 정책이 NodeInstanceRole에 대한 이미지 가져오기를 허용하는지 확인하십시오. 또는 AmazonEC2ContainerRegistryReadOnly 역할이 정책에 연결되어 있는지 확인합니다.

다음 예제에서는 이미지 풀 오류로 인해 [대기 중] 상태인 컨테이너와 [보류 중] 상태인 포드를 보여줍니다.

$ kubectl describe po web-test

Name:               web-test
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               ip-192-168-6-51.us-east-2.compute.internal/192.168.6.51
Start Time:         Wed, 22 Jul 2021 08:18:16 +0200
Labels:             app=web-test
Annotations:        kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"app":"web-test"},"name":"web-test","namespace":"default"},"spec":{...
                    kubernetes.io/psp: eks.privileged
Status:             Pending
IP:                 192.168.1.143
Containers:
  web-test:
    Container ID:   
    Image:          somerandomnonexistentimage
    Image ID:       
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ErrImagePull
...
Events:
  Type     Reason            Age                 From                                                 Message
  ----     ------            ----                ----                                                 -------
  Normal   Scheduled         66s                 default-scheduler                                    Successfully assigned default/web-test to ip-192-168-6-51.us-east-2.compute.internal
  Normal   Pulling           14s (x3 over 65s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Pulling image "somerandomnonexistentimage"
  Warning  Failed            14s (x3 over 55s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Failed to pull image "somerandomnonexistentimage": rpc error: code = Unknown desc = Error response from daemon: pull access denied for somerandomnonexistentimage, repository does not exist or may require 'docker login'
  Warning  Failed            14s (x3 over 55s)   kubelet, ip-192-168-6-51.us-east-2.compute.internal  Error: ErrImagePull

이전 단계를 시도한 후에도 컨테이너가 여전히 [대기 중] 상태인 경우 [추가 문제 해결] 섹션의 단계를 완료합니다.

포드가 CrashLoopBackOff 상태에 있음

CrashLoopBackOff에 걸린 포드가 반복적으로 시작되고 충돌합니다.

"Back-Off restarting failed container" 출력 메시지를 수신하는 경우 Kubernetes가 컨테이너를 시작한 직후에 컨테이너가 종료되었을 수 있습니다.

현재 Pod의 로그에서 오류를 찾으려면 다음 명령을 실행합니다.

$ kubectl logs YOUR_POD_NAME

충돌한 이전 Pod의 로그에서 오류를 찾으려면 다음 명령을 실행합니다.

$ kubectl logs --previous YOUR-POD_NAME

참고: 다중 컨테이너 Pod의 경우 컨테이너 이름을 끝에 추가할 수 있습니다. 예를 들면 다음과 같습니다.

$ kubectl logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]

Liveness 프로브가 성공 상태를 반환하지 않는 경우, 애플리케이션에 대해 Liveness 프로브가 올바르게 구성되어 있는지 확인합니다. 자세한 내용은 Kubernetes 설명서에서 프로브 구성을 참조하세요.

다음 예시는 시작 후 애플리케이션이 종료되고 상태, 마지막 상태, 사유, 종료 코드 및 재시작 횟수를 이벤트와 함께 알리기 때문에 CrashLoopBackOff 상태의 포드를 보여줍니다.

$ kubectl describe pod crash-app-b9cf4587-66ftw 
Name:         crash-app-b9cf4587-66ftw
Namespace:    default
Priority:     0
Node:         ip-192-168-91-249.ap-southeast-2.compute.internal/192.168.91.249
Start Time:   Tue, 12 Oct 2021 12:24:44 +1100
Labels:       app=crash-app
              pod-template-hash=b9cf4587
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           192.168.82.93
IPs:
  IP:           192.168.82.93
Controlled By:  ReplicaSet/crash-app-b9cf4587
Containers:
  alpine:
    Container ID:   containerd://a36709d9520db92d7f6d9ee02ab80125a384fee178f003ee0b0fcfec303c2e58
    Image:          alpine
    Image ID:       docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Tue, 12 Oct 2021 12:26:21 +1100
      Finished:     Tue, 12 Oct 2021 12:26:21 +1100
    Ready:          False
    Restart Count:  4
    ...
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  2m30s                default-scheduler  Successfully assigned default/crash-app-b9cf4587-66ftw to ip-192-168-91-249.ap-southeast-2.compute.internal
  Normal   Pulled     2m25s                kubelet            Successfully pulled image "alpine" in 5.121853269s
  Normal   Pulled     2m22s                kubelet            Successfully pulled image "alpine" in 1.894443044s
  Normal   Pulled     2m3s                 kubelet            Successfully pulled image "alpine" in 1.878057673s
  Normal   Created    97s (x4 over 2m25s)  kubelet            Created container alpine
  Normal   Started    97s (x4 over 2m25s)  kubelet            Started container alpine
  Normal   Pulled     97s                  kubelet            Successfully pulled image "alpine" in 1.872870869s
  Warning  BackOff    69s (x7 over 2m21s)  kubelet            Back-off restarting failed container
  Normal   Pulling    55s (x5 over 2m30s)  kubelet            Pulling image "alpine"
  Normal   Pulled     53s                  kubelet            Successfully pulled image "alpine" in 1.858871422s

포드에 대한 Liveness 프로브 실패의 예:

$ kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0
Node:         ip-192-168-91-249.ap-southeast-2.compute.internal/192.168.91.249
Start Time:   Tue, 12 Oct 2021 13:07:55 +1100
Labels:       app=nginx
Annotations:  kubernetes.io/psp: eks.privileged
Status:       Running
IP:           192.168.79.220
IPs:
  IP:  192.168.79.220
Containers:
  nginx:
    Container ID:   containerd://950740197c425fa281c205a527a11867301b8ec7a0f2a12f5f49d8687a0ee911
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:06e4235e95299b1d6d595c5ef4c41a9b12641f6683136c18394b858967cd1506
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Tue, 12 Oct 2021 13:10:06 +1100
      Finished:     Tue, 12 Oct 2021 13:10:13 +1100
    Ready:          False
    Restart Count:  5
    Liveness:       http-get http://:8080/ delay=3s timeout=1s period=2s #success=1 #failure=3
    ...
Events:
  Type     Reason     Age                    From               Message
  ----     ------     ----                   ----               -------
  Normal   Scheduled  2m47s                  default-scheduler  Successfully assigned default/nginx to ip-192-168-91-249.ap-southeast-2.compute.internal
  Normal   Pulled     2m44s                  kubelet            Successfully pulled image "nginx" in 1.891238002s
  Normal   Pulled     2m35s                  kubelet            Successfully pulled image "nginx" in 1.878230117s
  Normal   Created    2m25s (x3 over 2m44s)  kubelet            Created container nginx
  Normal   Started    2m25s (x3 over 2m44s)  kubelet            Started container nginx
  Normal   Pulled     2m25s                  kubelet            Successfully pulled image "nginx" in 1.876232575s
  Warning  Unhealthy  2m17s (x9 over 2m41s)  kubelet            Liveness probe failed: Get "http://192.168.79.220:8080/": dial tcp 192.168.79.220:8080: connect: connection refused
  Normal   Killing    2m17s (x3 over 2m37s)  kubelet            Container nginx failed liveness probe, will be restarted
  Normal   Pulling    2m17s (x4 over 2m46s)  kubelet            Pulling image "nginx"

이전 단계를 시도한 후에도 포드가 여전히 CrashLoopBackOff 상태인 경우, 추가 문제 해결 섹션의 단계를 완료합니다.

추가 문제 해결

이전 섹션의 단계를 완료한 후에도 포드가 멈춘 상태라면 다음 단계를 수행해 보세요.

1.    작업자 노드가 클러스터에 있고 준비 완료(Ready) 상태인지 확인하려면 다음 명령을 실행합니다.

$ kubectl get nodes

출력 예시:

NAME                                          STATUS   ROLES    AGE   VERSION
ip-192-168-6-51.us-east-2.compute.internal    Ready    <none>   25d   v1.21.2-eks-5047ed
ip-192-168-86-33.us-east-2.compute.internal   Ready    <none>   25d   v1.21.2-eks-5047ed

노드가 NotReady인 경우 노드 상태를 NotReady 또는 Unknown 상태에서 Ready 상태로 변경하려면 어떻게 해야 합니까? 또는 클러스터에 조인할 수 없다면 Amazon EKS 클러스터에서 작업자 노드를 조인하려면 어떻게 해야합니까? 단원을 참조하십시오.

2.    Kubernetes 클러스터의 버전을 확인하려면 다음 명령을 실행합니다.

$ kubectl version --short

출력 예시:

Client Version: v1.21.2-eks-5047ed
Server Version: v1.21.2-eks-c0eccc

3.    Kubernetes 작업자 노드의 버전을 확인하려면 다음 명령을 실행합니다.

$ kubectl get node -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion

출력 예시:

NAME                                          VERSION
ip-192-168-6-51.us-east-2.compute.internal    v1.21.2-eks-5047ed
ip-192-168-86-33.us-east-2.compute.internal   v1.21.2-eks-5047ed

4.    클러스터의 Kubernetes 서버 버전이 허용되는 버전 스큐(Kubernetes 설명서에서 제공) 내 작업자 노드의 버전과 일치하는지 확인합니다. 앞의 2단계와 3단계의 출력을 비교하세요.

중요: 패치 버전은 다를 수 있습니다(예: 클러스터의 경우 v1.21.x, 작업자 노드의 경우 v1.21.y).

클러스터 및 작업자 노드 버전이 호환되지 않는 경우, eksctl(eksctl 탭 참조) 또는 AWS CloudFormation(자체 관리형 노드(Self-managed nodes) 탭 참조)을 사용하여 새 노드 그룹을 생성합니다.

또는

호환되는 Kubernetes 버전을 사용하여 새 관리형 노드 그룹(Kubernetes: v1.21, 플랫폼: eks.1 이상)을 생성합니다. 그런 다음 호환되지 않는 Kubernetes 버전이 있는 노드 그룹을 삭제합니다.

5.    Amazon EKS 보안 그룹 고려 사항의 권장 규칙과 방화벽 규칙을 비교하여 Kubernetes 제어 영역이 작업자 노드와 통신할 수 있는지 확인합니다. 그런 다음 노드가준비 완료(Ready) 상태인지 확인합니다.


AWS 공식
AWS 공식업데이트됨 일 년 전