7.1.2 파드 생명 주기 (Lifecycle)

파드의 생명 주기는 크게 파드 자체의 단계(Phase)와 파드 내 개별 컨테이너의 상태(Container State), 그리고 컨테이너 실패 시의 동작을 결정하는 재시작 정책(Restart Policy)으로 나누어 이해할 수 있습니다. 이 세 가지 요소는 서로 밀접하게 연관되어 파드의 전체적인 상태를 결정합니다.

7.1.2.1 Pending, Running, Succeeded, Failed, Unknown 상태 (파드 단계, Pod Phases)

파드는 생성 요청부터 소멸까지 여러 단계를 거치며, 이러한 주요 단계를 ‘파드 단계(Pod Phase)’라고 부릅니다. kubectl describe pod <pod-name> 명령을 실행하면 파드의 status.phase 필드에서 현재 단계를 확인할 수 있습니다. 파드가 가질 수 있는 주요 단계는 다음과 같습니다.

파드 생명 주기 (Lifecycle)
  • Pending (보류 중):파드가 쿠버네티스 클러스터에 의해 승인되었지만, 아직 하나 이상의 컨테이너 이미지가 생성되지 않았거나, 파드가 실행될 노드에 스케줄링되지 않은 상태를 의미합니다. 이 단계에 머무는 주요 원인은 다음과 같습니다:
    • 스케줄링 대기: 클러스터 내에 파드를 실행할 만한 충분한 자원(CPU, 메모리 등)이 있는 노드가 없거나, 노드 셀렉터(NodeSelector), 어피니티/안티-어피니티(Affinity/Anti-affinity) 규칙, 테인트/톨러레이션(Taints/Tolerations) 등의 제약 조건으로 인해 적절한 노드를 찾지 못하는 경우입니다.
    • 이미지 다운로드 중: 파드가 특정 노드에 할당되었으나, 해당 노드에서 파드 내 컨테이너가 사용할 이미지를 레지스트리로부터 다운로드하는 데 시간이 걸리는 경우입니다. 이미지 크기가 크거나 네트워크 대역폭이 낮을 때 이 단계가 길어질 수 있습니다.
    • 초기화 컨테이너(Init Container) 실행 중: 만약 파드에 초기화 컨테이너가 정의되어 있다면, 모든 초기화 컨테이너가 성공적으로 완료될 때까지 파드는 Pending 상태에 머무릅니다.
    • 볼륨 마운트 대기: 파드에 필요한 스토리지 볼륨(예: PersistentVolumeClaim)이 아직 준비되지 않았거나 마운트 중인 경우에도 Pending 상태일 수 있습니다.Pending 상태가 오래 지속된다면, kubectl describe pod  명령의 Events 섹션을 확인하여 구체적인 원인을 파악해야 합니다.
  • Running (실행 중):파드가 특정 노드에 성공적으로 바인딩(binding)되었고, 파드 내의 모든 컨테이너가 생성된 상태입니다. 또한, 적어도 하나 이상의 컨테이너가 실제로 실행 중이거나, 시작 중이거나, 또는 재시작 중인 경우 Running 상태로 간주됩니다.주의할 점은, 파드가 Running 상태라고 해서 파드 내의 모든 애플리케이션이 완벽하게 정상적으로 동작하고 있다는 의미는 아니라는 것입니다. 예를 들어, 컨테이너는 시작되었지만 애플리케이션 내부 로직에 문제가 있어 정상적인 서비스를 제공하지 못할 수도 있습니다. 이러한 애플리케이션 수준의 상태를 확인하기 위해서는 이후에 배울 준비성 프로브(Readiness Probe)와 활성 프로브(Liveness Probe)와 같은 추가적인 메커니즘이 필요합니다.일반적으로 웹 서버나 API 서버처럼 지속적으로 실행되어야 하는 애플리케이션의 파드는 이 Running 상태를 유지하는 것이 목표입니다.
  • Succeeded (성공):파드 내의 모든 컨테이너가 성공적으로 종료되었고 (종료 코드 0), 앞으로 재시작되지 않을 상태를 의미합니다. 이 단계는 주로 배치(batch) 작업이나 단일 실행 작업(예: 쿠버네티스 잡(Job) 컨트롤러에 의해 관리되는 파드)에서 볼 수 있습니다. 작업이 성공적으로 완료되면 해당 파드는 Succeeded 상태로 전환되고, 이후에는 로그나 결과 확인 등을 위해 남아있다가 사용자에 의해 또는 컨트롤러에 의해 삭제될 수 있습니다.
  • Failed (실패):파드 내의 모든 컨테이너가 종료되었으며, 그중 적어도 하나 이상의 컨테이너가 오류로 인해 실패(0이 아닌 종료 코드)한 상태를 의미합니다. Succeeded와 마찬가지로, 이 상태의 파드도 더 이상 재시작되지 않습니다.애플리케이션 내부의 버그, 잘못된 설정, 자원 부족(예: 컨테이너가 할당된 메모리 초과 사용으로 OOMKilled 되는 경우) 등 다양한 원인으로 Failed 상태가 될 수 있습니다. 이 경우, kubectl logs -c  명령으로 컨테이너 로그를 확인하여 실패 원인을 분석해야 합니다. Job 컨트롤러에 의해 관리되는 파드가 반복적으로 실패하면 Job 자체가 Failed 상태가 될 수 있습니다.
  • Unknown (알 수 없음):어떤 이유로든 파드의 상태를 확인할 수 없는 경우입니다. 이는 주로 파드가 할당된 노드와의 통신에 문제가 생겼을 때 발생합니다. 예를 들어, 노드가 갑자기 다운되거나 네트워크 연결이 끊어져 컨트롤 플레인(API 서버, 컨트롤러 매니저 등)이 해당 노드의 Kubelet으로부터 파드 상태를 보고받지 못하는 경우입니다. 쿠버네티스 컨트롤러는 이런 상황을 감지하고, 일정 시간 후 해당 노드를 NotReady 상태로 변경하며, 필요에 따라 해당 노드의 파드들을 다른 정상적인 노드로 재스케줄링하려고 시도할 수 있습니다 (물론, 이는 파드를 관리하는 상위 컨트롤러의 정책에 따라 달라집니다).

