Pod Lifecycle & Container Lifecycle

Jaeminst·2022년 4월 26일
0
post-thumbnail

Pod Lifecycle

Pod는 정의된 수명 주기를 따르며 Pending 단계에서 시작하여 기본 컨테이너 중 하나 이상이 정상적으로 시작되면 Running을 거쳐 Pod의 컨테이너가 실패로 종료되었는지 여부에 따라 Succeeded 또는 Failed 단계를 거칩니다.

Pod가 실행되는 동안 kubelet은 일종의 오류를 처리하기 위해 컨테이너를 다시 시작할 수 있습니다. Pod 내에서 Kubernetes는 다양한 컨테이너 상태를 추적하고 Pod를 다시 정상 상태로 만들기 위해 취해야 할 조치를 결정합니다.

Kubernetes API에서 Pod에는 사양과 실제 상태가 모두 있습니다.
Pod object consists를 위한 status는 Pod conditions로 설정됩니다.
애플리케이션에 유용한 경우 사용자 지정 준비 정보를 Pod의 조건 데이터에 삽입할 수도 있습니다.

Pods은 오직 한 번의 lifetime을 스케줄링 합니다.
Pod가 노드에 scheduled(할당)되면, Pod는 중지되거나 종료될 때까지 해당 노드에서 실행됩니다.

scheduling-eviction
Kubernetes에서 스케줄링은 kubelet이 실행할 수 있도록 Pods가 Nodes와 일치하는지 확인하는 것을 의미합니다.
Preemption(선점)은 우선 순위가 더 높은 Pod가 노드에서 예약할 수 있도록 우선 순위가 낮은 Pod를 종료하는 프로세스입니다.
Eviction(축출)은 노드에서 하나 이상의 파드를 종료하는 프로세스입니다.

Pod lifetime

개별 애플리케이션 컨테이너와 마찬가지로 Pod는 상대적으로 일시적인 개체로 간주됩니다.
Pod가 생성되고 고유 ID(UID)가 할당되고 노드가 종료(재시작 정책에 따라) 또는 삭제될 때까지 남아 있는 노드에 예약됩니다.
노드가 죽으면 해당 노드에 예약된 Pod는 시간 초과 기간 후에 삭제되도록 예약됩니다.

Pods는 자체적으로 자가 치유되지 않습니다.
Pod가 node에 예약된 후 실패하면 Pod가 삭제됩니다.
마찬가지로 Pod는 리소스 부족이나 노드 유지 관리로 인해 퇴거에서 살아남지 못합니다.
Kubernetes는 상대적으로 일회용인 Pod 인스턴스를 관리하는 작업을 처리하는 컨트롤러라고 하는 더 높은 수준의 추상화를 사용합니다.

주어진 Pod(UID로 정의)는 절대 다른 node로 "rescheduled"되지 않습니다.
대신에 해당 Pod는 거의 동일한 새 Pod로 교체할 수 있습니다.
원하는 경우 동일한 "name"을 사용하지만 다른 "UID"를 사용합니다.

볼륨과 같이 Pod와 수명이 같다고 하면 특정 Pod(정확한 UID 포함)가 존재하는 한 해당 사물이 존재한다는 의미입니다. 어떤 이유로든 해당 Pod가 삭제되고 동일한 교체가 생성되더라도 관련 항목(아래 예에서는 볼륨)도 삭제되고 새로 생성됩니다.

  • 그림: Pod diagram
    다음을 포함하는 다중 컨테이너 Pod
    파일 풀러 및 컨테이너 간의 공유 저장소에 영구 볼륨을 사용하는 웹 서버.

Pod phase

Pod의 status 필드는 phase 필드가 있는 PodStatus 객체이다.

Pod의 단계는 Pod가 수명 주기에서 어디에 있는지에 대한 간단하고 높은 수준의 요약입니다. 이 단계는 컨테이너 또는 Pod 상태에 대한 관찰의 포괄적인 롤업을 의도하지 않았으며 포괄적인 상태 시스템을 의도하지도 않았습니다.

노드가 죽거나 클러스터의 나머지 부분에서 연결이 끊어지면 Kubernetes는 손실된 노드의 모든 Pod 단계를 실패로 설정하는 정책을 적용합니다.

phase

ValueDescription
Pending

