본문 바로가기

K8S

쿠버네티스(Kubernetes) 중단 (Disruption)

728x90

■ 쿠버네티스(Kubernetes) 중단 (Disruption)

  • Pod는 일반적 상황에서는 중단되지 않음. 하지만 관리자 또는 컨트롤러의 명령으로 인한 제거 (자발적 중단) 또는 Pod가 동작하는 하드웨어적인 오류로 인한 Pod 중단(비자발적 중단)이 발생 할 수 있음. 

 

 쿠버네티스(Kubernetes) 중단 (Disruption) 종류

  • 비자발적 중단
    • 노드를 지원하는 물리 머신의 하드웨어 오류
    • 클러스터 관리자의 실수로 VM(인스턴스) 삭제
    • 클라우드 공급자 또는 하이퍼바이저의 오류로 인한 VM 장애
    • 커널 패닉
    • 클러스터 네트워크 파티션의 발생으로 클러스터에서 노드가 사라짐
    • 노드의 리소스 부족으로 파드가 축출됨
    • 비자발적 중단은 Pod Disruption Budget(PDB)로 막을 수는 없지만 Budget은 차감 됨
  • 자발적 중단 (애플리케이션 소유자 작업)
    • 디플로이먼트 제거 또는 다른 파드를 관리하는 컨트롤러의 제거
    • 재시작을 유발하는 디플로이먼트의 파드 템플릿 업데이트
    • 파드를 직접 삭제
  • 자발적 중단 (클러스터 소유자 작업)
    • 복구 또는 업그레이드를 위한 노드 드레이닝 (노드 제거)
    • 클러스터의 스케일 축소를 위한 노드 드레이닝
    • 노드에 다른 무언가를 추가하기 위해 파드를 제거
    • 해당 작업은 관리자의 직접 수행, 자동화를 통한 수행 또는 클러스터 호스팅 공급자에 의해서도 수행 될 수 있음

 

 쿠버네티스(Kubernetes) Pod Disruption Budget

  • Pod의 자발적 중단이 빈번하게 발생하는 경우 Pod Discruption Budget(PDB)를 설정하여, 애플리케이션이 고가용성을 보장할 수 있도록 하는 기능이다. 
  • Pod Discruption Budget(PDB) 는 자발적 중단으로 일시에 중지되는 복제된 애플리케이션 Pod의 수를 제한하는 방식으로 고가용성을 보장함. 단, 노드의 리소스가 부족하여 kubelet이 노드의 자원을 회수하는 경우 PDB를 고려하지 않는다. 
  • 쿠버네티스에서는 관리자가 직접적으로 Pod 또는 디플로이먼트를 삭제하는 대신 Pod Discruption Budget(PDB) 를 준수하는 "Eviction API"를 사용을 권장 한다.
    • 사용자가 "kubectl drain <node-name>" 명령어를 사용하게 되면 컨트롤러는 해당 노드의 모든 Pod를 축출하게 되며, 작업 과정에서 Pod 축출이 실패하게 될 경우 모든 Pod가 축출되거나 설정한 Timeout 시간이 될 때 까지 모든 실패된 요청을 다시 시도 하게 된다. 
    • "kubectl drain <node-name> --disable-eviction" 옵션을 사용하게 되면 PDB를 무시하게 되어 애플리케이션 가용성에 문제가 생길 수 있어, 해당 옵션의 사용은 신중히 사용해야 한다.
    • "kubectl drain <node-name> --pod-selector="key=value" 옵션을 사용하게 되면 Pod의 Label값을 이용하여 중단할 Pod를 필터링하여 중단 할 수 있다.
  • Eviction API을 사용할 경우 API 서버가 " Eviction " 객체를 생성하여 Pod를 graceful shutdown 시킨다. API를 사용하게 되면 PodDiscruptionBudget과 terminationGracePeriodSeconds 를 준수하여 Pod를 종료 시킨다. 
    • # nginxTest1-eviction.json 생성
      {
        "apiVersion": "policy/v1",
        "kind": "Eviction",
        "metadata": {
          "name": "nginxTest1",
          "namespace": "evpicapi"
        }
      }
      
      # API 서버에 요청 
      curl -v -H 'Content-type: application/json' https://<API_SERVER>/api/v1/namespaces/evpicapi/pods/nginxTest1/eviction \
       -d @nginxTest1-eviction.json
       
       ---------------------------
      # 파이썬을 사용하여 다수의 Pod 삭제 
      import requests
      import json
      
      # 쿠버네티스 API 서버 엔드포인트
      api_server = "https://<API_SERVER>"
      
      # Eviction 요청을 위한 헤더
      headers = {
          'Content-type': 'application/json',
          'Authorization': 'Bearer <YOUR_ACCESS_TOKEN>'
          # cat /var/run/secrets/kubernetes.io/serviceaccount/token 토큰 확인
      }
      
      # 제거할 파드 목록
      pods = ["nginxTest1", "nginxTest2", "nginxTest3", "nginxTest4"]
      namespace = "evpicapi"
      
      for pod in pods:
          eviction = {
              "apiVersion": "policy/v1",
              "kind": "Eviction",
              "metadata": {
                  "name": pod,
                  "namespace": namespace
              }
          }
      
          url = f"{api_server}/api/v1/namespaces/{namespace}/pods/{pod}/eviction"
          response = requests.post(url, headers=headers, data=json.dumps(eviction))
      
          if response.status_code == 200:
              print(f"Successfully evicted {pod}")
          else:
              print(f"Failed to evict {pod}: {response.status_code} - {response.text}")
    • HTTP 200 OK: 정상적으로 요청을 받아서 Pod가 삭제 됨
    • HTTP 429 Too Many Requests: PDB 설정으로 인해 Pod 삭제 요청이 허용 되지 않음.
    • HTTP 500 Internal Server Error: 잘못된 설정(misconfiguration)으로 인해 추축 명령이 허용되지 않음. 

 쿠버네티스(Kubernetes) Pod Disruption Budget 예시

  • 전제 조건
    • 가용 노드: 3개
    • 수용 가능 Pod: 노드 당 2개의 Pod만 수용 가능 
    • 가용 Pod: 3개 (레플리카 설정)+ 1 (별도)
    • Pod Disruption Budget: 2개
