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

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

노드의 컴포넌트에는 kubelet, container runtime 그리고 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-node가 false 이면 노드를 수동으로 관리하겠다는 의미.
  • --register-with-taints: 주어진 테인트(taint) 리스트(콤마로 분리된 <key>=<value>:<effect>)를 가진 노드 등록.
  • --node-ip: 노드의 IP 주소.
  • --node-labels: 클러스터에 노드를 등록할 때 추가 할 레이블 (NodeRestriction admission plugin에 의해 적용되는 레이블 제한 사항 참고).
  • --node-status-update-frequency: 얼마나 자주 kubelet 이 API 서버에 해당 노드 상태를 게시할 지 정의.

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

참고:

노드 이름 고유성 섹션에서 언급했듯이, 노드 구성을 업데이트해야 하는 경우 API 서버에 노드를 다시 등록하는 것이 좋다. 예를 들어 kubelet이 --node-labels의 새로운 구성으로 다시 시작되더라도, 동일한 노드 이름이 사용된 경우 레이블이 해당 노드의 등록에 설정되기 때문에 변경 사항이 적용되지 않는다.

노드에 이미 스케줄된 파드는 해당 노드 구성이 kubelet 재시작에 의해 변경된 경우 오작동하거나 문제를 일으킬 수 있다. 예를 들어 이미 실행 중인 파드가 노드에 할당된 새 레이블에 대해 오염(taint)될 수 있는 반면 해당 파드와 호환되지 않는 다른 파드는 새 레이블을 기반으로 스케줄링된다. 노드 재등록(re-registration)은 모든 파드를 비우고(drain) 다시 적절하게 스케줄링되도록 한다.

수동 노드 관리

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

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

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

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

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

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

kubectl cordon $NODENAME

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

참고: 데몬셋(DaemonSet)에 포함되는 일부 파드는 스케줄 불가 노드에서 실행될 수 있다. 일반적으로 데몬셋은 워크로드 애플리케이션을 비우는 경우에도 노드에서 실행되어야 하는 노드 로컬 서비스를 제공한다.

노드 상태

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

  • 주소
  • 컨디션
  • 용량과 할당가능
  • 정보

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

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

출력되는 각 섹션은 아래에 설명되어 있다.

주소

이 필드의 용법은 클라우드 제공사업자 또는 베어메탈 구성에 따라 다양하다.

  • HostName: 노드의 커널에 의해 알려진 호스트명이다. --hostname-override 파라미터를 통해 치환될 수 있다.
  • ExternalIP: 일반적으로 노드의 IP 주소는 외부로 라우트 가능 (클러스터 외부에서 이용 가능) 하다 .
  • InternalIP: 일반적으로 노드의 IP 주소는 클러스터 내에서만 라우트 가능하다.

컨디션

conditions 필드는 모든 Running 노드의 상태를 기술한다. 컨디션의 예로 다음을 포함한다.

노드 컨디션설명

Ready 노드가 상태 양호하며 파드를 수용할 준비가 되어 있는 경우 True, 노드의 상태가 불량하여 파드를 수용하지 못할 경우 False, 그리고 노드 컨트롤러가 마지막 node-monitor-grace-period (기본값 40 기간 동안 노드로부터 응답을 받지 못한 경우) Unknown
DiskPressure 디스크 사이즈 상에 압박이 있는 경우, 즉 디스크 용량이 넉넉치 않은 경우 True, 반대의 경우 False
MemoryPressure 노드 메모리 상에 압박이 있는 경우, 즉 노드 메모리가 넉넉치 않은 경우 True, 반대의 경우 False
PIDPressure 프로세스 상에 압박이 있는 경우, 즉 노드 상에 많은 프로세스들이 존재하는 경우 True, 반대의 경우 False
NetworkUnavailable 노드에 대해 네트워크가 올바르게 구성되지 않은 경우 True, 반대의 경우 False
참고: 커맨드 라인 도구를 사용해서 코드화된 노드의 세부 정보를 출력하는 경우 조건에는 SchedulingDisabled 이 포함된다. SchedulingDisabled 은 쿠버네티스 API의 조건이 아니며, 대신 코드화된 노드는 사양에 스케줄 불가로 표시된다.

쿠버네티스 API에서, 노드의 컨디션은 노드 리소스의 .status 부분에 표현된다. 예를 들어, 다음의 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 컨디션의 status 가 pod-eviction-timeout (kube-controller-manager에 전달된 인수)보다 더 길게 Unknown 또는 False로 유지되는 경우, 노드 컨트롤러가 해당 노드에 할당된 전체 파드에 대해 API를 이용한 축출(eviction)을 트리거한다. 기본 축출 타임아웃 기간은 5분 이다. 노드에 접근이 불가할 때와 같은 경우, API 서버는 노드 상의 kubelet 과 통신이 불가하다. API 서버와의 통신이 재개될 때까지 파드 삭제에 대한 결정은 kubelet 에 전해질 수 없다. 그 사이, 삭제되도록 스케줄 되어진 파드는 분할된 노드 상에서 계속 동작할 수도 있다.

노드 컨트롤러가 클러스터 내 동작 중지된 것을 확신할 때까지는 파드를 강제로 삭제하지 않는다. 파드가 Terminating 또는 Unknown 상태로 있을 때 접근 불가한 노드 상에서 동작되고 있는 것을 보게 될 수도 있다. 노드가 영구적으로 클러스터에서 삭제되었는지에 대한 여부를 쿠버네티스가 기반 인프라로부터 유추할 수 없는 경우, 노드가 클러스터를 영구적으로 탈퇴하게 되면, 클러스터 관리자는 손수 노드 오브젝트를 삭제해야 할 수도 있다. 쿠버네티스에서 노드 오브젝트를 삭제하면 노드 상에서 동작 중인 모든 파드 오브젝트가 API 서버로부터 삭제되며 파드가 사용하던 이름을 다시 사용할 수 있게 된다.