Kubernetes 클러스터에서 포드를 수락했지만 하나 이상의 컨테이너가 설정되어 실행할
준비가 되지 않았습니다.
여기에는 Pod가 예약을 기다리는 데 소비한 시간과 네트워크를 통해 컨테이너 이미지를
다운로드하는 데 소비한 시간이 포함됩니다.

Running

Pod가 노드에 바인딩되었으며 모든 컨테이너가 생성되었습니다.
하나 이상의 컨테이너가 아직 실행 중이거나 시작 또는 다시 시작하는 중입니다.

SucceededPod의 모든 컨테이너가 성공적으로 종료되었으며 다시 시작되지 않습니다.
Failed

Pod의 모든 컨테이너가 종료되었으며 하나 이상의 컨테이너가 실패로 종료되었습니다.
즉, 컨테이너가 0이 아닌 상태로 종료되었거나 시스템에 의해 종료되었습니다.

Unknown상태를 연결할 수 없는 상태로 2015년 이후 이 값은 사용되지 않습니다.

Pod conditions

Pod는 PodConditions의 배열을 통해서 PodStatus를 확인합니다.

  • PodScheduled
    Pod가 노드에 예약되었습니다.

  • ContainersReady
    Pod의 모든 컨테이너가 준비되었습니다.

  • Initialized
    모든 초기화 컨테이너가 성공적으로 완료되었습니다.

  • Ready
    Pod는 요청을 처리할 수 있습니다.
    그리고, 모든 일치하는 서비스의 load balancing pools에 추가할 수 있습니다.

# Maybe, I think so podConditions as Code
  - type: podConditions
    status: ture | false | unknown
    lastProbeTime: 60 # ( Timestamp of last probed )
    lastTransitionTime: 5 # ( Timestamp of transitioned status )
    reason: Machine-readable (조건의 마지막 전환 이유)
    message: Human-readable (마지막 상태 전환에 대한 세부 정보)

Container Lifecycle

kubelet managed Containers
can use the Container lifecycle hook framework to
run code triggered by events during their management lifecycle.

Container states

쿠버네티스는 파드 전체의 단계뿐만 아니라 파드 내부의 각 컨테이너의 상태를 추적한다. 컨테이너 수명 주기 후크를 사용하여 이벤트를 트리거하여 컨테이너 수명 주기의 특정 지점에서 실행할 수 있습니다.

Container restart policy

Pod의 spec에는 'Always', 'OnFailure' 및 'Never' 값이 가능한 restartPolicy 필드가 있습니다. 기본값은 'Always'입니다.

restartPolicy는 Pod의 모든 컨테이너에 적용됩니다.
restartPolicy는 동일한 노드에서 kubelet이 컨테이너를 다시 시작하는 것만 참조합니다.
Pod 종료의 컨테이너 후 kubelet은 기하급수적인 백오프 지연(10초, 20초, 40초, …)으로 컨테이너를 다시 시작하며 최대 5분입니다.
컨테이너가 문제 없이 10분 동안 실행되면 kubelet은 해당 컨테이너에 대한 restart backoff timer를 재설정합니다.

Container Lifecycle Hooks

Angular와 같이 구성 요소 lifecycle hooks가 있는 많은 프로그래밍 언어 프레임워크와 유사하게 Kubernetes는 컨테이너에 lifecycle hooks를 제공합니다. hooks를 사용하면 컨테이너가 관리 lifecycle의 이벤트를 인식하고 해당 lifecycle hooks가 실행될 때 handler에 구현된 코드를 실행할 수 있습니다.

Container hooks

컨테이너에 노출되는 두 개의 hooks가 있습니다.

  • PostStart (시작 게시)
    이 hooks는 컨테이너가 생성된 직후에 실행됩니다.
    그러나 hooks가 컨테이너 ENTRYPOINT(진입 지점)보다 먼저 실행된다는 보장은 없습니다.
    handler에 parameters가 전달되지 않습니다.

  • PreStop (사전 정지)
    이 hooks는 API 요청 또는 활성/시작 프로브 실패, 선점, 리소스 경합 등의 관리 이벤트로 인해 컨테이너가 종료되기 직전에 호출됩니다.
    컨테이너가 이미 종료되거나 완료된 상태에 있고 컨테이너를 중지하라는 TERM signal이 전송되기 전에 hooks가 완료되어야 하는 경우 PreStop hooks에 대한 호출이 실패합니다.
    파드의 종료 유예 기간 카운트다운은 PreStop hooks가 실행되기 전에 시작되므로 handler의 결과에 관계없이 컨테이너는 파드의 terminationGracePeriod(종료 유예 기간) 내에 결국 종료됩니다.
    handler에 parameters가 전달되지 않습니다.

