노드

쿠버네티스는 컨테이너를 파드내에 배치하고 노드 에서 실행함으로 워크로드를 구동한다. 노드는 클러스터에 따라 가상 또는 물리적 머신일 수 있다. 각 노드는 컨트롤 플레인에 의해 관리되며 파드를 실행하는 데 필요한 서비스를 포함한다.

일반적으로 클러스터에는 여러 개의 노드가 있으며, 학습 또는 리소스가 제한되는 환경에서는 하나만 있을 수도 있다.

노드의 컴포넌트에는 kubelet, 컨테이너 런타임 그리고 kube-proxy가 포함된다.

관리

API 서버에 노드를 추가하는 두가지 주요 방법이 있다.

  1. 노드의 kubelet으로 컨트롤 플레인에 자체 등록
  2. 사용자(또는 다른 사용자)가 노드 오브젝트를 수동으로 추가

노드 오브젝트 또는 노드의 kubelet으로 자체 등록한 후 컨트롤 플레인은 새 노드 오브젝트가 유효한지 확인한다. 예를 들어 다음 JSON 매니페스트에서 노드를 만들려는 경우이다.

{
  "kind": "Node",
  "apiVersion": "v1",
  "metadata": {
    "name": "10.240.79.157",
    "labels": {
      "name": "my-first-k8s-node"
    }
  }
}

쿠버네티스는 내부적으로 노드 오브젝트를 생성한다(표시한다). 쿠버네티스는 kubelet이 노드의 metadata.name 필드와 일치하는 API 서버에 등록이 되어 있는지 확인한다. 노드가 정상이면(예를 들어 필요한 모든 서비스가 실행중인 경우) 파드를 실행할 수 있게 된다. 그렇지 않으면, 해당 노드는 정상이 될 때까지 모든 클러스터 활동에 대해 무시된다.

노드 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.

노드 이름 고유성

이름은 노드를 식별한다. 두 노드는 동시에 같은 이름을 가질 수 없다. 쿠버네티스는 또한 같은 이름의 리소스가 동일한 객체라고 가정한다. 노드의 경우, 동일한 이름을 사용하는 인스턴스가 동일한 상태(예: 네트워크 설정, 루트 디스크 내용)와 노드 레이블과 같은 동일한 속성(attribute)을 갖는다고 암시적으로 가정한다. 인스턴스가 이름을 변경하지 않고 수정된 경우 이로 인해 불일치가 발생할 수 있다. 노드를 대폭 교체하거나 업데이트해야 하는 경우, 기존 노드 오브젝트를 먼저 API 서버에서 제거하고 업데이트 후 다시 추가해야 한다.

노드에 대한 자체-등록(self-registration)

kubelet 플래그 --register-node가 참(기본값)일 경우, kubelet은 API 서버에 스스로 등록을 시도할 것이다. 이는 선호되는 패턴이며, 대부분의 배포판에서 사용된다.

자체-등록에 대해, kubelet은 다음 옵션과 함께 시작된다.

  • --kubeconfig - apiserver에 스스로 인증하기 위한 자격증명에 대한 경로.

  • --cloud-provider - 자신에 대한 메터데이터를 읽기 위해 어떻게 클라우드 제공자와 소통할지에 대한 방법.

  • --register-node - 자동으로 API 서버에 등록.

  • --register-with-taints - 주어진 테인트(taint) 리스트(콤마로 분리된 <key>=<value>:<effect>)를 가진 노드 등록.

    register-node가 거짓이면 동작 안 함.

  • --node-ip - 선택적인, 쉼표로 구분된 노드의 IP 주소의 리스트. 각 주소 체계마다 하나의 주소만 지정 가능. 예를 들어, 단일 스택 IPv4 클러스터에서는 kubelet이 노드의 주소로 쓸 수 있게 IPv4 주소로 설정함.

    이중 스택 클러스터 실행에 관한 상세 정보는 IPv4/IPv6 이중 스택 구성을 참고.

    이 인자를 사용하지 않으면 kubelet은 노드의 기본 IPv4 주소를 사용함. 만약 노드가 IPv4 주소가 없으면 kubelet은 노드의 기본 IPv6 주소를 사용함.

  • --node-labels - 클러스터에 노드를 등록할 때 추가 할 레이블 (NodeRestriction admission plugin에 의해 적용되는 레이블 제한 사항 참고).

  • --node-status-update-frequency - 얼마나 자주 kubelet이 API 서버에 해당 노드 상태를 게시할 지 정의.