이러한 파드의 단계는 쿠버네티스가 클러스터의 워크로드를 어떻게 인식하고 관리하는지에 대한 상위 수준의 그림을 제공합니다.

7.1.2.2 컨테이너 상태 (Waiting, Running, Terminated)

파드의 단계(Phase)는 파드 내 개별 컨테이너들의 상태를 종합하여 결정됩니다. 즉, 파드의 상태를 더 깊이 이해하기 위해서는 그 안에 있는 각 컨테이너의 상태(Container State)를 살펴보는 것이 중요합니다. kubectl describe pod <pod-name> 명령을 실행하면 status.containerStatuses 필드에서 각 컨테이너의 현재 상태 및 이전 상태(존재하는 경우)를 확인할 수 있습니다. 컨테이너는 다음 세 가지 주요 상태 중 하나를 가집니다.

  • Waiting (대기 중):컨테이너가 아직 Running 또는 Terminated 상태가 아닌 경우입니다. 즉, 컨테이너가 실행을 시작하기 위해 필요한 작업들을 수행하고 있는 상태입니다. Waiting 상태일 때는 reason 필드를 통해 구체적인 대기 원인을 알 수 있으며, 일반적인 원인들은 다음과 같습니다:
    • ContainerCreating: 컨테이너 런타임(예: containerd, CRI-O)이 컨테이너를 생성하고 있는 중입니다. 이 과정에는 네트워크 설정, 볼륨 마운트 등이 포함될 수 있습니다.
    • ImagePulling / ImagePullBackOff / ErrImagePull: 컨테이너 이미지를 레지스트리에서 가져오고 있는 중이거나, 이미지 가져오기에 실패하여 재시도 중이거나, 또는 이미지 가져오기에 실패한 상태입니다. 이미지 이름이 잘못되었거나, 레지스트리 접근 권한이 없거나, 네트워크 문제 등이 원인일 수 있습니다. ImagePullBackOff는 반복적인 실패로 인해 다음 시도까지 지연 시간이 점점 늘어나는 상태를 의미합니다.
    • CrashLoopBackOff: 컨테이너가 시작된 직후 비정상적으로 종료되고, 쿠버네티스가 이를 재시작하려고 하지만 계속해서 반복적으로 실패하는 상태입니다. 애플리케이션 코드의 버그, 설정 오류, 자원 부족(예: 시작 시 너무 많은 메모리 요구) 등이 원인일 수 있습니다. 이 경우 컨테이너 로그를 반드시 확인해야 합니다.
    • 초기화 컨테이너(Init Container)가 아직 완료되지 않았을 때, 주 애플리케이션 컨테이너들은 이 Waiting 상태에 머무를 수 있습니다.
  • Running (실행 중):컨테이너가 성공적으로 시작되어 현재 실행 중인 상태를 의미합니다. 이 상태는 컨테이너 내의 주 프로세스가 정상적으로 시작되었음을 나타냅니다. 컨테이너가 Running 상태가 되면 쿠버네티스는 정의된 경우 Liveness Probe와 Readiness Probe를 시작하여 애플리케이션의 실제 건강 상태와 서비스 준비 상태를 주기적으로 점검합니다. (프로브에 대해서는 이후 장에서 자세히 다룹니다.)
  • Terminated (종료됨):컨테이너가 실행을 시작했다가 어떤 이유로든 실행을 멈추고 종료된 상태입니다. Terminated 상태의 컨테이너는 다음과 같은 중요한 정보를 제공합니다:
    • reason: 종료된 이유를 간략하게 설명합니다. 일반적인 reason 값으로는 Completed (정상 종료), Error (오류로 인한 종료), OOMKilled (메모리 부족으로 커널에 의해 강제 종료), DeadlineExceeded (파드의 activeDeadlineSeconds 초과) 등이 있습니다.
    • exitCode: 컨테이너 내의 주 프로세스가 종료될 때 반환한 종료 코드입니다. 일반적으로 0은 성공적인 종료를, 0이 아닌 값은 오류를 의미합니다.
    • startedAt 및 finishedAt: 컨테이너가 시작된 시간과 종료된 시간 정보입니다.
    • message: 컨테이너 종료에 대한 좀 더 상세한 메시지가 있을 수 있습니다.

