사전 kubelet
구현체

kubelet

gabury1

kubelet 은 쿠버네티스에서 노드마다 하나씩 도는 프로그램입니다. 이 노드에 무엇이 떠 있어야 하는지를 받아서 그대로 맞춥니다. 컨테이너를 직접 실행하지는 않습니다. 그 일은 컨테이너 런타임에 넘깁니다.

상세

쿠버네티스 커맨드라인 레퍼런스는 kubelet 을 각 노드에서 도는 주 노드 에이전트라고 적습니다. 구성요소 문서는 노드 구성요소를 "모든 노드에서 돌면서 돌고 있는 파드를 유지하고 쿠버네티스 런타임 환경을 제공하는 것" 으로 묶습니다. 그 묶음 안에서 kubelet 의 몫은 한 줄입니다. 파드가 컨테이너까지 포함해 돌고 있도록 보장하는 일입니다. 같은 묶음에 컨테이너 런타임이 함께 들어갑니다. 선택인 kube-proxy 도 같은 묶음입니다.

kubelet 은 PodSpec 단위로 일합니다. PodSpec 은 파드 하나를 기술하는 YAML(YAML Ain't Markup Language) 또는 JSON(JavaScript Object Notation) 객체입니다. kubelet 은 여러 경로로 들어온 PodSpec 묶음을 받습니다. 그리고 거기 적힌 컨테이너들이 돌고 있고 건강한 상태가 되도록 보장합니다. 무엇을 띄울지는 이 명세가 정하고, kubelet 은 실제 상태를 거기에 맞추는 쪽입니다.

PodSpec 이 들어오는 세 경로

주된 경로는 kube-apiserver 입니다. 레퍼런스는 그 밖에 컨테이너 매니페스트를 kubelet 에 줄 수 있는 방법이 둘 더 있다고 적습니다.

경로 어떻게 주나 주기
kube-apiserver 주된 경로 —
파일 명령줄 플래그로 경로를 넘긴다. 그 경로 아래 파일들이 갱신되는지 주기적으로 감시한다 기본 20초. 플래그로 바꾼다
HTTP(HyperText Transfer Protocol) 엔드포인트 명령줄 파라미터로 엔드포인트를 넘긴다 20초마다 확인한다. 이것도 플래그로 바꾼다
flowchart TD
    S1["kube-apiserver"] --> K["kubelet"]
    S2["파일 경로"] --> K
    S3["HTTP 엔드포인트"] --> K
    K --> R["컨테이너 런타임"]
    K -->|노드 상태| S1

노드 등록

kubelet 은 노드를 kube-apiserver 에 등록할 수 있습니다. 노드 이름은 셋 중 하나로 정합니다. 호스트네임, 호스트네임을 덮어쓰는 플래그, 클라우드 제공자용 로직입니다.

--register-node 플래그가 참이면 kubelet 이 스스로 등록을 시도합니다. 이 값이 기본입니다. Nodes 문서는 이것을 선호되는 방식이라 적습니다. 대부분의 배포판이 이렇게 쓴다고 덧붙입니다. 자기 등록에는 옵션 몇 개가 딸립니다. --kubeconfig 는 kube-apiserver 에 자신을 인증할 크리덴셜 경로입니다. --cloud-provider 는 자기 메타데이터를 읽으러 클라우드 제공자와 어떻게 이야기할지 정합니다. --register-with-taints 는 주어진 테인트 목록을 달아 노드를 등록합니다. --node-status-update-frequency 는 kubelet 이 노드 상태를 kube-apiserver 에 얼마나 자주 올릴지 정합니다.

포기한 것

쿠버네티스가 만들지 않은 컨테이너

레퍼런스가 문장으로 못 박습니다. kubelet 은 쿠버네티스가 만들지 않은 컨테이너를 관리하지 않습니다. 같은 노드에서 손으로 띄운 컨테이너가 돌고 있어도 kubelet 의 관리 대상 밖입니다. 그 대신 관리 범위가 PodSpec 으로 들어온 것에 한정됩니다.

컨테이너를 직접 실행하는 일

컨테이너를 실제로 띄우는 일은 컨테이너 런타임이 합니다. 그 사이를 잇는 것이 CRI(Container Runtime Interface, 컨테이너 런타임 인터페이스)입니다. CRI 는 플러그인 인터페이스입니다. kubelet 이 넓은 범위의 컨테이너 런타임을 쓸 수 있게 합니다. 클러스터 구성요소를 다시 컴파일할 필요도 없어집니다. kubelet 이 파드와 그 컨테이너를 띄우려면 클러스터의 각 노드에 동작하는 컨테이너 런타임이 있어야 합니다. 런타임에 붙을 때 kubelet 쪽이 클라이언트입니다. 런타임과 이미지 서비스 엔드포인트는 --container-runtime-endpoint 명령줄 플래그로 따로 지정할 수 있습니다.

이 위임에는 값이 붙습니다. 쿠버네티스 v1.26 이후로 kubelet 은 컨테이너 런타임이 v1 CRI API(Application Programming Interface, 응용 프로그램 인터페이스)를 지원할 것을 요구합니다. 런타임이 v1 API 를 지원하지 않으면 kubelet 은 노드를 등록하지 않습니다.

어느 노드에 띄울지 정하는 일

파드를 어느 노드에 얹을지는 kubelet 이 고르지 않습니다. 구성요소 문서는 그 일을 컨트롤 플레인 쪽 kube-scheduler 의 몫으로 적습니다. kube-scheduler 는 아직 노드에 묶이지 않은 파드를 찾아서 각 파드를 적합한 노드에 배정합니다.

권한도 자기 노드 쪽으로 좁혀둘 수 있습니다. Node 인가 모드와 NodeRestriction 승인 플러그인이 켜져 있으면 kubelet 은 자기 자신의 Node 리소스만 만들거나 고칠 권한을 갖습니다.

스왑이 켜진 노드

KubeletConfiguration 레퍼런스의 failSwapOn 은 노드에 스왑이 켜져 있으면 kubelet 이 시작에 실패하도록 지시하는 값입니다. 기본값이 true 입니다. 컨테이너 워크로드가 쓸 스왑 메모리는 memorySwap 이 따로 설정합니다. 그 안의 swapBehavior 는 "" 또는 "NoSwap" 일 때 워크로드가 스왑을 쓸 수 없게 합니다. 이것이 기본 선택지입니다. "LimitedSwap" 으로 두면 워크로드의 스왑 사용이 제한됩니다. 그때의 스왑 한도는 컨테이너의 메모리 요청에 비례합니다.

예시

정적 파드 매니페스트

kubelet 설정 파일의 staticPodPath 필드에 디렉토리를 적어두면 kubelet 이 그 디렉토리를 주기적으로 훑습니다. YAML 이나 JSON 파일이 나타나고 사라지는 대로 정적 파드를 만들고 지웁니다. 점으로 시작하는 파일은 훑을 때 무시합니다.

작업 문서가 싣는 최소 예는 웹 서버 하나입니다. 먼저 정적 파드를 돌릴 노드를 고릅니다. 예에 쓰인 노드는 my-node1 입니다. 거기에 접속해 디렉토리 하나를 정합니다. 문서가 드는 자리는 /etc/kubernetes/manifests 입니다.

터미널
# Run this command on the node where kubelet is running
mkdir -p /etc/kubernetes/manifests/
cat <<EOF >/etc/kubernetes/manifests/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    role: myrole
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
EOF

이 파일이 그 디렉토리에 나타나면 kubelet 이 그것을 보고 파드를 만듭니다. 같은 일을 명령줄로 시키는 방법이 하나 더 있습니다. kubelet 을 --pod-manifest-path=/etc/kubernetes/manifests/ 인자와 함께 시작하는 것입니다. 문서는 이쪽을 대안이자 폐기된 방법이라고 적습니다. 이 작업 문서 자체는 CRI-O 와 Fedora 를 기준으로 쓰였습니다.

KubeletConfiguration 파일

kubelet 설정 파라미터의 일부는 명령줄 플래그 대신 디스크의 설정 파일로 줄 수 있습니다. 문서는 설정 파일로 주는 쪽을 권합니다. 노드 배포와 설정 관리가 단순해지기 때문이라고 적습니다.

YAML
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: "192.168.0.8"
port: 20250
serializeImagePulls: false
evictionHard:
  memory.available: "100Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "15%"
  imagefs.inodesFree: "5%"

port 가 이 kubelet 이 서비스할 포트입니다. evictionHard 아래 다섯 줄이 하드 축출 임계값입니다. 이 파일을 물리려면 kubelet 을 --config 플래그에 이 파일 경로를 주어 시작합니다. 그러면 kubelet 이 여기서 설정을 읽습니다. 같은 값을 겨냥하는 명령줄 플래그가 있으면 그 플래그가 파일의 값을 덮어씁니다.

운영

노드 압박 축출

kubelet 은 축출 신호 다섯 개를 씁니다.

신호 무엇으로 계산하나
memory.available node.status.capacity[memory] 에서 node.stats.memory.workingSet 을 뺀 값
nodefs.available node.stats.fs.available
nodefs.inodesFree node.stats.fs.inodesFree
imagefs.available node.stats.runtime.imagefs.available
imagefs.inodesFree node.stats.runtime.imagefs.inodesFree

기본 하드 축출 임계값은 이렇습니다. 리눅스 노드에서 memory.available<100Mi, 윈도우 노드에서 memory.available<500Mi 입니다. 그 밖에 nodefs.available<10% 와 imagefs.available<15% 가 있습니다. 리눅스 노드에는 nodefs.inodesFree<5% 와 imagefs.inodesFree<5% 가 더 붙습니다. 문서는 이 기본값들이 파라미터를 하나도 바꾸지 않았을 때만 설정된다고 적습니다.

cgroup 드라이버

kubelet 과 그 아래 컨테이너 런타임은 둘 다 컨트롤 그룹과 맞물려야 합니다. 파드와 컨테이너의 자원 관리를 강제하고 CPU(Central Processing Unit, 중앙 처리 장치)·메모리 요청과 한도 같은 자원을 설정하기 위해서입니다. 이 맞물림에 쓰이는 것이 cgroup 드라이버입니다. 문서는 kubelet 과 컨테이너 런타임이 같은 cgroup 드라이버를 쓰고 같게 설정되는 것이 결정적이라고 적습니다.

systemd 는 cgroup 과 긴밀하게 통합돼 있습니다. systemd 유닛마다 cgroup 을 하나씩 할당합니다. init 시스템으로는 systemd 를 쓰는 노드를 생각해 봅니다. 여기서 드라이버로 cgroupfs 를 쓰면 시스템에 cgroup 관리자가 둘 생깁니다. 관리자가 둘이면 시스템의 가용 자원과 사용 중인 자원에 대한 시야도 둘이 됩니다. 문서는 kubelet 과 컨테이너 런타임에는 cgroupfs 를 쓰고 나머지 프로세스에는 systemd 를 쓰도록 구성된 노드가 자원 압박 아래에서 불안정해지는 경우가 있다고 적습니다.

kube-apiserver 와의 버전 스큐

kubelet 은 kube-apiserver 보다 새로우면 안 됩니다. 반대쪽으로는 kube-apiserver 보다 최대 세 마이너 판까지 뒤처져도 됩니다. 1.25 미만의 kubelet 은 두 마이너 판까지만 뒤처질 수 있습니다. 문서가 드는 예는 kube-apiserver 가 1.36 일 때입니다. 이때 지원되는 kubelet 은 1.36, 1.35, 1.34, 1.33 입니다. 고가용성 클러스터에서 kube-apiserver 인스턴스끼리 판이 어긋나 있으면 허용 되는 kubelet 판의 폭이 그만큼 좁아집니다.

포트와 인증·인가 기본값

kubelet 이 서비스할 포트는 --port 로 정하고 기본값은 10250 입니다. 인증도 인가도 없이 읽기만 되는 포트가 따로 있습니다. --read-only-port 이고 기본값은 10255 입니다. 0 으로 두면 끕니다. 레퍼런스는 이 두 플래그 모두 폐기 예정이라고 표시합니다. --config 로 지정하는 설정 파일에서 값을 정하라고 적습니다.

기본값이 무엇을 열어두는지가 이 자리에서 제일 먼저 볼 것입니다. --anonymous-auth 의 기본값은 true 입니다. kubelet 의 HTTPS(HyperText Transfer Protocol Secure) 엔드포인트로 온 요청 가운데 다른 인증 방법에서 거부되지 않은 것은 익명 요청으로 다뤄집니다. 익명 요청에는 사용자 이름 system:anonymous 와 그룹 system:unauthenticated 가 붙습니다. 익명 접근을 끄고 인증되지 않은 요청에 401 Unauthorized 를 돌려주려면 kubelet 을 --anonymous-auth=false 플래그로 시작합니다.

인증을 통과한 요청은 그다음 인가를 받습니다. 익명 요청도 포함해서입니다. --authorization-mode 의 기본값은 AlwaysAllow 입니다. 이 모드는 모든 요청을 허용합니다.

관련 항목

컨테이너 실행을 넘기는 상대와 접속 방식

컨테이너 런타임 · 컨테이너 런타임 인터페이스 · CRI-O · 플러그인 · 인터페이스

kubelet이 노드에서 실행 환경과 자원 통제를 함께 맞추는 대상

kube-proxy · cgroup · cgroupfs · systemd · CPU · 워크로드

kubelet이 노드를 등록할 때 자신을 증명하는 자격

kubeconfig · 인증 · 크리덴셜 · 클라우드 · 메타데이터

kubelet이 apiserver를 상대할 때 지키는 조건

kube-apiserver · 노드 인가 모드 · NodeRestriction 승인 플러그인 · TokenReview API · SubjectAccessReview API · 권한 · 인가 · 리소스 · 버전 스큐 · 고가용성

kubelet과 역할을 나눠 맡는 컨트롤 플레인 구성 요소

kube-scheduler · kube-controller-manager · cloud-controller-manager

kubelet이 속하는 상위 체계

Kubernetes · 노드 · 클러스터

kubelet이 다루는 대상

파드 · PodSpec · 정적 파드 · KubeletConfiguration · 테인트 · 노드 압박 축출 · 축출

kubelet이 PodSpec을 주고받을 때 쓰는 형식과 통신 수단

YAML · JSON · HTTP · HTTPS · API · 엔드포인트

다른 이름: 큐블릿 · node agent