Node authorization modeNodeRestriction admission plugin이 활성화 되면, 각 kubelet은 자신이 속한 노드의 리소스에 대해서만 생성/수정할 권한을 가진다.

수동 노드 관리

kubectl을 사용해서 노드 오브젝트를 생성하고 수정할 수 있다.

노드 오브젝트를 수동으로 생성하려면 kubelet 플래그를 --register-node=false 로 설정한다.

--register-node 설정과 관계 없이 노드 오브젝트를 수정할 수 있다. 예를 들어 기존 노드에 레이블을 설정하거나, 스케줄 불가로 표시할 수 있다.

파드의 노드 셀렉터와 함께 노드의 레이블을 사용해서 스케줄링을 제어할 수 있다. 예를 들어, 사용 가능한 노드의 하위 집합에서만 실행되도록 파드를 제한할 수 있다.

노드를 스케줄 불가로 표시하면 스케줄러가 해당 노드에 새 파드를 배치할 수 없지만, 노드에 있는 기존 파드에는 영향을 미치지 않는다. 이는 노드 재부팅 또는 기타 유지보수 준비 단계에서 유용하다.

노드를 스케줄 불가로 표시하려면 다음을 실행한다.

kubectl cordon $NODENAME

보다 자세한 내용은 안전하게 노드를 드레인(drain)하기 를 참고한다.

노드 상태

노드의 상태는 다음의 정보를 포함한다.

kubectl 을 사용해서 노드 상태와 기타 세부 정보를 볼수 있다.

kubectl describe node <insert-node-name-here>

자세한 정보는 노드 상태를 참고.

노드 하트비트

쿠버네티스 노드가 보내는 하트비트는 클러스터가 개별 노드가 가용한지를 판단할 수 있도록 도움을 주고, 장애가 발견된 경우 조치를 할 수 있게한다.

노드에는 두 가지 형태의 하트비트가 있다.

  • 노드의 .status에 대한 업데이트
  • kube-node-lease 네임스페이스 내의 리스(Lease) 오브젝트. 각 노드는 연관된 리스 오브젝트를 갖는다.

노드 컨트롤러

노드 컨트롤러는 노드의 다양한 측면을 관리하는 쿠버네티스 컨트롤 플레인 컴포넌트이다.

노드 컨트롤러는 노드가 생성되어 유지되는 동안 다양한 역할을 한다. 첫째는 등록 시점에 (CIDR 할당이 사용토록 설정된 경우) 노드에 CIDR 블럭을 할당하는 것이다.

두 번째는 노드 컨트롤러의 내부 노드 리스트를 클라우드 제공사업자의 사용 가능한 머신 리스트 정보를 근거로 최신상태로 유지하는 것이다. 클라우드 환경에서 동작 중일 경우, 노드상태가 불량할 때마다, 노드 컨트롤러는 해당 노드용 VM이 여전히 사용 가능한지에 대해 클라우드 제공사업자에게 묻는다. 사용 가능하지 않을 경우, 노드 컨트롤러는 노드 리스트로부터 그 노드를 삭제한다.

세 번째는 노드의 동작 상태를 모니터링하는 것이다. 노드 컨트롤러는 다음을 담당한다.

  • 노드가 접근 불가능(unreachable) 상태가 되는 경우, 노드의 .status 필드의 Ready 컨디션을 업데이트한다. 이 경우에는 노드 컨트롤러가 Ready 컨디션을 Unknown으로 설정한다.
  • 노드가 계속 접근 불가능 상태로 남아있는 경우, 해당 노드의 모든 파드에 대해서 API를 이용한 축출을 트리거한다. 기본적으로, 노드 컨트롤러는 노드를 Unknown으로 마킹한 뒤 5분을 기다렸다가 최초의 축출 요청을 시작한다.

기본적으로, 노드 컨트롤러는 5 초마다 각 노드의 상태를 체크한다. 체크 주기는 kube-controller-manager 구성 요소의 --node-monitor-period 플래그를 이용하여 설정할 수 있다.

