시작하기 전에

쿠버네티스는 워커 노드의 장애가 발생하더라도 정상적 혹은 부분적으로 기능을 수행할 수 있도록 결함 감내(fault tolerant) 시스템으로 디자인되어 있습니다. 쿠버네티스의 마스터 노드는 가상 머신과 같은 인프라의 상태를 주기적으로 워커 노드로 부터 수신하며, 어떠한 이유로 인해 문제가 발생한 경우에는 이를 복구하도록 동작합니다. 그러나 모든 경우의 문제를 해결하는데는 한계가 있으며, 노드의 유지보수를 위해 개발자가 특정 워커 노드 상에 운영중이던 파드(pod)의 우아한 종료(gracefully shutting down)를 위한 개입이 필요할 수 있습니다. 이 문서에서는 쿠버네티스 클러스터의 Ready 상태인 노드 수를 서버 반납이나 유지보수를 위한 중단 등으로 의도적으로 축소시키고자 할때, 축소 대상의 노드에서 구동중인 어플리케이션을 다른 노드로 배출(drain)시키는 과정을 다룹니다.

쿠버네티스에 대한 오해

쿠버네티스에 대한 흔한 오해
충분한 자원이 있다면 쿠버네티스는 문제가 있는 노드의 모든 파드(Pod)들을 다른 노드로 재스케줄링할 것이므로, 워커 노드에 발생할 수 있는 문제에 대해 걱정할 필요가 없다. 또한 필요시 Cluster Autoscaler가 새로운 워커 노드를 추가할 것이므로, 애플리케이션 및 클러스터에 대한 운영은 문제 없이 지속될 수 있다.

위에 기술된 내용은 쿠버네티스를 운영하는데 있어 가질수 있는 흔한 오해 중 하나입니다. 쿠버네티스 마스터 노드의 kube-controller-manager는 특정 워커 노드의 컨디션에 문제를 감지하였더라도, 파드(pod) 축출(eviction) 조건이 충족된 경우에 재스케줄링을 수행합니다. 동작 중인 워커 노드를 강제로 재시작하는 경우에는 앞서 언급한 조건이 충족되지 않는 경우, 일정시간 동안 해당 워커 노드에 스케줄된 파드의 정지(downtime)를 유발하게 됩니다. 특정 워커 노드의 재부팅전 kubectl drain의 명령어를 통해 구동중이던 파드(pod)를 다른 워커 노드로 축출(eviction)하는 우아한 종료(gracefully shutting down pods) 과정을 통해 안정적으로 서비스를 운영할 수 있습니다.

워커 노드의 상태 확인

쿠버네티스의 마스터 노드는 주기적으로 인프라의 상태를 주기적으로 워커 노드로 부터 수신합니다. 노드의 상태와 상세 정보는 다음의 커맨드를 통해 확인할 수 있습니다. 자세한 내용은 [공식 문서]를 참고해주세요.

$ kubectl --kubeconfig=$KUBE_CONFIG describe node $NODENAME

노드의 컨디션은 JSON 오브젝트로 반환됩니다. 다음은, 정상 상태의 노드의 컨디션을 나타내는 응답 예제입니다.

"conditions": [
  {
    "type": "Ready",
    "status": "True",
    "reason": "KubeletReady",
    "message": "kubelet is posting ready status",
    "lastHeartbeatTime": "2019-06-05T18:38:35Z",
    "lastTransitionTime": "2019-06-05T11:41:27Z"
  }
]

노드의 컨디션 중 Ready 타입의 상태가 마스터 노드의 kube-controller-manager에 인수로 넘겨지는 pod-eviction-timeout보다 더 길게 Unknown 또는 False로 유지되는 경우, 노드 상에 모든 파드(Pod)들은 노드 컨트롤러에 의해 삭제되도록 스케줄됩니다. 네이버 클라우드 플랫폼의 쿠버네티스 서비스에서는 pod-eviction-timeout을 5분을 설정값으로 사용합니다.

kubectl drain 명령을 사용하여 워커 노드에서 파드 축출