Hook handler 구현

컨테이너는 해당 hooks에 대한 처리기를 구현하고 등록하여 hooks에 액세스할 수 있습니다.
컨테이너에 대해 구현할 수 있는 두 가지 유형의 hooks handler가 있습니다.

  • Exec
    컨테이너의 cgroup 및 네임스페이스 내에서 pre-stop.sh와 같은 특정 명령을 실행합니다.

  • HTTP
    컨테이너의 특정 끝점에 대해 HTTP 요청을 실행합니다.

프로브를 사용한 컨테이너 확인 메커니즘과 컨테이너 라이프사이클 훅은 다른 개념입니다.
확인 메커니즘 : exec, grpc, httpGet, tcpSocket
라이프사이클 훅: PostStart, PreStop

Hook handler 실행

  1. Container lifecycle management hook이 호출
  2. Kubernetes 관리 시스템은 hook action에 따라 handler가 실행되는데.
  3. 컨테이너 확인 메커니즘의 탐침수행이 kubelet 프로세스에 의해 실행
  4. 컨테이너 내에서는 exec 또는 HTTP response function 같은 hooks handler가 실행된다.

사용자는 후크 핸들러를 가능한 한 가볍게 만들어야 합니다. 그러나 컨테이너를 중지하기 전에 상태를 저장하는 경우와 같이 장기 실행 명령이 의미가 있는 경우가 있습니다.

hooks handler 호출은 컨테이너를 포함하는 파드의 컨텍스트 내에서 동기적입니다.
그러나, PostStart hook은 컨테이너 진입지점과 비동기적입니다.
그래서 hooks가 실행되는 데 너무 오래 걸리거나 중단되면 컨테이너가 실행 중인 상태에 도달할 수 없습니다.

실행 중에 PreStop hooks가 중단되면 Pod의 단계는 Terminating이 되며 해당 종료 유예 기간이 만료된 후 Pod가 종료될 때까지 유지됩니다.
이 유예 기간은 PreStop hooks가 실행되고 컨테이너가 정상적으로 중지되는 데 걸리는 총 시간에 적용됩니다.
예를 들어, terminationGracePeriodSeconds: 60
hooks가 완료되는 데 55초가 걸리고 Container가 신호를 수신한 후 정상적으로 중지하는 데 10초가 걸리는 경우, 종료 유예기간이 이 두 가지 일이 일어나는 데 걸리는 총 시간(55+10)보다 적습니다.

Debugging Hook handlers

PostStart 또는 PreStop 후크가 실패하면 컨테이너가 종료됩니다.
PreStop hooks는 컨테이너를 중지하라는 신호에서 비동기적으로 실행되지 않습니다.
따라서, TERM 신호를 보내기 전에 실행을 완료해야 합니다.

Example

# lifecycle-events.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
$ kubectl describe pod lifecycle-demo
Events:
  Type     Reason               Age              From               Message
  ----     ------               ----             ----               -------
  Normal   Scheduled            7s               default-scheduler  Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2...
  Normal   Pulled               6s               kubelet            Successfully pulled image "nginx" in 229.604315ms
  Normal   Pulling              4s (x2 over 6s)  kubelet            Pulling image "nginx"
  Normal   Created              4s (x2 over 5s)  kubelet            Created container lifecycle-demo-container
  Normal   Started              4s (x2 over 5s)  kubelet            Started container lifecycle-demo-container
  Warning  FailedPostStartHook  4s (x2 over 5s)  kubelet            Exec lifecycle hook ([badcommand]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(30229739-9651-4e5a-9a32-a8f1688862db)" failed - error: command 'badcommand' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: \"badcommand\": executable file not found in $PATH: unknown\r\n"
  Normal   Killing              4s (x2 over 5s)  kubelet            FailedPostStartHook
  Normal   Pulled               4s               kubelet            Successfully pulled image "nginx" in 215.66395ms
  Warning  BackOff              2s (x2 over 3s)  kubelet            Back-off restarting failed container

실패한 FailedPreStopHook 이벤트를 직접 생성하려면, 위 예제를 수정하여 postStart 명령을 "badcommand"로 변경하고 적용합니다.

profile
DevOps !

0개의 댓글