kubelet
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 설정 파라미터의 일부는 명령줄 플래그 대신 디스크의 설정 파일로 줄 수 있습니다. 문서는 설정 파일로 주는 쪽을 권합니다. 노드 배포와 설정 관리가 단순해지기 때문이라고 적습니다.
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을 주고받을 때 쓰는 형식과 통신 수단
다른 이름: 큐블릿 · node agent