node-1 node-2 node-3
pod-a ( available ) pod-b ( available ) pod-c ( available )
pod-x ( available )    
  • kubectl drain node-1 명령을 통해 해당 node의 pod 축출 수행. 명령 즉시 kubectl 은 node-1에 있는 pod-a, pod-x 중지 시켜 terminating 상태로 전환 
node-1 (draining) node-2 node-3
pod-a (terminating) pod-b ( available ) pod-c ( available )
pod-x (terminating)    
  • Pod replica를 관리하는 디플로이먼트가 Pod가 중지된것을 확인 하고, 다른 노드에 Pod 생성. pod-a 다른 노드에 생성 되고 pod-x 역시 관리 주체에 의해 다른 노드에 생성 됨.
node-1 (drained) node-2 node-3
  pod-b ( available ) pod-c ( available )
  pod-d (starting) pod-y ( available )
  • pod-d가 완전한 가용 상태가 아닌 순간에 다시 drain 명령을 수행 하게 되면, PDB에 의해 drain 작업이 취소 됨. 현재  설정 된 PDB는 2개 이고, 가용 pod는 b, c 2개이기 때문이다. 
node-1  (drained) node-2 node-3
  pod-b ( available ) pod-c ( available )
  pod-d ( available ) pod-y
  • 해당 상태에서 다시 node-2를 비우기 위해 drain 명령을 수행하게 되면 pod-b / pod-d 중 하나를 축출하게 된다. 만약, pod-b가 축출 된 이후 pod-d를 축출 하려고 하면 디플로이먼트 설정에 의해 해당 명령은 거부 된다. 
  • 디플로이먼트에 의해 새로운 pod-e가 생성되고, 해당 pod를 스케줄하기 위한 충분한 리소스가 없기 때문에 축출 명령은 차단 되고 클러스터는 아래 상태로 종료 되게 된다. 해당 시점에서 노드를 추가하여 정상적으로 pod가 배포 된다.
node-1  (drained) node-2 node-3 no node
  pod-b ( available ) pod-c ( available ) pod-e (pending)
  pod-d ( available ) pod-y  

 

728x90