Kubernetes Static Pods, 제대로 이해하기
본 포스팅에서는 Kubernetes의 Static Pod의 개념을 이해하고 생성, 수정 및 삭제할 수 있도록 학습하는 목표를 가집니다.
🔗 Kubernetes Series
모든 Kubernetes 시리즈를 확인하시려면 위를 참고해 주세요.
쿠버네티스의 Static Pod에 대해서 알아보도록 하겠습니다.
Static Pods
일반적인 Pod는 주로 Deployment, StatefulSet, DaemonSet 등의 컨트롤러를 통해 생성되고 관리됩니다.
또, 생성된 리소스는 Kubernetes API 서버를 통해 정의되고 관리됩니다.
정적 Pod(이하 Static Pod)는 API 서버의 관여없이 특정 노드에서 kubelet 데몬에 의해 직접 관리됩니다.
컨트롤 플레인에 의해 관리되는 일반 Pod와 달리,
kubelet이 각 Static Pod를 관찰하고 실패하면 재실행시킵니다.
Regular Pod vs. Static Pod
일반 Pod과 Static Pod의 차이점을 조금 더 살펴보도록 하겠습니다.
먼저 관리 주체가 다릅니다.
✔️ Regular Pod
일반 Pod는 API 서버에 의해 관리되고, 관리를 위한 데이터가 etcd에 저장됩니다.
따라서 kubectl 같은 명령어를 통해 쉽게 조회, 수정, 삭제가 가능합니다.
일반 Pod의 경우, kubelet은 kube-apiserver에 의존하여 해당 kubelet이 위치한 노드에 어떤 Pod를 배치할지 지시를 받습니다.
이 지시는 kube-scheduler의 판단에 따라 결정되고, 이후 데이터 저장소에 저장됩니다.
✔️ Static Pod
Static Pod는 API 서버와 독립적으로 동작합니다.
kubelet은 Static Pod를 감지하고 생성하지만, Static Pod의 정보를 따로 저장하지 않습니다.
대신, API 서버는 "Mirror Pod"라는 형태로 조회할 수 있게 합니다.
kubelet는 각 Static Pod에 해당하는 Mirror Pod를 Kubernetes API에 생성을 시도합니다.
그래서 Etcd에 저장되어 있지 않아도,
kube-apiserver API 나 kubectl 명령어를 통해 Static Pod 정보를 확인할 수 있습니다.
즉, kube-apiserver API에서 조회는 할 수 있어도 mirror 객체이기 때문에 그 어떤 제어는 불가능합니다.
Static Pod는 항상 특정 노드의 하나의 Kubelet에 바인딩됩니다.
Static Pod 이름은 특정한 규칙이 있는데요.
해당 ≪static_pod_name≫-≪node_name≫
으로 생성됩니다.
자세한 내용은 마지막 섹션 Regular Pods? Mirror Pods? 을 참고해주세요.
Usage
독립적인 Pod를 띄우고자 할 때 Static Pod를 사용하기 때문에,
두 종류의 Pod는 사용 목적이 다릅니다.
✔️ Regular Pod
일반 Pod는 애플리케이션 배포, 스케일링, 업데이트 등의 일반적인 Kubernetes 작업에 사용됩니다.
✔️ Static Pod
Static Pod는 주로 클러스터 부팅 과정에서 필수적인 컴포넌트를 실행할 때 사용됩니다.
가령, etcd 이나 kube-apiserver 등이 있죠.
각 노드에 필수적으로 존재해야 하는 시스템 컴포넌트를 실행하는 데 적합합니다.
만약, Master 없을 때 단일 Node가 독립적으로 실행될 수 있을까요?
kube-apiserver, kube-scheduler, controllers, etcd cluster 등 리소스를 관리할 컨트롤 플레인이 없을 때, 가능할까요?
결론적으로 말씀드리면,
네, 하나의 Node가 독립적으로 실행될 수 있습니다.
How Static Pod Work?
kubelet 데몬으로 실행되기 때문에 노드를 독립적으로 관리할 수 있습니다.
그러나 Pod 상세 데이터를 제공해줄 API 서버가 없습니다.
어떻게 Pod를 생성 할 수 있을까요?
kube-apiserver 없이 Pod 정의 파일을 전달하는 방법은,
kubelet이 Pod 상세 정보를 파일에서 읽어오게 설정할 수 있습니다.
즉, Pod에 관한 정보를 저장하는 서버 디렉터리에 관리하고,
kubelet을 설정하면 해당 Pod 정의 파일을 읽을 수 있습니다.
kubelet은 주기적으로 특정 디렉터리 하위의 파일을 읽고 Pod를 생성하며, Pod가 죽지 않도록 보장합니다.
특정 디렉터리는 아래 Designated Directory 섹션에서 계속 설명합니다.
앱이 고장 나면 kubelet이 재시작을 시도합니다.
디렉터리 내 파일이 변경되면 kubelet이 Pod를 재생성하여 변경 사항을 적용합니다.
파일을 제거하면 해당 Static Pod가 자동으로 삭제됩니다.
API 서버나 쿠버네티스 클러스터 구성 요소의 간섭 없이,
kubelet이 스스로 만든 Pod를 정적 Pod라고 합니다.
kubelet은 오직 Pod에 대한 내용만 알기 때문에,
ReplicaSet, Deployment, Service를 통해 배치될 수 없고,
지정된 디렉토리에 정의 파일을 배치하는 방식으로만 Pod를 만들 수 있습니다.
Designated Directory
그렇다면, kubelet이 Static Pod를 생성하기 위해 참조하는 폴더는 어디에 존재하며 어떻게 구성할까요?
Static Pod 의 Manifest (이하 매니페스트) 파일들을 관리하는 폴더는
기본적으로 /etc/kubernetes/manifests
폴더로 설정되어 있습니다.
여기서 매니페스트 파일이란, 특정 디렉터리에 있는 JSON 이나 YAML 형식의 표준 Pod 정의를 의미합니다.
가령, 아래와 같이 Control Plane 컴포넌트 중,
기본적으로 Static Pod 로 띄우는 파일들이 저장되어 있음을 확인할 수 있습니다.
controlplane ~ ➜ ll /etc/kubernetes/manifests
total 28
drwxrwxr-x 1 root root 4096 Jul 10 13:30 ./
drwxrwxr-x 1 root root 4096 Jul 10 13:30 ../
-rw------- 1 root root 2400 Jul 10 13:30 etcd.yaml
-rw------- 1 root root 3877 Jul 10 13:30 kube-apiserver.yaml
-rw------- 1 root root 3393 Jul 10 13:30 kube-controller-manager.yaml
-rw-r--r-- 1 root root 0 Apr 17 18:31 .kubelet-legacy.yaml
-rw------- 1 root root 1463 Jul 10 13:30 kube-scheduler.yaml
Kubelet은 해당 디렉터리를 정기적으로 스캔하며,
디렉터리 안의 YAML/JSON 파일이 생성되거나 삭제되었을 때 Static Pod를 생성하거나 삭제합니다.
참고로, Kubelet 이 특정 디렉터리를 스캔할 때 점(.)으로 시작하는 단어를 무시합니다.
예시를 위해 위에 추가 해둔 .kubelet-legacy.yaml
은 무시됩니다.
이 때, Kubelet이 참조할 디렉터리를 변경하고 싶다면 아래의 두 옵션을 통해 수정할 수 있습니다.
✔️ Kubelet config - staticPodPath
kubelet 을 설정할 때 kubelet 설정 파일에 staticPodPath
옵션으로 원하는 위치를 지정할 수 있습니다.
가령, kubelet이 아래와 같이 실행되었을 때,
$ ps -ef | grep /usr/bin/kubelet
root 4345 0.0 0.0 4357904 94820 ? Ssl 13:30 0:11 /usr/bin/kubelet \
--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
--kubeconfig=/etc/kubernetes/kubelet.conf \
--config=/var/lib/kubelet/config.yaml \
--container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \
--pod-infra-container-image=registry.k8s.io/pause:3.9
...
설정 파일인 --config=/var/lib/kubelet/config.yaml
을 살펴보면,
$ cat /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
...
staticPodPath: /etc/kubernetes/manifests
...
위와 같이 설정된 staticPodPath
를 확인할 수 있습니다.
Kubelet의 구성 파일은 🔗 Kubelet Config 에서 자세히 확인할 수 있습니다.
✔️ --pod-manifest-path option
혹은, 권장하지는 않지만, 명령행의 인자로 넘겨줄 수 있습니다.
--pod-manifest-path=/etc/kubernetes/manifests
호스트의 어떤 디렉터리든 될 수 있으며,
디렉터리 위치는 서비스를 실행하는 동안 kubelet에 옵션으로 전달됩니다.
이처럼 Kubelet이 특정 위치에서 Static Pod를 불러오기 때문에,
Static Pod을 생성할 때는 가장 먼저 kubelet 옵션을 살펴볼 필요가 있습니다.
Create a Static Pod
가장 간단하게 Static Pod를 생성하는 방법은
pod 실행 yaml 를 Kubelet이 참조하는 staticPodPath에 저장하면 됩니다.
가령, 아래와 같은 단일 명령어로 말이죠.
$ kubectl run --restart=Never \
--image=busybox static-busybox \
--dry-run=client -o yaml \
--command -- sleep 1000 \
> /etc/kubernetes/manifests/static-busybox.yaml
해당 명령어를 입력한 후, 아래와 같이 저장된 것을 확인할 수 있습니다.
controlplane ~ ➜ cat /etc/kubernetes/manifests/static-busybox.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: static-busybox
name: static-busybox
spec:
containers:
- command:
- sleep
- "1000"
image: busybox
name: static-busybox
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
status: {}
두 번째 방법은 아래와 같이 일반 Pod 파일을 생성하는 것입니다.
원하는 Static Pod Yaml Spec을 작성해서 위 위치에 저장해주면,
Kubelet이 주기적으로 읽어서 업데이트 할 때 Pod가 올라갑니다.
# /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
그럼, 이번엔 생성한 Static Pod를 확인해보겠습니다.
Observe Static Pods
먼저, Static Pod를 확인하기 위해서 Container Runtime의 명령어를 사용할 수 있습니다.
Kubectl 명령어나 kube-serverapi 가 없이도 확인할 수 있다는 의미입니다.
아래와 같이 확인합니다.
✔️ Docker: docker ps
✔️ cri-o: crictl ps
✔️ containerd: nerdctl ps
controlplane ~ ➜ crictl ps
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
7bfd3f585b3a9 fffffc90d343c 2 minutes ago Running web 0 cb6e2e86b0ccf static-web-controlplane
8255080953cff 65ad0d468eb1c 10 minutes ago Running static-busybox 0 a6edc266133b3 static-busybox-controlplane
...
Modify / Delete a Static Pod
그럼, Static Pod 를 수정 하거나 삭제하려면 어떻게 해야할까요?
kubectl edit 명령어나 그 밖에 떠 있는 Pod에서는 수정하거나 삭제할 수 없습니다.
Mirror 객체이기 때문이죠.
반드시 Kubelet이 읽어오는 Static Pod 파일 자체를 수정해야합니다.
가령, 위의 예시 중 static-busybox 의 sleep 시간을 500으로 변경하고 싶다면 아래와 같이 수정합니다.
$ kubectl run --restart=Never \
--image=busybox static-busybox \
--dry-run=client -o yaml \
--command -- sleep 500 \
> /etc/kubernetes/manifests/static-busybox.yaml
단순히 오버라이딩하는 것으로 수정이 완료 됩니다.
삭제할 때도 동일합니다.
해당 Static Pod 정의 파일 자체를 삭제하면 됩니다.
$ rm /etc/kubernetes/manifests/static-busybox.yaml
General Pods ? Mirror Pods?
일반 Pod와 Static Pod 로 생성된 인스턴스인 Mirror Pod는 어떻게 구분할까요?
두 가지 방법이 있습니다.
✔️ 1. 이름을 통한 추측
Static Pod는 생성 시, 이름 뒤에 노드 이름이 붙습니다.
위에서 언급했다시피, ≪static_pod_name≫-≪node_name≫
의 포맷으로 생성됩니다.
Ex: etcd-controlplane
, kube-apiserver-controlplane
, kube-controller-manager-controlplane
, kube-scheduler-controlplane
등
컨트롤 플레인에 존재하는 Static Pod 를 살펴보면 쉽게 이해할 수 있을 텐데요.
❯ k get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 59d v1.29.2
❯ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-76f75df574-l6tsh 0/1 Running 1 (11s ago) 59d
kube-system coredns-76f75df574-s787j 0/1 Running 1 (11s ago) 59d
kube-system kube-apiserver-kind-control-plane 0/1 Running 1 (11s ago) 59d
kube-system kube-controller-manager-kind-control-plane 0/1 Running 1 (11s ago) 59d
kube-system kube-proxy-8v42q 1/1 Running 1 (11s ago) 59d
kube-system kube-scheduler-kind-control-plane 0/1 Running 1 (11s ago) 59d
...
먼저, kube-scheduler 나 kube-apiserver 등의 경우, 하이픈과 노드 이름 kind-control-plane 이 붙은 것을 확인할 수 있습니다.
kube-scheduler-kind-control-plane, kube-apiserver-kind-control-plane
→ Static Pod
반면, kube-proxy나 coredns의 경우, 하이픈 뒤 랜덤 문자열이 붙은 것을 확인할 수 있습니다.
kube-proxy-8v42q, coredns-76f75df574-l6tsh, coredns-76f75df574-s787j
→ 일반 Pod
✔️ 2. Pod 상세 조회
Static Pod의 경우네는 .metadata.ownerReferences.kind
→ Node
로 표기됩니다.
가령, 아래 kube-controller-manager 를 확인해보면,
controlplane ~ ➜ kubectl get pods kube-controller-manager-controlplane -n kube-system -o yaml
apiVersion: v1
kind: Pod
metadata:
...
name: kube-controller-manager-controlplane
namespace: kube-system
ownerReferences:
- apiVersion: v1
controller: true
kind: Node
name: controlplane
uid: 07cf24ac-9926-4125-9f64-f501d99ddd95
kind가 Node 인 것을 확인할 수 있습니다.
→ Static Pod
반면, Control Plane을 통해 관리되는 Pod는 .metadata.ownerReferences.kind
→ ReplicaSet
와 같이 Node
가 아닙니다.
controlplane ~ ➜ kubectl get pods coredns-69f9c977-8v7km -n kube-system -o yaml
apiVersion: v1
kind: Pod
metadata:
...
name: coredns-69f9c977-8v7km
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: coredns-69f9c977
uid: 2d54c431-233c-4fdc-9734-f90bb46dcdc5
위와 같이 kind가 ReplicaSet인 것을 확인할 수 있습니다.
→ 일반 Pod
| Reference |
🔗 Kubernetes.io - Official Docs
🔗 Udemy: certified-kubernetes-administrator-with-practice-tests