시작하기 전에

Kubernetes는 워커 노드의 장애가 발생하더라도 정상적 혹은 부분적으로 기능을 수행할 수 있도록 결함 감내(fault tolerant) 시스템으로 디자인되어 있습니다. Kubernetes의 마스터 노드는 가상 머신과 같은 인프라의 상태를 주기적으로 워커 노드로부터 수신하며, 어떠한 이유로 인해 문제가 발생한 경우에는 이를 복구하도록 동작합니다. 그러나 모든 경우의 문제를 해결하는데는 한계가 있으며, 노드의 유지보수를 위해 개발자가 특정 워커 노드 상에 운영 중이던 파드(pod)의 우아한 종료(gracefully shutting down)를 위한 개입이 필요할 수 있습니다.

이 문서에서는 Kubernetes 클러스터의 Ready 상태인 노드 수를 서버 반납이나 유지보수를 위한 중단 등으로 의도적으로 축소시키고자 할 때, 축소 대상의 노드에서 구동 중인 애플리케이션을 다른 노드로 배출(drain)시키는 과정을 다룹니다.

Kubernetes에 대한 오해

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

위에 기술된 내용은 Kubernetes 운영에 대한 흔한 오해 중 하나입니다. Kubernetes 마스터 노드의 kube-controller-manager는 특정 워커 노드의 컨디션에 문제를 감지하였더라도, 파드 축출(eviction) 조건이 충족된 경우에 재스케줄링을 수행합니다.

동작 중인 워커 노드를 강제로 재시작하는 경우에는 앞서 언급한 조건이 충족되지 않는 경우, 일정 시간 동안 해당 워커 노드에 스케줄된 파드의 정지(downtime)를 유발합니다. 특정 워커 노드의 재시작 전 kubectl drain 명령어를 사용해 구동 중이던 파드를 다른 워커 노드로 축출하는 우아한 종료(gracefully shutting down pods) 과정을 통해 안정적으로 서비스를 운영할 수 있습니다.

워커 노드의 상태 확인

Kubernetes의 마스터 노드는 주기적으로 인프라의 상태를 주기적으로 워커 노드로부터 수신합니다. 노드의 상태와 상세 정보는 다음의 명령어를 실행하여 확인할 수 있습니다. 자세한 내용은 공식 문서를 참고해주세요.

$ 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로 유지되는 경우, 노드 상의 모든 파드는 노드 컨트롤러에 의해 삭제되도록 스케줄됩니다.

네이버 클라우드 플랫폼의 Kubernetes 서비스에서는 pod-eviction-timeout 값을 5분으로 설정하여 사용합니다.

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

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

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

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

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

$ kubectl --kubeconfig=$KUBE_CONFIG get nodes

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

$ kubectl --kubeconfig=$KUBE_CONFIG drain $NODENAME

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

  • 파드가 emptyDir을 사용하여 local data를 저장하는 경우

    emptyDir를 사용하여 local data를 저장하는 파드가 해당 워커 노드에 있는 경우, 이 파드를 삭제 시 해당 데이터 또한 삭제되므로 수행되지 않습니다. 해당 파드가 제거되어도 문제가 없는 경우에는 --delete-local-data 플래그를 drain 명령어에 추가하여 수행합니다.

  • 해당 워커 노드에 데몬셋(daemonset)이 구동되고 있는 경우

    데몬셋에 속한 파드가 해당 워커 노드에 구동되고 있는 경우, kubectl drain 명령이 수행되지 않습니다. 데몬셋 컨트롤러는 노드가 unschedulable 상태에 있더라도 이를 무시하고 해당 노드에 파드를 스케줄하여 배치할 수 있습니다. 데몬셋에 속한 파드가 있는 경우에는, --ignore-daemonsets 플래그를 추가하여 해당 파드를 축출 대상에서 제외할 수 있습니다.

  • Kubernetes의 컨트롤러에서 관리되지 않는 파드가 구동되고 있는 경우

    Kubernetes에서는 Deployment, Statefulset, DaemonSet, ReplicaSet, Job과 같은 컨트롤러가 관리하지 않는 파드가 해당 워커 노드 상에 있는 경우, kubectl drain 명령어는 이를 보호하기 위해서 동작하지 않습니다. --force 플래그를 추가하여 kubectl drain 명령어를 실행하는 경우, 이러한 파드는 클러스터에서 제거되며 재스케줄링되지 않습니다.

명령어 예

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

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

$ kubectl --kubeconfig=$KUBE_CONFIG uncordon $NODENAME

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

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

    처리중...