노드에 대한 커널 업데이트 및 인프라의 유지 보수 등 작업의 수행전에, kubectl drain과 같은 명령어를 사용하여 해당 노드로부터 파드(pod)들을 안전하게 축출(eviction)할 수 있습니다. 안전한 축출(eviction)은 파드(pod)의 컨테이너들을 우아한 종료(gracefully terminate)하도록 합니다.

Note: kubectl drain 명령어는 노드내 제거할 수 없는 특정 시스템 파드(pod)들을 무시합니다. 자세한 사항은 [kubectl drain] 가이드를 참고하세요.

kubectl drain명령이 성공적으로 수행되었다면, 이는 모든 파드(pod)들이 안전하게 특정 워커 노드로 부터 축출(eviction)되었다는것을 의미합니다. 그런 다음 가상 머신을 정지, 재시작 혹은 반납하여 노드를 중단하는 것이 안전합니다.

① 파드(pod)를 축출(eviction)하고자 하는 노드를 확인합니다. 클러스터 내 모든 워커 노드를 조회하기 위해서는 다음의 명령어를 이용합니다.

$ kubectl --kubeconfig=$KUBE_CONFIG get nodes

② 조회한 노드의 이름 중에 파드(pod)를 배출(drain)할 대상의 워커 노드의 이름을 입력합니다. 이 동작은 노드에 스케줄을 할 수 없도록 표시하면서, 대상 워커 노드 상에 있는 모든 파드들을 우아하게 종료합니다.

$ kubectl --kubeconfig=$KUBE_CONFIG drain $NODENAME

위 명령어는 대상 워커 노드의 파드(pod)가 아래의 경우에 속하는 경우 동작하지 않습니다.

  • 파드(pod)들이 emptyDir을 사용하여 local data를 저장하는 경우 emptyDir를 사용하여 local data를 저장하는 파드(pod)가 해당 워커 노드에 있는 경우, 이 파드(pod)를 삭제 시 해당 데이터 또한 삭제가 되므로 수행되지 않습니다. 해당 파드(pod)가 제거되어도 문제가 없는 경우에는 --delete-local-data 플래그를 drain 명령어에 추가하여 수행합니다.
  • 해당 워커 노드에 데몬셋(daemonset)이 구동 되고 있는경우 데몬셋에 속한 파드(pod)들이 해당 워커 노드에 구동되고 있는 경우, kubectl drain 명령이 수행되지 않습니다. 데몬셋 컨트롤러는 노드의 unschedulable 상태가 있더라도, 이를 무시하고 해당 노드에 파드(pod)를 스케줄하여 배치할 수 있습니다. 데몬셋에 속한 파드(pod)들이 있는 경우에는, --ignore-daemonsets 플래그를 추가하여 해당 파드(pod)들을 축출(eviction)대상에서 제외할 수 있습니다.

  • 쿠버네티스의 컨트롤러에서 관리가 되지 않는 파드가 구동되고 있는 경우 쿠버네티스에서는 Deployment, Statefulset, DaemonSet, ReplicaSet, Job와 같은 컨트롤러가 관리하지 않는 파드(pod)가 해당 워커 노드 상에 있는 경우, kubectl drain 명령어는 이를 보호하기 위해서 동작하지 않습니다. kubectl drain 명령어를 --force 옵션을 통해 실행하는 경우, 이러한 Pod들은 클러스터에서 제거되며 재스케줄링되지 않습니다.

명령어 예제

$ kubectl --kubeconfig=$KUBE_CONFIG drain $NODENAME --delete-local-data --ignore-daemonsets

③ 에러 반환 없이 kubectl drain명령어가 성공한 경우, 가상 머신을 재부팅 하거나 제거 등과 같은 클러스터 유지 보수 작업을 수행할 수 있습니다. 유지 보수 작업 후에는 해당 워커 노드에 다시 파드들이 스케줄될 수 있도록 다음의 커맨드를 사용합니다. 해당 워커 노드를 반납하고자 하는 경우에는 아래 명령어를 수행할 필요가 없습니다.

$ kubectl --kubeconfig=$KUBE_CONFIG uncordon $NODENAME

""에 대한 건이 검색되었습니다.

    ""에 대한 검색 결과가 없습니다.

    처리중...