Computing

Kubernetes 고가용성(HA) (4): Heartbeats 본문

Cloud/Kubernetes

Kubernetes 고가용성(HA) (4): Heartbeats

jhson989 2023. 4. 27. 22:00

이전글

Kubernetes 고가용성(HA) (1): 고가용성과 Kube Master의 고가용성

Kubernetes 고가용성(HA) (2): kubeadm을 통한 고가용성 배포

- Kubernetes 고가용성(HA) (3): Keepalived와 HAProxy

 

이전 글들에서 쿠버네티스의 고가용성을 위한 복수 개의 Control plane 노드 구성 방법에 대하여 정리하였다. 정리하면서 느꼈지만 쿠버네티스는 중단없는 (인터넷) 서비스 운영, 즉 고가용성을 위해 다양한 기법이 적용된 것 같다. 오늘은 각 노드(Control plane or Worker)가 살아있음을 쿠버네티스 시스템에 알리는 Heartbeats[1]라는 개념에 대하여 정리하고자 한다.

 

 

 

분산 시스템에서의 Heartbeats

Heartbeat(s)[2]는 우리말로는 심장박동을 의미한다. 사람이 살아있다면 어느정도 일정한 빈도로 심장이 뛰면서 Heartbeats를 생성한다. 따라서 Heartbeats가 계속해서 발생한다면 이 정보를 통해 사람이 살아 있다고 판단할 수 있을 것이다. 이와 마찬가지 개념으로 쿠버네티스, 나아가 분산 시스템에서 시스템을 구성하는 개별 노드(컴퓨터, 서버)가 살아있음(또는 접근가능함)을 알려주는 신호를 Heartbeat라고 한다. 살아있음을 확인하는 행위 자체는 health check라고 한다. 

 

여러 대의 노드로 구성된 분산 시스템이 있다고 하자. 그 시스템은 전체 시스템을 관리하는 Master(쿠버네티스의 경우 Control plane)와 프로그램을 실행하는 Worker로 구성될 것이다. Master는 Worker들이 정상 작동하는 지 정보를 알아야 전체적인 시스템을 관리할 수 있을 것이다. 따라서 각 Worker들은 주기적으로 자신이 정상 작동함을 Master에게 알려야 할 필요가 생긴다. 이러한 상황에서 Worker들이 Master에게 주기적으로 보내는 신호를 Heartbeat라고 하고, 이 신호가 수신되는 한 Master는 해당 신호를 보낸 Worker가 살아있음을 판단할 수 있다[2].

 

Worker에서 Master로 보내는 Heartbeat 신호는 다양한 요인에 의해서 전송되지 않을 수 있다. 예를 들면, Worker 자체가 고장나 버리거나 Heartbeat를 보내는 소프트웨어에 에러가 발생할 수도 있다. 혹은 Worker 자체는 문제가 없을 수 있으나 Worker와 Master 사이의 네트워크에 문제가 발생한 것일 수도 있다.

 

이런 저런 이유에서 Worker의 Heartbeat를 더 이상 수신받지 못한다면 Master는 해당 Worker가 살았는 지 죽었는 지를 판단해야 하는 상황이 온다. 대개의 경우, Heartbeat가 일정 시간 이상 수신되지 않는다면 죽었다고 판단하는 것 같다[3]. 만약 죽었다고 판단한다면, Master는 죽은 Worker가 하던 일을 자동으로 다른 살아있는 Worker에게 할당하므로서 전체 시스템이 정상 작동하도록 한다(고가용성(HA)를 달성한다).

 

실제 구현은 다양한 방식이 존재한다. Master가 모든 Node에게 message를 보내고, 각 Node가 그 message에 답하는 방식으로 구현할 수 있다[4]. 혹은 쿠버네티스와 마찬가지로 lease를 이용하여 각 Node가 직접 Master에게 신호를 보내는 방식도 가능하다[1].

 

 

 

Kubernetes의 Heartbeats

쿠버네티스도 다른 분산 시스템과 마찬가지로 Heartbeat 매커니즘을 이용하여, 클러스터에 참여한 노드의 생존 여부(접근 가능 여부, reachability)를 판단한다. 쿠버네티스의 모든 노드(Control plane과 Worker 모두)는 Heartbeat 메세지를 주기적으로 Control plane에 전송한다. Control plane은 이 신호를 수신함으로서 각 노드가 정상 작동하는 지 판단한다. 만약 정상 작동하지 않는다면 장애 대응(failover)를 실행한다[1].

 

쿠버네티스의 각 노드의 Kubelet가 Heartbeat 신호를 Control plane에 보내는 역할을 담당한다[1]. 각 노드에 설치된 Kubelet은 주기적으로 Control plane의 API server에 신호를 보내 각 노드가 살아있다는 정보를 etcd에 저장한다[5]. 즉 쿠버네티스에서의 Heartbeat 매터니즘은 kubelet이 API server를 통해 etcd에 주기적으로 상태를 업데이트하는 방식으로 작동한다. (다만 궁금한 것은 Control plane의 Heartbeat는 어떻게 생성되는 지이다. Control plane은 kubelet이 없다고 알고 있는데 그면 누가 담당을 하는 것일까?)

 