노드에서 문제가 발생하면, 쿠버네티스 컨트롤 플레인은 자동으로 노드 상태에 영향을 주는 조건과 일치하는 테인트(taints)를 생성한다. 스케줄러는 파드를 노드에 할당할 때 노드의 테인트를 고려한다. 또한 파드는 노드에 특정 테인트가 있더라도 해당 노드에서 동작하도록 톨러레이션(toleration)을 가질 수 있다.

자세한 내용은 컨디션별 노드 테인트하기를 참조한다.

용량과 할당가능

노드 상에 사용 가능한 리소스를 나타낸다. 리소스에는 CPU, 메모리 그리고 노드 상으로 스케줄 되어질 수 있는 최대 파드 수가 있다.

용량 블록의 필드는 노드에 있는 리소스의 총량을 나타낸다. 할당가능 블록은 일반 파드에서 사용할 수 있는 노드의 리소스 양을 나타낸다.

노드에서 컴퓨팅 리소스 예약하는 방법을 배우는 동안 용량 및 할당가능 리소스에 대해 자세히 읽어보자.

정보

커널 버전, 쿠버네티스 버전 (kubelet과 kube-proxy 버전), 컨테이너 런타임 상세 정보 및 노드가 사용하는 운영 체제가 무엇인지와 같은 노드에 대한 일반적인 정보가 기술된다. 이 정보는 Kubelet 이 노드에서 수집하여 쿠버네티스 API 로 전송한다.

하트비트

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

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

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

노드의 .status에 비하면, 리스는 경량의 리소스이다. 큰 규모의 클러스터에서는 리스를 하트비트에 사용하여 업데이트로 인한 성능 영향을 줄일 수 있다.

kubelet 은 노드의 .status 생성과 업데이트 및 관련된 리스의 업데이트를 담당한다.

  • kubelet 은 상태가 변경되거나 설정된 인터벌보다 오래 업데이트가 없는 경우 노드의 .status를 업데이트한다. 노드의 .status 업데이트에 대한 기본 인터벌은 접근이 불가능한 노드에 대한 타임아웃인 40초 보다 훨씬 긴 5분이다.
  • kubelet 은 리스 오브젝트를 (기본 업데이트 인터벌인) 매 10초마다 생성하고 업데이트한다. 리스 업데이트는 노드의 .status 업데이트와는 독립적이다. 만약 리스 업데이트가 실패하면, kubelet 은 200 ms에서 시작하고 7초의 상한을 갖는 지수적 백오프를 사용해서 재시도한다.

노드 컨트롤러

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

