이 가이드는 고가용성 애플리케이션을 구성하려는 소유자와 파드에서 발생하는 장애 유형을 이해하기 원하는 애플리케이션 소유자를 위한 것이다.
또한 클러스터의 업그레이드와 오토스케일링과 같은 클러스터의 자동화 작업을 하려는 관리자를 위한 것이다.
파드는 누군가(사람 또는 컨트롤러)가 파괴하거나 불가피한 하드웨어 오류 또는 시스템 소프트웨어 오류가 아니면 사라지지 않는다.
우리는 이런 불가피한 상황을 애플리케이션의 비자발적 중단 으로 부른다. 예시:
리소스 부족을 제외한 나머지 조건은 대부분의 사용자가 익숙할 것이다. 왜냐하면 그 조건은 쿠버네티스에 국한되지 않기 때문이다.
우리는 다른 상황을 자발적인 중단 으로 부른다. 여기에는 애플리케이션 소유자의 작업과 클러스터 관리자의 작업이 모두 포함된다. 다음은 대표적인 애플리케이션 소유자의 작업이다.
클러스터 관리자의 작업:
위 작업은 클러스터 관리자가 직접 수행하거나 자동화를 통해 수행하며, 클러스터 호스팅 공급자에 의해서도 수행된다.
클러스터에 자발적인 중단을 일으킬 수 있는 어떤 원인이 있는지 클러스터 관리자에게 문의하거나 클라우드 공급자에게 문의하고, 배포 문서를 참조해서 확인해야 한다. 만약 자발적인 중단을 일으킬 수 있는 원인이 없다면 Pod Disruption Budget의 생성을 넘길 수 있다.
주의: 모든 자발적인 중단이 Pod Disruption Budget에 연관되는 것은 아니다. 예를 들어 디플로이먼트 또는 파드의 삭제는 Pod Disruption Budget를 무시한다.
비자발적인 중단으로 인한 영향을 경감하기 위한 몇 가지 방법은 다음과 같다.
자발적 중단의 빈도는 다양하다. 기본적인 쿠버네티스 클러스터에서는 자발적인 운영 중단이 전혀 없다. 그러나 클러스터 관리자 또는 호스팅 공급자가 자발적 중단이 발생할 수 있는 일부 부가 서비스를 운영할 수 있다. 예를 들어 노드 소프트웨어의 업데이트를 출시하는 경우 자발적 중단이 발생할 수 있다. 또한 클러스터(노드) 오토스케일링의 일부 구현에서는 단편화를 제거하고 노드의 효율을 높이는 과정에서 자발적 중단을 야기할 수 있다. 클러스터 관리자 또는 호스팅 공급자는 예측 가능한 자발적 중단 수준에 대해 문서화해야 한다.
쿠버네티스는 자주 발생하는 자발적 중단에도 고가용성 애플리케이션을 실행 할 수 있는 기능을 제공한다. 우리는 이 기능을 Disruption Budgets 이라 부른다.
애플리케이션 소유자는 각 애플리케이션에 대해 PodDisruptionBudget
오브젝트(PDB)를 만들 수 있다.
PDB는 자발적 중단으로 일시에 중지되는 복제된 애플리케이션 파드의 수를 제한한다.
예를 들어 정족수 기반의 애플리케이션이
실행 중인 레플리카의 수가 정족수 이하로 떨어지지 않도록 한다.
웹 프런트 엔드는 부하를 처리하는 레플리카의 수가
일정 비율 이하로 떨어지지 않도록 보장할 수 있다.
클러스터 관리자와 호스팅 공급자는 직접적으로 파드나 디플로이먼트를 제거하는 대신
Eviction API로
불리는 Pod Disruption Budgets를 준수하는 도구를 이용해야 한다.
예를 들어 kubectl drain
명령어나 Kubernetes-on-GCE 클러스터 업그레이드 스크립트(cluster/gce/upgrade.sh
)이다.
클러스터 관리자가 노드를 비우고자 할 경우에는 kubectl drain
명령어를 사용한다.
해당 도구는 머신에 존재하는 모든 파드를 축출하려는 시도를 한다.
축출 요청은 일시적으로 거부될 수 있으며, 도구는 모든 파드가 종료되거나
설정 가능한 타임아웃이 도래할 때까지 주기적으로 모든 실패된 요청을 다시 시도한다.
PDB는 애플리케이션이 필요로 하는 레플리카의 수에 상대적으로, 용인할 수 있는 레플리카의 수를 지정한다.
예를 들어 .spec.replicas: 5
의 값을 갖는 디플로이먼트는 어느 시점에든 5개의 파드를 가져야 한다.
만약 해당 디플로이먼트의 PDB가 특정 시점에 파드를 4개 허용한다면, Eviction API는 한 번에 2개의 파드가 아닌, 1개의 파드의 자발적인 중단을 허용한다.
파드 그룹은 레이블 셀렉터를 사용해서 지정한 애플리케이션으로 구성되며 애플리케이션 컨트롤러(디플로이먼트, 스테이트풀 셋 등)를 사용한 것과 같다.
파드의 “의도”하는 수량은 파드 컨트롤러의 .spec.replicas
를 기반으로 계산한다.
컨트롤러는 오브젝트의 .metadata.ownerReferences
를 사용해서 파드를 발견한다.
PDB는 비자발적 중단이 발생하는 것을 막을 수는 없지만, 버짓이 차감된다.
애플리케이션의 롤링 업그레이드로 파드가 삭제되거나 사용할 수 없는 경우 중단 버짓에 영향을 준다. 그러나 컨트롤러(디플로이먼트, 스테이트풀 셋과 같은)는 롤링 업데이트시 PDB의 제한을 받지 않는다. 애플리케이션 업데이트 진행 중 발생하는 중단 처리는 컨트롤러 사양에 구성되어있다. (디플로이먼트 업데이트에 대해 알아보기.)
파드를 Eviction API로 축출하면 정상적으로 종료된다.
(파드사양에서 terminationGracePeriodSeconds
를 참조.)
node-1
부터 node-3
까지 3개의 노드가 있는 클러스터가 있다고 하자.
클러스터에는 여러 애플리케이션을 실행하고 있다.
여러 애플리케이션 중 하나는 pod-a
, pod-b
, pod-c
로 부르는 3개의 레플리카가 있다. 여기에 pod-x
라고 부르는 PDB와 무관한 파드가 보인다.
초기에 파드는 다음과 같이 배치된다.
node-1 | node-2 | node-3 |
---|---|---|
pod-a available | pod-b available | pod-c available |
pod-x available |
전체 3개 파드는 디플로이먼트의 일부분으로 전체적으로 항상 3개의 파드 중 최소 2개의 파드를 사용할 수 있도록 하는 PDB를 가지고 있다.
예를 들어, 클러스터 관리자가 커널 버그를 수정하기위해 새 커널 버전으로 재부팅하려는 경우를 가정해보자.
클러스터 관리자는 첫째로 node-1
을 kubectl drain
명령어를 사용해서 비우려 한다.
kubectl
은 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-d
라는 대체 파드를 생성한다.
node-1
은 차단되어 있어 다른 노드에 위치한다.
무언가가 pod-x
의 대체 파드로 pod-y
도 생성했다.
(참고: 스테이트풀 셋은 pod-0
처럼 불릴, pod-a
를
교체하기 전에 완전히 중지해야 하며, pod-0
로 불리지만, 다른 UID로 생성된다.
그렇지 않으면 이 예시는 스테이트풀 셋에도 적용된다.)
이제 클러스터는 다음과 같은 상태이다.
node-1 draining | node-2 | node-3 |
---|---|---|
pod-a terminating | pod-b available | pod-c available |
pod-x terminating | pod-d starting | pod-y |
어느 순간 파드가 종료되고, 클러스터는 다음과 같은 상태가 된다.
node-1 drained | node-2 | node-3 |
---|---|---|
pod-b available | pod-c available | |
pod-d starting | pod-y |
이 시점에서 만약 성급한 클러스터 관리자가 node-2
또는 node-3
을
비우려고 하는 경우 디플로이먼트에 available 상태의 파드가 2개 뿐이고,
PDB에 필요한 최소 파드는 2개이기 때문에 drain 명령이 차단된다. 약간의 시간이 지나면 pod-d
가 available 상태가 된다.
이제 클러스터는 다음과 같은 상태이다.
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
와 같이 어떤 순서대로 두 파드를 축출하려 할 것이다.
drain 커멘드는 pod-b
를 축출하는데 성공했다.
그러나 drain 커멘드가 pod-d
를 축출하려 하는 경우
디플로이먼트에 available 상태의 파드는 1개로 축출이 거부된다.
디플로이먼트는pod-b
를 대체할 pod-e
라는 파드를 생성한다.
클러스터에 pod-e
를 스케줄하기 위한 충분한 리소스가 없기 때문에
드레이닝 명령어는 차단된다.
클러스터는 다음 상태로 끝나게 된다.
node-1 drained | node-2 | node-3 | no node |
---|---|---|---|
pod-b available | pod-c available | pod-e pending | |
pod-d available | pod-y |
이 시점에서 클러스터 관리자는 클러스터에 노드를 추가해서 업그레이드를 진행해야 한다.
쿠버네티스에 중단이 발생할 수 있는 비율을 어떻게 변화시키는지 다음의 사례를 통해 알 수 있다.
보통 클러스터 매니저와 애플리케이션 소유자는 서로에 대한 지식이 부족한 별도의 역할로 생각하는 것이 유용하다. 이와 같은 책임의 분리는 다음의 시나리오에서 타당할 수 있다.
Pod Disruption Budgets는 역할 분리에 따라 역할에 맞는 인터페이스를 제공한다.
만약 조직에 역할 분리에 따른 책임의 분리가 없다면 Pod Disruption Budgets를 사용할 필요가 없다.
만약 클러스터 관리자라면, 그리고 클러스터 전체 노드에 노드 또는 시스템 소프트웨어 업그레이드와 같은 중단이 발생할 수 있는 작업을 수행하는 경우 다음과 같은 옵션을 선택한다.
Pod Disruption Budget 설정하기의 단계를 따라서 애플리케이션을 보호한다.
노드 비우기에 대해 자세히 알아보기
이 페이지가 도움이 되었나요?
피드백 감사합니다. 쿠버네티스 사용 방법에 대해서 구체적이고 답변 가능한 질문이 있다면, 다음 링크에서 질문하십시오. Stack Overflow. 원한다면 GitHub 리포지터리에 이슈를 열어서 문제 리포트 또는 개선 제안이 가능합니다..