구체적으로 쿠버네티스의 Heartbeat는 두 가지 상태를 업데이트한다.

- 각 노드의 Node 오브젝트의 status 업데이트

- 각 노드의 Lease 오브젝트 업데이트 (Lease의 개념은 다음 링크)

 

쿠버네티스 초기에는 각 노드의 Node 오브젝트의 status 필드만을 주기적으로(약 10초마다) 업데이트함으로서 Heartbeats 신호를 전달하였다고 한다. 다만 Node 오브젝트는 해당 Node에 대한 모든 정보를 포함하고 있는 오브젝트기에 상대적으로 매우 큰 오브젝트이다. 이러한 오브젝트에 주기적으로 업데이트를 실행할 경우 Node 오브젝트의 크기는 더욱 커지게 된다[5]. (etcd의 경우 업데이트 log 자체를 저장해두기에 시간이 지날수록 오브젝트가 커지게 됨)

 

[5]는 이런 문제를 파악하고 Heartbeat 정보만을 처리하기 위해 Lease 오브젝트를 제안하였으며, 현재 쿠버네티스는 이 개념을 채택하여 사용하고 있다. Lease 오브젝트는 오로지 Heartbeats만을 위해 만들어진 오브젝트이므로 다른 개념들이 함께 저장된 Node 오브젝트에 비해 크기가 작게 유지된다. 따라서 Heartbeats을 효율적으로 구현할 수 있다고 한다.

구체적인 쿠버네티스의 Heartbeat 구현은 다음과 같다. 

- kubelet은 10초 마다 Lease 오브젝트를 업데이트한다.

- kubelet은 meaningful한 상태 업데이트가 필요할 때 혹은 5분 마다 Node 오브젝트의 status를 업데이트한다.

 

 

 

Heartbeat 실패의 경우

쿠버네티스 노드에 문제가 발생할 경우 Heartbeat 신호가 더 이상 Control plane의 etcd에 업데이트되지 않을 것이다. 이제는 누군가가 나서서 해당 노드가 죽었구나를 판단하고 장애 대응을 해야한다. Control plane의 Node controller가 해당 역할을 수행한다. Node controller는 etcd에 저장된 Lease 오브젝트와 Node 오브젝트를 확인하고 해당 노드의 상태를 최종 판단한다[6].

 

Node controller가 어떤 노드가 죽었다(접근 불가능하다. unreachable)고 판단할 경우 다음과 같은 두 가지 작업을 수행한다.

- Node 오브젝트의 status 필드를 Ready에서 NotReady(or Unknown)으로 업데이트

- 일정 시간이 지나면 해당 노드에서 실행되는 Pod들을 다른 노드에서 실행시킴 (API-initiated eviction)

 

Node controller는 5초마다 Node object의 status와 Lease object를 확인한다. 만약 40초 이상 두 개가 업데이트되지 않았다면 해당 노드에 문제가 생겼다고 판단하고 Node의 Status를 Ready에서 NotReady(Unknown)으로 수정한다. 만약 5분 이상 Ready가 되지 않는다면 Node controller는 해당 노드에서 실행되는 파드들을 다른 노드에서 실행시킨다(eviction). 

 

Fig 1. Node 상태

Fig 1.은 종료시킨 Node의 상태(Node-dead, 위)와 정상작동하는 Node의 상태(Node-alive, 아래)를 보여주는 그림이다. kubectl get nodes 명령어를 통해 각 노드의 상태를 확인하였다. Node-dead의 경우 "kubelet이 node status를 업데이트하지 않는다"는 메세지와 함께 status가 Unknown으로 설정되어 있는 것을 확인할 수 있다.

 

 

 

Reference

[1] https://kubernetes.io/docs/concepts/architecture/nodes/#heartbeats

[2] https://en.wikipedia.org/wiki/Heartbeat_(computing)

[3] Kawazoe Aguilera, Marcos; Chen, Wei; Toueg, Sam (1997). "Heartbeat: A timeout-free failure detector for quiescent reliable communication" (PDF). Distributed Algorithms. Berlin, Heidelberg: Springer Berlin Heidelberg. pp. 126–140. doi:10.1007/bfb0030680. hdl:1813/7286. ISBN 978-3-540-63575-8. ISSN 0302-9743.

[4] https://en.wikipedia.org/wiki/Heartbeat_(computing)#CITEREFRobertson2000

[5] https://github.com/kubernetes/enhancements/blob/0460fcf4637d440ce7d539a931e44dae931f9849/keps/sig-node/0009-node-heartbeat.md

[6] https://kubernetes.io/docs/concepts/architecture/nodes/#node-controller