파드 내의 모든 컨테이너 상태가 Terminated이고, 모두 exitCode 0으로 종료되었다면 파드 단계는 Succeeded가 됩니다. 만약 하나라도 exitCode가 0이 아닌 컨테이너가 있다면 파드 단계는 Failed가 될 가능성이 높습니다 (재시작 정책에 따라 달라질 수 있음).

7.1.2.3 재시작 정책 (Restart Policy)

파드 내의 컨테이너가 예기치 않게 종료되었을 때, 쿠버네티스가 해당 컨테이너를 어떻게 처리할지를 결정하는 것이 바로 ‘재시작 정책(Restart Policy)’입니다. 이 정책은 파드 명세(PodSpec)의 spec.restartPolicy 필드에 정의되며, 파드 내의 모든 컨테이너에 동일하게 적용됩니다. 재시작 정책은 다음 세 가지 값 중 하나를 가질 수 있습니다.

  • Always (항상 재시작, 기본값):컨테이너가 어떤 이유로든 (성공적으로 종료되든, 오류로 종료되든) 종료되면 쿠버네티스는 항상 해당 컨테이너를 재시작하려고 시도합니다. 이 정책은 웹 서버, API 서버, 데이터베이스와 같이 지속적으로 실행되어야 하는 서비스형 애플리케이션에 적합합니다. 디플로이먼트(Deployment), 레플리카셋(ReplicaSet), 스테이트풀셋(StatefulSet)과 같은 컨트롤러에 의해 관리되는 파드의 기본 재시작 정책은 보통 Always입니다. 컨테이너가 반복적으로 빠르게 실패하는 경우(예: CrashLoopBackOff), 쿠버네티스는 재시작 시도 간의 지연 시간을 점진적으로 늘려 시스템에 과도한 부하를 주는 것을 방지합니다.
  • OnFailure (실패 시에만 재시작):컨테이너가 오류로 인해 종료된 경우(0이 아닌 종료 코드)에만 재시작을 시도합니다. 컨테이너가 성공적으로 작업을 완료하고 종료 코드 0으로 종료된 경우에는 재시작하지 않습니다. 이 정책은 특정 작업을 수행하고 완료되면 종료되는 배치(batch) 작업이나 스크립트 실행 등에 유용합니다. 예를 들어, 쿠버네티스 잡(Job) 컨트롤러는 기본적으로 파드에 OnFailure 재시작 정책을 적용하여, 작업이 일시적인 오류로 실패했을 경우 재시도하고 성공하면 더 이상 재시작하지 않도록 합니다.
  • Never (재시작 안 함):컨테이너가 종료되면, 성공 여부와 관계없이 쿠버네티스는 해당 컨테이너를 절대로 재시작하지 않습니다. 이 경우, 컨테이너가 종료되면 파드는 해당 컨테이너의 최종 상태(예: Succeeded 또는 Failed)를 반영하게 됩니다. 이 정책은 단 한 번만 실행되어야 하는 작업이나, 외부 시스템에서 재시도 로직을 관리하는 경우, 또는 디버깅 목적으로 컨테이너의 최종 상태를 정확히 확인하고 싶을 때 사용될 수 있습니다. 쿠버네티스 잡(Job)의 경우, spec.backoffLimit (재시도 횟수 제한)을 초과하여 잡이 실패 처리되면, 관련된 파드들은 더 이상 OnFailure 정책에 따라 재시작되지 않고 최종적으로 Failed 상태를 유지하게 됩니다.

중요한 점은, 재시작 정책은 파드가 실행 중인 동일한 노드 내에서의 컨테이너 재시작에만 관여한다는 것입니다. 만약 노드 자체가 실패하거나 파드가 어떤 이유로든 노드에서 삭제된다면, 재시작 정책이 아니라 파드를 관리하는 상위 컨트롤러(예: 디플로이먼트, 스테이트풀셋)가 새로운 파드를 다른 노드에 생성하는 역할을 담당합니다.

이처럼 파드의 단계, 컨테이너의 상태, 그리고 재시작 정책은 서로 긴밀하게 상호작용하며 파드의 전체적인 생명 주기를 형성합니다. 이러한 개념들을 잘 이해하고 kubectl 명령을 통해 실제 파드의 상태 변화를 관찰하는 연습을 한다면, 여러분은 쿠버네티스 환경에서 애플리케이션을 보다 효과적으로 관리하고 문제를 해결하는 능력을 갖추게 될 것입니다. 다음으로는 이러한 파드를 실제로 어떻게 설계하고 활용할 수 있는지 다양한 패턴에 대해 알아보겠습니다.