노드 컨트롤러는 노드가 생성되어 유지되는 동안 다양한 역할을 한다. 첫째는 등록 시점에 (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.18 [beta]

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

그레이스풀(Graceful) 노드 셧다운(shutdown)

기능 상태: Kubernetes v1.21 [beta]

kubelet 은 노드 시스템 셧다운을 감지하고 노드에서 실행 중인 파드를 종료하려고 시도한다.

Kubelet 은 노드가 종료되는 동안 파드가 일반 파드 종료 프로세스를 따르도록 한다.

그레이스풀 노드 셧다운 기능은 systemd inhibitor locks 를 사용하여 주어진 기간 동안 노드 종료를 지연시키므로 systemd 에 의존한다.

그레이스풀 노드 셧다운은 1.21에서 기본적으로 활성화된 GracefulNodeShutdown 기능 게이트로 제어된다.

기본적으로, 아래 설명된 두 구성 옵션, shutdownGracePeriod  shutdownGracePeriodCriticalPods 는 모두 0으로 설정되어 있으므로, 그레이스풀 노드 셧다운 기능이 활성화되지 않는다. 기능을 활성화하려면, 두 개의 kubelet 구성 설정을 적절하게 구성하고 0이 아닌 값으로 설정해야 한다.

그레이스풀 셧다운 중에 kubelet 은 다음의 두 단계로 파드를 종료한다.

  1. 노드에서 실행 중인 일반 파드를 종료시킨다.
  2. 노드에서 실행 중인 중요(critical) 파드를 종료시킨다.

그레이스풀 노드 셧다운 기능은 두 개의 KubeletConfiguration 옵션으로 구성된다.

  • shutdownGracePeriod:
    • 노드가 종료를 지연해야 하는 총 기간을 지정한다. 이것은 모든 일반 및 중요 파드의 파드 종료에 필요한 총 유예 기간에 해당한다.
  • shutdownGracePeriodCriticalPods:
    • 노드 종료 중에 중요 파드를 종료하는 데 사용되는 기간을 지정한다. 이 값은 shutdownGracePeriod 보다 작아야 한다.

예를 들어, shutdownGracePeriod=30s, shutdownGracePeriodCriticalPods=10s 인 경우, kubelet 은 노드 종료를 30초까지 지연시킨다. 종료하는 동안 처음 20(30-10)초는 일반 파드의 유예 종료에 할당되고, 마지막 10초는 중요 파드의 종료에 할당된다.

참고:

그레이스풀 노드 셧다운 과정에서 축출된 파드는 셧다운(shutdown)된 것으로 표시된다. kubectl get pods 명령을 실행하면 축출된 파드의 상태가 Terminated 으로 표시된다. 그리고 kubectl describe pod 명령을 실행하면 노드 셧다운으로 인해 파드가 축출되었음을 알 수 있다.

Reason:         Terminated
Message:        Pod was terminated in response to imminent node shutdown.

논 그레이스풀 노드 셧다운

기능 상태: Kubernetes v1.24 [alpha]

전달한 명령이 kubelet 에서 사용하는 금지 잠금 메커니즘(inhibitor locks mechanism)을 트리거하지 않거나, 또는 사용자 오류(예: ShutdownGracePeriod 및 ShutdownGracePeriodCriticalPods 가 제대로 설정되지 않음)로 인해 kubelet 의 노드 셧다운 관리자(Node Shutdown Mananger)가 노드 셧다운 액션을 감지하지 못할 수 있다. 자세한 내용은 위의 그레이스풀 노드 셧다운 섹션을 참조한다.

노드가 셧다운되었지만 kubelet 의 노드 셧다운 관리자가 이를 감지하지 못하면, 스테이트풀셋에 속한 파드는 셧다운된 노드에 '종료 중(terminating)' 상태로 고착되어 다른 동작 중인 노드로 이전될 수 없다. 이는 셧다운된 노드의 kubelet이 파드를 지울 수 없어서 결국 스테이트풀셋이 동일한 이름으로 새 파드를 만들 수 없기 때문이다. 만약 파드가 사용하던 볼륨이 있다면, 볼륨어태치먼트(VolumeAttachment)도 기존의 셧다운된 노드에서 삭제되지 않아 결국 파드가 사용하던 볼륨이 다른 동작 중인 노드에 연결(attach)될 수 없다. 결과적으로, 스테이트풀셋에서 실행되는 애플리케이션이 제대로 작동하지 않는다. 기존의 셧다운된 노드가 정상으로 돌아오지 못하면, 이러한 파드는 셧다운된 노드에 '종료 중(terminating)' 상태로 영원히 고착될 것이다.

위와 같은 상황을 완화하기 위해, 사용자가 node.kubernetes.io/out-of-service 테인트를 NoExecute 또는 NoSchedule 값으로 추가하여 노드를 서비스 불가(out-of-service) 상태로 표시할 수 있다. kube-controller-manager에 NodeOutOfServiceVolumeDetach 기능 게이트가 활성화되어 있고, 노드가 이 테인트에 의해 서비스 불가 상태로 표시되어 있는 경우, 노드에 매치되는 톨러레이션이 없다면 노드 상의 파드는 강제로 삭제될 것이고, 노드 상에서 종료되는 파드에 대한 볼륨 해제(detach) 작업은 즉시 수행될 것이다. 이를 통해 서비스 불가 상태 노드의 파드가 빠르게 다른 노드에서 복구될 수 있다.

논 그레이스풀 셧다운 과정 동안, 파드는 다음의 두 단계로 종료된다.

  1. 매치되는 out-of-service 톨러레이션이 없는 파드를 강제로 삭제한다.
  2. 이러한 파드에 대한 볼륨 해제 작업을 즉시 수행한다.
참고:
  • node.kubernetes.io/out-of-service 테인트를 추가하기 전에, 노드가 완전한 셧다운 또는 전원 꺼짐 상태에 있는지 (재시작 중인 것은 아닌지) 확인한다.
  • 사용자가 서비스 불가 상태 테인트를 직접 추가한 것이기 때문에, 파드가 다른 노드로 옮겨졌고 셧다운 상태였던 노드가 복구된 것을 확인했다면 사용자가 서비스 불가 상태 테인트를 수동으로 제거해야 한다.

파드 우선순위 기반 그레이스풀 노드 셧다운

기능 상태: Kubernetes v1.23 [alpha]

그레이스풀 노드 셧다운 시 파드 셧다운 순서에 더 많은 유연성을 제공할 수 있도록, 클러스터에 프라이어리티클래스(PriorityClass) 기능이 활성화되어 있으면 그레이스풀 노드 셧다운 과정에서 파드의 프라이어리티클래스가 고려된다. 이 기능으로 그레이스풀 노드 셧다운 시 파드가 종료되는 순서를 클러스터 관리자가 프라이어리티 클래스 기반으로 명시적으로 정할 수 있다.

위에서 기술된 것처럼, 그레이스풀 노드 셧다운 기능은 파드를 중요하지 않은(non-critical) 파드와 중요한(critical) 파드 2단계(phase)로 구분하여 종료시킨다. 셧다운 시 파드가 종료되는 순서를 명시적으로 더 상세하게 정해야 한다면, 파드 우선순위 기반 그레이스풀 노드 셧다운을 사용할 수 있다.

그레이스풀 노드 셧다운 과정에서 파드 우선순위가 고려되기 때문에, 그레이스풀 노드 셧다운이 여러 단계로 일어날 수 있으며, 각 단계에서 특정 프라이어리티 클래스의 파드를 종료시킨다. 정확한 단계와 단계별 셧다운 시간은 kubelet 에 설정할 수 있다.

다음과 같이 클러스터에 커스텀 파드 프라이어리티 클래스가 있다고 가정하자.

파드 프라이어리티 클래스 이름파드 프라이어리티 클래스 값

custom-class-a 100000
custom-class-b 10000
custom-class-c 1000
regular/unset 0

kubelet 환경 설정 안의 shutdownGracePeriodByPodPriority 설정은 다음과 같을 수 있다.

파드 프라이어리티 클래스 값종료 대기 시간

100000 10 seconds
10000 180 seconds
1000 120 seconds
0 60 seconds

이를 나타내는 kubelet 환경 설정 YAML은 다음과 같다.

shutdownGracePeriodByPodPriority:
  - priority: 100000
    shutdownGracePeriodSeconds: 10
  - priority: 10000
    shutdownGracePeriodSeconds: 180
  - priority: 1000
    shutdownGracePeriodSeconds: 120
  - priority: 0
    shutdownGracePeriodSeconds: 60

위의 표에 의하면 priority 값이 100000 이상인 파드는 종료까지 10초만 주어지며, 10000 이상 ~ 100000 미만이면 180초, 1000 이상 ~ 10000 미만이면 120초가 주어진다. 마지막으로, 다른 모든 파드는 종료까지 60초가 주어질 것이다.

모든 클래스에 대해 값을 명시할 필요는 없다. 예를 들어, 대신 다음과 같은 구성을 사용할 수도 있다.

파드 프라이어리티 클래스 값종료 대기 시간

100000 300 seconds
1000 120 seconds
0 60 seconds

위의 경우, custom-class-b 에 속하는 파드와 custom-class-c 에 속하는 파드는 동일한 종료 대기 시간을 갖게 될 것이다.

특정 범위에 해당되는 파드가 없으면, kubelet 은 해당 범위에 해당되는 파드를 위해 기다려 주지 않는다. 대신, kubelet 은 즉시 다음 프라이어리티 클래스 값 범위로 넘어간다.

기능이 활성화되어 있지만 환경 설정이 되어 있지 않으면, 순서 지정 동작이 수행되지 않을 것이다.

이 기능을 사용하려면 GracefulNodeShutdownBasedOnPodPriority 기능 게이트를 활성화해야 하고, kubelet config의 ShutdownGracePeriodByPodPriority를 파드 프라이어리티 클래스 값과 각 값에 대한 종료 대기 시간을 명시하여 지정해야 한다.

참고: 그레이스풀 노드 셧다운 과정에서 파드 프라이어리티를 고려하는 기능은 쿠버네티스 v1.23에서 알파 기능으로 도입되었다. 쿠버네티스 1.24에서 이 기능은 베타 상태이며 기본적으로 활성화되어 있다.

graceful_shutdown_start_time_seconds  graceful_shutdown_end_time_seconds 메트릭은 노드 셧다운을 모니터링하기 위해 kubelet 서브시스템에서 방출된다.

스왑(swap) 메모리 관리

기능 상태: Kubernetes v1.22 [alpha]

쿠버네티스 1.22 이전에는 노드가 스왑 메모리를 지원하지 않았다. 그리고 kubelet 은 노드에서 스왑을 발견하지 못한 경우 시작과 동시에 실패하도록 되어 있었다. 1.22부터는 스왑 메모리 지원을 노드 단위로 활성화할 수 있다.

노드에서 스왑을 활성화하려면, NodeSwap 기능 게이트가 kubelet 에서 활성화되어야 하며, 명령줄 플래그 --fail-swap-on 또는 구성 설정에서 failSwapOn 가 false 로 지정되어야 한다.

경고: 메모리 스왑 기능이 활성화되면, 시크릿 오브젝트의 내용과 같은 tmpfs에 기록되었던 쿠버네티스 데이터가 디스크에 스왑될 수 있다.

사용자는 또한 선택적으로 memorySwap.swapBehavior를 구성할 수 있으며, 이를 통해 노드가 스왑 메모리를 사용하는 방식을 명시한다. 예를 들면,

memorySwap:
  swapBehavior: LimitedSwap

swapBehavior에 가용한 구성 옵션은 다음과 같다.

  • LimitedSwap: 쿠버네티스 워크로드는 스왑을 사용할 수 있는 만큼으로 제한된다. 쿠버네티스에 의해 관리되지 않는 노드의 워크로드는 여전히 스왑될 수 있다.
  • UnlimitedSwap: 쿠버네티스 워크로드는 요청한 만큼 스왑 메모리를 사용할 수 있으며, 시스템의 최대치까지 사용 가능하다.

만약 memorySwap 구성이 명시되지 않았고 기능 게이트가 활성화되어 있다면, kubelet 은 LimitedSwap 설정과 같은 행동을 기본적으로 적용한다.

LimitedSwap 설정에 대한 행동은 노드가 ("cgroups"으로 알려진) 제어 그룹이 v1 또는 v2 중에서 무엇으로 동작하는가에 따라서 결정된다.

  • cgroupsv1: 쿠버네티스 워크로드는 메모리와 스왑의 조합을 사용할 수 있다. 파드의 메모리 제한이 설정되어 있다면 가용 상한이 된다.
  • cgroupsv2: 쿠버네티스 워크로드는 스왑 메모리를 사용할 수 없다.

테스트를 지원하고 피드벡을 제공하기 위한 정보는 KEP-2400  디자인 제안에서 찾을 수 있다.

'플랫폼 > kubernetes' 카테고리의 다른 글

쿠버네티스 권장 레이블  (0) 2022.07.13
쿠버네티스 필드 셀렉터  (0) 2022.07.13
쿠버네티스 어노테이션  (0) 2022.07.13
쿠버네티스 레이블, 셀렉터  (0) 2022.07.12
쿠버네티스 네임스페이스  (0) 2022.07.12

kubectl 과 대시보드와 같은 많은 도구들로 쿠버네티스 오브젝트를 시각화하고 관리할 수 있다. 공통 레이블 셋은 모든 도구들이 이해할 수 있는 공통의 방식으로 오브젝트를 식별하고 도구들이 상호 운용적으로 작동할 수 있도록 한다.

권장 레이블은 지원 도구 외에도 쿼리하는 방식으로 애플리케이션을 식별하게 한다.

메타데이터는 애플리케이션의 개념을 중심으로 정리된다. 쿠버네티스는 플랫폼 서비스(PaaS)가 아니며 애플리케이션에 대해 공식적인 개념이 없거나 강요하지 않는다. 대신 애플리케이션은 비공식적이며 메타데이터로 설명된다. 애플리케이션에 포함된 정의는 유연하다.

참고: 메타데이터들은 권장하는 레이블이다. 애플리케이션을 보다 쉽게 관리할 수 있지만 코어 도구에는 필요하지 않다.

공유 레이블과 주석에는 공통 접두사인 app.kubernetes.io 가 있다. 접두사가 없는 레이블은 사용자가 개인적으로 사용할 수 있다. 공유 접두사는 공유 레이블이 사용자 정의 레이블을 방해하지 않도록 한다.

레이블

레이블을 최대한 활용하려면 모든 리소스 오브젝트에 적용해야 한다.

설명 예시 타입
app.kubernetes.io/name 애플리케이션 이름 mysql 문자열
app.kubernetes.io/instance 애플리케이션의 인스턴스를 식별하는 고유한 이름 mysql-abcxzy 문자열
app.kubernetes.io/version 애플리케이션의 현재 버전 (예: a semantic version, revision hash 등.) 5.7.21 문자열
app.kubernetes.io/component 아키텍처 내 구성요소 database 문자열
app.kubernetes.io/part-of 이 애플리케이션의 전체 이름 wordpress 문자열
app.kubernetes.io/managed-by 애플리케이션의 작동을 관리하는 데 사용되는 도구 helm 문자열
app.kubernetes.io/created-by 이 리소스를 만든 컨트롤러/사용자 controller-manager 문자열

위 레이블의 실제 예시는 다음 스테이트풀셋 오브젝트를 고려한다.

# 아래는 전체 명세의 일부분이다
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: mysql-abcxzy
    app.kubernetes.io/version: "5.7.21"
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/created-by: controller-manager

애플리케이션과 애플리케이션 인스턴스

애플리케이션은 동일한 쿠버네티스 클러스터나 동일한 네임스페이스에도 한번 또는 그 이상 설치될 수 있다. 예를 들어, 하나의 쿠버네티스 클러스터에 WordPress가 여러 번 설치되어 각각 서로 다른 웹사이트를 서비스할 수 있다.

애플리케이션의 이름과 애플리케이션 인스턴스 이름은 별도로 기록된다. 예를 들어 WordPress 는 애플리케이션 이름으로 app.kubernetes.io/name 이라는 레이블에 wordpress 라는 값을 가지며, 애플리케이션 인스턴스 이름으로는 app.kubernetes.io/instance 라는 레이블에 wordpress-abcxzy 라는 값을 가진다. 이를 통해 애플리케이션과 애플리케이션 인스턴스를 식별할 수 있다. 모든 애플리케이션 인스턴스는 고유한 이름을 가져야 한다.

예시

위 레이블을 사용하는 다른 방식에 대한 예시는 다양한 복잡성이 있다.

단순한 스테이트리스(stateless) 서비스

Deployment  Service 오브젝트를 통해 배포된 단순한 기본적인 서비스의 경우를 보자. 다음 두 식별자는 레이블을 가장 간단한 형태로 사용하는 방법을 나타낸다.

Deployment 는 애플리케이션을 실행하는 파드를 감시(oversee)하는 데 사용한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: myservice
    app.kubernetes.io/instance: myservice-abcxzy
...

Service는 애플리케이션을 노출하기 위해 사용한다.

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: myservice
    app.kubernetes.io/instance: myservice-abcxzy
...

데이터베이스가 있는 웹 애플리케이션

Helm 을 이용해서 데이터베이스(MySQL)을 이용하는 웹 애플리케이션(WordPress)을 설치한 것과 같이 좀 더 복잡한 애플리케이션을 고려할 수 있다. 다음 식별자는 이 애플리케이션을 배포하는 데 사용하는 오브젝트의 시작을 보여준다.

WordPress 를 배포하는 데 다음과 같이 Deployment 로 시작한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: wordpress
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/version: "4.9.4"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: server
    app.kubernetes.io/part-of: wordpress
...

Service 는 애플리케이션을 노출하기 위해 사용한다.

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: wordpress
    app.kubernetes.io/instance: wordpress-abcxzy
    app.kubernetes.io/version: "4.9.4"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: server
    app.kubernetes.io/part-of: wordpress
...

MySQL 은 StatefulSet 에 MySQL의 소속과 상위 애플리케이션에 대한 메타데이터가 포함되어 노출된다.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: mysql-abcxzy
    app.kubernetes.io/version: "5.7.21"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
...

Service 는 WordPress 의 일부로 MySQL 을 노출하는 데 이용한다.

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: mysql
    app.kubernetes.io/instance: mysql-abcxzy
    app.kubernetes.io/version: "5.7.21"
    app.kubernetes.io/managed-by: helm
    app.kubernetes.io/component: database
    app.kubernetes.io/part-of: wordpress
...

MySQL StatefulSet  Service 로 MySQL 과 WordPress 가 더 큰 범위의 애플리케이션에 포함되어 있는 것을 알게 된다.

'플랫폼 > kubernetes' 카테고리의 다른 글

쿠버네티스 노드  (0) 2022.07.15
쿠버네티스 필드 셀렉터  (0) 2022.07.13
쿠버네티스 어노테이션  (0) 2022.07.13
쿠버네티스 레이블, 셀렉터  (0) 2022.07.12
쿠버네티스 네임스페이스  (0) 2022.07.12

필드 셀렉터는 한 개 이상의 리소스 필드 값에 따라 쿠버네티스 리소스를 선택하기 위해 사용된다. 필드 셀렉터 쿼리의 예시는 다음과 같다.

  • metadata.name=my-service
  • metadata.namespace!=default
  • status.phase=Pending

다음의 kubectl 커맨드는 status.phase 필드의 값이 Running 인 모든 파드를 선택한다.

kubectl get pods --field-selector status.phase=Running
참고: 필드 셀렉터는 본질적으로 리소스 필터 이다. 기본적으로 적용되는 셀렉터나 필드는 없으며, 이는 명시된 종류의 모든 리소스가 선택된다는 것을 의미한다. 여기에 따라오는 kubectl 쿼리인 kubectl get pods  kubectl get pods --field-selector "" 는 동일하다.

사용 가능한 필드

사용 가능한 필드는 쿠버네티스의 리소스 종류에 따라서 다르다. 모든 리소스 종류는 metadata.name  metadata.namespace 필드 셀렉터를 사용할 수 있다. 사용할 수 없는 필드 셀렉터를 사용하면 다음과 같이 에러를 출력한다.

kubectl get ingress --field-selector foo.bar=baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"

사용 가능한 연산자

필드 셀렉터에서 =, ==, != 연산자를 사용할 수 있다 (=와 ==는 동일한 의미이다). 예를 들면, 다음의 kubectl 커맨드는 default 네임스페이스에 속해있지 않은 모든 쿠버네티스 서비스를 선택한다.

kubectl get services  --all-namespaces --field-selector metadata.namespace!=default

연계되는 셀렉터

레이블을 비롯한 다른 셀렉터처럼 쉼표(,)로 구분되는 목록을 통해 필드 셀렉터를 연계해서 사용할 수 있다. 다음의 kubectl 커맨드는 status.phase 필드가 Running 이 아니고, spec.restartPolicy 필드가 Always 인 모든 파드를 선택한다.

kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

여러 개의 리소스 종류

필드 셀렉터를 여러 개의 리소스 종류에 걸쳐 사용할 수 있다. 다음의 kubectl 커맨드는 default 네임스페이스에 속해있지 않은 모든 스테이트풀셋(StatefulSet)과 서비스를 선택한다.

kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default

'플랫폼 > kubernetes' 카테고리의 다른 글

쿠버네티스 노드  (0) 2022.07.15
쿠버네티스 권장 레이블  (0) 2022.07.13
쿠버네티스 어노테이션  (0) 2022.07.13
쿠버네티스 레이블, 셀렉터  (0) 2022.07.12
쿠버네티스 네임스페이스  (0) 2022.07.12

쿠버네티스 어노테이션을 사용하여 임의의 비식별 메타데이터를 오브젝트에 첨부할 수 있다. 도구 및 라이브러리와 같은 클라이언트는 이 메타데이터를 검색할 수 있다.

오브젝트에 메타데이터 첨부

레이블이나 어노테이션을 사용하여 쿠버네티스 오브젝트에 메타데이터를 첨부할 수 있다. 레이블을 사용하여 오브젝트를 선택하고, 특정 조건을 만족하는 오브젝트 컬렉션을 찾을 수 있다. 반면에, 어노테이션은 오브젝트를 식별하고 선택하는데 사용되지 않는다. 어노테이션의 메타데이터는 작거나 크고, 구조적이거나 구조적이지 않을 수 있으며, 레이블에서 허용되지 않는 문자를 포함할 수 있다.

어노테이션은 레이블과 같이 키/값 맵이다.

"metadata": {
  "annotations": {
    "key1" : "value1",
    "key2" : "value2"
  }
}
참고: 맵의 키와 값은 문자열이어야 한다. 다르게 말해서, 숫자, 불리언(boolean), 리스트 등의 다른 형식을 키나 값에 사용할 수 없다.

다음은 어노테이션에 기록할 수 있는 정보의 예제이다.

  • 필드는 선언적 구성 계층에 의해 관리된다. 이러한 필드를 어노테이션으로 첨부하는 것은 클라이언트 또는 서버가 설정한 기본 값, 자동 생성된 필드, 그리고 오토사이징 또는 오토스케일링 시스템에 의해 설정된 필드와 구분된다.
  • 빌드, 릴리스, 또는 타임 스탬프, 릴리스 ID, git 브랜치, PR 번호, 이미지 해시 및 레지스트리 주소와 같은 이미지 정보.
  • 로깅, 모니터링, 분석 또는 감사 리포지터리에 대한 포인터.
  • 디버깅 목적으로 사용될 수 있는 클라이언트 라이브러리 또는 도구 정보: 예를 들면, 이름, 버전, 그리고 빌드 정보.
  • 다른 생태계 구성 요소의 관련 오브젝트 URL과 같은 사용자 또는 도구/시스템 출처 정보.
  • 경량 롤아웃 도구 메타데이터. 예: 구성 또는 체크포인트
  • 책임자의 전화번호 또는 호출기 번호, 또는 팀 웹 사이트 같은 해당 정보를 찾을 수 있는 디렉터리 진입점.
  • 행동을 수정하거나 비표준 기능을 수행하기 위한 최종 사용자의 지시 사항.

어노테이션을 사용하는 대신, 이 유형의 정보를 외부 데이터베이스 또는 디렉터리에 저장할 수 있지만, 이는 배포, 관리, 인트로스펙션(introspection) 등을 위한 공유 클라이언트 라이브러리와 도구 생성을 훨씬 더 어렵게 만들 수 있다.

문법과 캐릭터 셋

어노테이션은 키/값 쌍이고 유효한 어노테이션 키에는 두 개의 세그먼트가 있다. 두 개의 세그먼트는 선택적인 접두사와 이름(name)이며, 슬래시(/)로 구분된다. 이름 세그먼트는 필수이며, 영문 숫자([a-z0-9A-Z])로 시작하고 끝나는 63자 이하이어야 하고, 사이에 대시(-), 밑줄(_), 점(.)이 들어갈 수 있다. 접두사는 선택적이다. 지정된 경우, 접두사는 DNS 서브도메인이어야 한다. 점(.)으로 구분된 일련의 DNS 레이블은 총 253자를 넘지 않고, 뒤에 슬래시(/)가 붙는다.

접두사가 생략되면 어노테이션 키는 사용자에게 비공개로 간주된다. 최종 사용자 오브젝트에 어노테이션을 추가하는 자동화된 시스템 구성 요소(예 :kube-scheduler, kube-controller-manager, kube-apiserver, kubectl, 또는 다른 써드파티 자동화)는 접두사를 지정해야 한다.

kubernetes.io/와 k8s.io/ 접두사는 쿠버네티스 핵심 구성 요소를 위해 예약되어 있다.

다음은 imageregistry: https://hub.docker.com/ 어노테이션이 있는 파드의 구성 파일 예시이다.


apiVersion: v1
kind: Pod
metadata:
  name: annotations-demo
  annotations:
    imageregistry: "https://hub.docker.com/"
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

'플랫폼 > kubernetes' 카테고리의 다른 글

쿠버네티스 권장 레이블  (0) 2022.07.13
쿠버네티스 필드 셀렉터  (0) 2022.07.13
쿠버네티스 레이블, 셀렉터  (0) 2022.07.12
쿠버네티스 네임스페이스  (0) 2022.07.12
쿠버네티스 오브젝트 이름, ID  (0) 2022.07.12

레이블은 파드와 같은 오브젝트에 첨부된 키와 값의 쌍이다. 레이블은 오브젝트의 특성을 식별하는 데 사용되어 사용자에게 중요하지만, 코어 시스템에 직접적인 의미는 없다. 레이블로 오브젝트의 하위 집합을 선택하고, 구성하는데 사용할 수 있다. 레이블은 오브젝트를 생성할 때에 붙이거나 생성 이후에 붙이거나 언제든지 수정이 가능하다. 오브젝트마다 키와 값으로 레이블을 정의할 수 있다. 오브젝트의 키는 고유한 값이어야 한다.

"metadata": {
  "labels": {
    "key1" : "value1",
    "key2" : "value2"
  }
}

레이블은 UI 와 CLI 에서 효율적인 쿼리를 사용하고 검색에 사용하기에 적합하다. 식별되지 않는 정보는 어노테이션으로 기록해야 한다.

사용 동기

레이블을 이용하면 사용자가 느슨하게 결합한 방식으로 조직 구조와 시스템 오브젝트를 매핑할 수 있으며, 클라이언트에 매핑 정보를 저장할 필요가 없다.

서비스 배포와 배치 프로세싱 파이프라인은 흔히 다차원의 엔티티들이다(예: 다중 파티션 또는 배포, 다중 릴리스 트랙, 다중 계층, 계층 속 여러 마이크로 서비스들). 관리에는 크로스-커팅 작업이 필요한 경우가 많은데 이 작업은 사용자보다는 인프라에 의해 결정된 엄격한 계층 표현인 캡슐화를 깨트린다.

레이블 예시:

  • "release" : "stable", "release" : "canary"
  • "environment" : "dev", "environment" : "qa", "environment" : "production"
  • "tier" : "frontend", "tier" : "backend", "tier" : "cache"
  • "partition" : "customerA", "partition" : "customerB"
  • "track" : "daily", "track" : "weekly"

이 예시는 일반적으로 사용하는 레이블이며, 사용자는 자신만의 규칙(convention)에 따라 자유롭게 개발할 수 있다. 오브젝트에 붙여진 레이블 키는 고유해야 한다는 것을 기억해야 한다.

구문과 캐릭터 셋

레이블은 키와 값의 쌍이다. 유효한 레이블 키에는 슬래시(/)로 구분되는 선택한 접두사와 이름이라는 2개의 세그먼트가 있다. 이름 세그먼트는 63자 미만으로 시작과 끝은 알파벳과 숫자([a-z0-9A-Z])이며, 대시(-), 밑줄(_), 점(.)과 함께 사용할 수 있다. 접두사는 선택이다. 만약 접두사를 지정한 경우 접두사는 DNS의 하위 도메인으로 해야 하며, 점(.)과 전체 253자 이하, 슬래시(/)로 구분되는 DNS 레이블이다.

접두사를 생략하면 키 레이블은 개인용으로 간주한다. 최종 사용자의 오브젝트에 자동화된 시스템 컴포넌트(예: kube-scheduler, kube-controller-manager, kube-apiserver, kubectl 또는 다른 타사의 자동화 구성 요소)의 접두사를 지정해야 한다.

kubernetes.io/와 k8s.io/ 접두사는 쿠버네티스의 핵심 컴포넌트로 예약되어 있다.

유효한 레이블 값은 다음과 같다.

  • 63 자 이하여야 하고 (공백일 수도 있음),
  • (공백이 아니라면) 시작과 끝은 알파벳과 숫자([a-z0-9A-Z])이며,
  • 알파벳과 숫자, 대시(-), 밑줄(_), 점(.)을 중간에 포함할 수 있다.

다음의 예시는 파드에 environment: production  app: nginx 2개의 레이블이 있는 구성 파일이다.


apiVersion: v1
kind: Pod
metadata:
  name: label-demo
  labels:
    environment: production
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

레이블 셀렉터

이름과 UID 와 다르게 레이블은 고유하지 않다. 일반적으로 우리는 많은 오브젝트에 같은 레이블을 가질 것으로 예상한다.

레이블 셀렉터를 통해 클라이언트와 사용자는 오브젝트를 식별할 수 있다. 레이블 셀렉터는 쿠버네티스 코어 그룹의 기본이다.

API 는 현재 일치성 기준  집합성 기준 이라는 두 종류의 셀렉터를 지원한다. 레이블 셀렉터는 쉼표로 구분된 다양한 요구사항에 따라 만들 수 있다. 다양한 요구사항이 있는 경우 쉼표 기호가 AND(&&) 연산자로 구분되는 역할을 하도록 해야 한다.

비어있거나 지정되지 않은 셀렉터는 상황에 따라 달라진다. 셀렉터를 사용하는 API 유형은 유효성과 의미를 문서화해야 한다.

참고: 레플리카셋(ReplicaSet)과 같은 일부 API 유형에서 두 인스턴스의 레이블 셀렉터는 네임스페이스 내에서 겹치지 않아야 한다. 그렇지 않으면 컨트롤러는 상충하는 명령으로 보고, 얼마나 많은 복제본이 필요한지 알 수 없다.
주의: 일치성 기준과 집합성 기준 조건 모두에 대해 논리적인 OR (||) 연산자가 없다. 필터 구문이 적절히 구성되어 있는지 확인해야 한다.

일치성 기준 요건

일치성 기준 또는 불일치 기준 의 요구사항으로 레이블의 키와 값의 필터링을 허용한다. 일치하는 오브젝트는 추가 레이블을 가질 수 있지만, 레이블의 명시된 제약 조건을 모두 만족해야 한다. =,==,!= 이 세 가지 연산자만 허용한다. 처음 두 개의 연산자의 일치성(그리고 동의어), 나머지는 불일치 를 의미한다. 예를 들면,

environment = production
tier != frontend

전자는 environment 를 키로 가지는 것과 production 을 값으로 가지는 모든 리소스를 선택한다. 후자는 tier 를 키로 가지고, 값을 frontend 를 가지는 리소스를 제외한 모든 리소스를 선택하고, tier 를 키로 가지며 값을 공백으로 가지는 모든 리소스를 선택한다. environment=production,tier!=frontend 처럼 쉼표를 통해 한 문장으로 frontend 를 제외한 production 을 필터링할 수 있다.

일치성 기준 레이블 요건에 대한 하나의 이용 시나리오는 파드가 노드를 선택하는 기준을 지정하는 것이다. 예를 들어, 아래 샘플 파드는 "accelerator=nvidia-tesla-p100" 레이블을 가진 노드를 선택한다.

apiVersion: v1
kind: Pod
metadata:
  name: cuda-test
spec:
  containers:
    - name: cuda-test
      image: "k8s.gcr.io/cuda-vector-add:v0.1"
      resources:
        limits:
          nvidia.com/gpu: 1
  nodeSelector:
    accelerator: nvidia-tesla-p100

집합성 기준 요건

집합성 기준 레이블 요건에 따라 값 집합을 키로 필터링할 수 있다. in, notin과 exists(키 식별자만 해당)의 3개의 연산자를 지원한다. 예를 들면,

environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
  • (in) 첫 번째 예시에서 키가 environment이고 값이 production 또는 qa 인 모든 리소스를 선택한다.
  • (notion) 두 번째 예시에서 키가 tier 이고 값이 frontend 와 backend 를 가지는 리소스를 제외한 모든 리소스와 키로 tier 를 가지고 값을 공백으로 가지는 모든 리소스를 선택한다.
  • (exists) 세 번째 예시에서 레이블의 값에 상관없이 키가 partition 을 포함하는 모든 리소스를 선택한다.
  • (non-exists) 네 번째 예시에서 레이블의 값에 상관없이 키가 partition 을 포함하지 않는 모든 리소스를 선택한다.

마찬가지로 쉼표는 AND 연산자로 작동한다. 따라서 partition,environment notin (qa)와 같이 사용하면 값과 상관없이 키가 partition인 것과 키가 environment이고 값이 qa와 다른 리소스를 필터링할 수 있다. 집합성 기준 레이블 셀렉터는 일반적으로 environment=production과 environment in (production)을 같은 것으로 본다. 유사하게는 !=과 notin을 같은 것으로 본다.

집합성 기준 요건은 일치성 기준 요건과 조합해서 사용할 수 있다. 예를 들어 partition in (customerA, customerB),environment!=qa 가 있다.

API

LIST와 WATCH 필터링

LIST와 WATCH 작업은 쿼리 파라미터를 사용해서 반환되는 오브젝트 집합을 필터링하기 위해 레이블 셀렉터를 지정할 수 있다. 다음의 두 가지 요건 모두 허용된다(URL 쿼리 문자열을 그대로 표기함).

  • 일치성 기준 요건: ?labelSelector=environment%3Dproduction,tier%3Dfrontend
  • 집합성 기준 요건: ?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29

두 가지 레이블 셀렉터 스타일은 모두 REST 클라이언트를 통해 선택된 리소스를 확인하거나 목록을 볼 수 있다. 예를 들어, kubectl로 apiserver 를 대상으로 일치성 기준 으로 하는 셀렉터를 다음과 같이 이용할 수 있다.

kubectl get pods -l environment=production,tier=frontend

또는 집합성 기준 요건을 사용하면

kubectl get pods -l 'environment in (production),tier in (frontend)'

앞서 안내한 것처럼 집합성 기준 요건은 더 보여준다. 예시에서 다음과 같이 OR 연산자를 구현할 수 있다.

kubectl get pods -l 'environment in (production, qa)'

또는 exists 연산자에 불일치한 것으로 제한할 수 있다.

kubectl get pods -l 'environment,environment notin (frontend)'

API 오브젝트에서 참조 설정

services  replicationcontrollers 와 같은 일부 쿠버네티스 오브젝트는 레이블 셀렉터를 사용해서 파드와 같은 다른 리소스 집합을 선택한다.

서비스와 레플리케이션 컨트롤러

services 에서 지정하는 파드 집합은 레이블 셀렉터로 정의한다. 마찬가지로 replicationcontrollers 가 관리하는 파드의 오브젝트 그룹도 레이블 셀렉터로 정의한다.

서비스와 레플리케이션 컨트롤러의 레이블 셀렉터는 json 또는 yaml 파일에 매핑된 일치성 기준 요구사항의 셀렉터만 지원한다.

"selector": {
    "component" : "redis",
}

or

selector:
    component: redis

json 또는 yaml 서식에서 셀렉터는 component=redis 또는 component in (redis) 모두 같은 것이다.

세트-기반 요건을 지원하는 리소스

Job, Deployment, ReplicaSet 그리고 DaemonSet 같은 새로운 리소스들은 집합성 기준 의 요건도 지원한다.

selector:
  matchLabels:
    component: redis
  matchExpressions:
    - {key: tier, operator: In, values: [cache]}
    - {key: environment, operator: NotIn, values: [dev]}

matchLabels 는 {key,value} 의 쌍과 매칭된다. matchLabels 에 매칭된 단일 {key,value} 는 matchExpressions의 요소와 같으며 key 필드는 "key"로, operator는 "In" 그리고 values에는 "value"만 나열되어 있다. matchExpressions 는 파드 셀렉터의 요건 목록이다. 유효한 연산자에는 In, NotIn, Exists 및 DoNotExist 가 포함된다. In 및 NotIn 은 설정된 값이 있어야 한다. matchLabels와 matchExpressions 모두 AND로 되어 있어 일치하기 위해서는 모든 요건을 만족해야 한다.

노드 셋 선택

레이블을 통해 선택하는 사용 사례 중 하나는 파드를 스케줄 할 수 있는 노드 셋을 제한하는 것이다. 자세한 내용은 노드 선택 문서를 참조한다.

'플랫폼 > kubernetes' 카테고리의 다른 글

쿠버네티스 필드 셀렉터  (0) 2022.07.13
쿠버네티스 어노테이션  (0) 2022.07.13
쿠버네티스 네임스페이스  (0) 2022.07.12
쿠버네티스 오브젝트 이름, ID  (0) 2022.07.12
쿠버네티스 오브젝트 관리  (0) 2022.07.12

+ Recent posts