축출 빈도 제한

대부분의 경우, 노드 컨트롤러는 초당 --node-eviction-rate(기본값 0.1)로 축출 속도를 제한한다. 이 말은 10초당 1개의 노드를 초과하여 파드 축출을 하지 않는다는 의미가 된다.

노드 축출 행위는 주어진 가용성 영역 내 하나의 노드가 상태가 불량할 경우 변화한다. 노드 컨트롤러는 영역 내 동시에 상태가 불량한 노드의 퍼센티지가 얼마나 되는지 체크한다(Ready 컨디션은 Unknown 또는 False 값을 가진다).

  • 상태가 불량한 노드의 비율이 최소 --unhealthy-zone-threshold (기본값 0.55)가 되면 축출 속도가 감소한다.
  • 클러스터가 작으면 (즉 --large-cluster-size-threshold 노드 이하면 - 기본값 50) 축출이 중지된다.
  • 이외의 경우, 축출 속도는 초당 --secondary-node-eviction-rate(기본값 0.01)로 감소된다.

이 정책들이 가용성 영역 단위로 실행되어지는 이유는 나머지가 연결되어 있는 동안 하나의 가용성 영역이 컨트롤 플레인으로부터 분할되어 질 수도 있기 때문이다. 만약 클러스터가 여러 클라우드 제공사업자의 가용성 영역에 걸쳐 있지 않는 이상, 축출 매커니즘은 영역 별 가용성을 고려하지 않는다.

노드가 가용성 영역들에 걸쳐 퍼져 있는 주된 이유는 하나의 전체 영역이 장애가 발생할 경우 워크로드가 상태 양호한 영역으로 이전되어질 수 있도록 하기 위해서이다. 그러므로, 하나의 영역 내 모든 노드들이 상태가 불량하면 노드 컨트롤러는 --node-eviction-rate 의 정상 속도로 축출한다. 코너 케이스란 모든 영역이 완전히 상태불량(클러스터 내 양호한 노드가 없는 경우)한 경우이다. 이러한 경우, 노드 컨트롤러는 컨트롤 플레인과 노드 간 연결에 문제가 있는 것으로 간주하고 축출을 실행하지 않는다. (중단 이후 일부 노드가 다시 보이는 경우 노드 컨트롤러는 상태가 양호하지 않거나 접근이 불가능한 나머지 노드에서 파드를 축출한다.)

또한, 노드 컨트롤러는 파드가 테인트를 허용하지 않을 때 NoExecute 테인트 상태의 노드에서 동작하는 파드에 대한 축출 책임을 가지고 있다. 추가로, 노드 컨틀로러는 연결할 수 없거나, 준비되지 않은 노드와 같은 노드 문제에 상응하는 테인트를 추가한다. 이는 스케줄러가 비정상적인 노드에 파드를 배치하지 않게 된다.

리소스 용량 추적

노드 오브젝트는 노드 리소스 용량에 대한 정보: 예를 들어, 사용 가능한 메모리의 양과 CPU의 수를 추적한다. 노드의 자체 등록은 등록하는 중에 용량을 보고한다. 수동으로 노드를 추가하는 경우 추가할 때 노드의 용량 정보를 설정해야 한다.

쿠버네티스 스케줄러는 노드 상에 모든 노드에 대해 충분한 리소스가 존재하도록 보장한다. 스케줄러는 노드 상에 컨테이너에 대한 요청의 합이 노드 용량보다 더 크지 않도록 체크한다. 요청의 합은 kubelet에서 관리하는 모든 컨테이너를 포함하지만, 컨테이너 런타임에 의해 직접적으로 시작된 컨 테이너는 제외되고 kubelet의 컨트롤 범위 밖에서 실행되는 모든 프로세스도 제외된다.

노드 토폴로지

기능 상태: Kubernetes v1.27 [stable] (enabled by default: true)

TopologyManager 기능 게이트(feature gate)를 활성화 시켜두면, kubelet이 리소스 할당 결정을 할 때 토폴로지 힌트를 사용할 수 있다. 자세한 내용은 노드의 컨트롤 토폴로지 관리 정책을 본다.

다음 내용