
CKA 스케줄링 섹션 중 Static Pod를 kind 환경에서 직접 실습했다. 개념을 잡고, docker exec로 컨트롤 플레인 컨테이너 안에 들어가서 manifest를 생성하고 수정하는 것까지 다뤘다. 실습하면서 CrashLoopBackOff, ImagePullBackOff 오류를 직접 마주치고 원인을 파악해서 해결했다.
일반 파드는 API 서버 → 스케줄러 → kubelet 순서로 실행된다. 반면 Static Pod는 kubelet이 특정 디렉토리를 직접 감시하다가 yaml 파일이 생기면 API 서버 없이 바로 실행하는 파드다.
/etc/kubernetes/manifests/ ← kubelet이 감시하는 경로
├── kube-apiserver.yaml
├── etcd.yaml
├── kube-scheduler.yaml
└── kube-controller-manager.yaml
존재 이유는 부트스트랩 문제 때문이다. kube-apiserver 자체를 파드로 띄우려면 API 서버가 필요한데, 아직 API 서버가 없다. 이 닭-달걀 문제를 Static Pod로 해결한다. 클러스터 초기화 시 manifests 디렉토리에 yaml이 복사되면 kubelet이
감지해서 컨트롤 플레인을 띄운다.
kubelet은 파드가 아니라 systemd가 관리하는 OS 레벨 프로세스다. 쿠버네티스 컴포넌트 중 유일하게 쿠버네티스 바깥에 있고, 컨트롤 플레인 포함 모든 노드에 설치된다.
kubectl get nodes
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 2m42s v1.35.0
kind-worker Ready <none> 2m28s v1.35.0
kind-worker2 Ready <none> 2m28s v1.35.0
kind는 노드가 Docker 컨테이너로 실행된다. 처음에 SSH로 접속하려다 실패했다.
ssh 172.18.0.3
# ^C (안됨)
kind 노드는 SSH가 아니라 docker exec로 접속해야 한다.
docker ps
# kind-control-plane, kind-worker, kind-worker2 컨테이너 확인
docker exec -it kind-control-plane bash
컨테이너 안에서 kubelet 설정을 확인한다.
cat /var/lib/kubelet/config.yaml | grep staticPodPath
# staticPodPath: /etc/kubernetes/manifests
ls /etc/kubernetes/manifests
# etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
컨트롤 플레인 컴포넌트 4개가 전부 Static Pod로 떠있는 걸 확인할 수 있다.
처음에 로컬 터미널에서 경로를 그대로 입력했다.
# 로컬에서 실행 → 실패
kubectl run web-static --image=nginx:1.27 --dry-run=client -o yaml \
> /etc/kubernetes/manifests/web-static.yaml
# zsh: no such file or directory: /etc/kubernetes/manifests/web-static.yaml
로컬 macOS에는 /etc/kubernetes/manifests/가 없다. 컨테이너 안에서 실행해야 한다.
docker exec -it kind-control-plane bash
# 컨테이너 안에서
kubectl run web-static --image=nginx:1.27 --dry-run=client -o yaml \
> /etc/kubernetes/manifests/web-static.yaml
참고로 컨테이너 안에는 k alias가 없다.
k get pods
# bash: k: command not found
# kubectl을 풀네임으로 써야 함
파일을 넣으면 kubelet이 자동 감지해서 바로 파드가 뜬다.
kubectl get pods -w
# NAME READY STATUS RESTARTS AGE
# web-static-kind-control-plane 0/1 ContainerCreating 0 34s
# web-static-kind-control-plane 1/1 Running 0 42s
kubectl run log-agent --image=busybox --dry-run=client -o yaml \
> /etc/kubernetes/manifests/log-agent.yaml
kubectl get pods
# NAME READY STATUS RESTARTS
# log-agent-kind-control-plane 0/1 CrashLoopBackOff 1 (5s ago)
describe로 원인을 확인한다.
kubectl describe pods log-agent-kind-control-plane
# State: Terminated
# Reason: Completed
# Exit Code: 0
# Events:
# Warning BackOff kubelet Back-off restarting failed container log-agent
Exit Code가 0이고 즉시 종료됐다. busybox는 명령어를 지정하지 않으면 기본으로 sh를 실행하는데, 입력받을 터미널이 없으니 바로 종료된다. 파드가 종료되면 kubelet이 재시작하고, 또 종료되는 걸 반복하다가 재시작 간격을 점점 늘리는 게 CrashLoopBackOff다.
sleep을 추가해서 프로세스가 살아있게 한다.
kubectl run log-agent --image=busybox --dry-run=client -o yaml \
-- sleep 3600 > /etc/kubernetes/manifests/log-agent.yaml
kubectl get pods -w
# log-agent-kind-control-plane 0/1 Pending 0 1s
# log-agent-kind-control-plane 1/1 Running 0 3s
manifest 파일의 이미지를 busybox:1.36으로 바꾸려고 에디터를 시도했는데 전부 없었다.
vim /etc/kubernetes/manifests/log-agent.yaml
# bash: vim: command not found
vi /etc/kubernetes/manifests/log-agent.yaml
# bash: vi: command not found
nano /etc/kubernetes/manifests/log-agent.yaml
# bash: nano: command not found
sed로 파일을 직접 수정한다.
sed -i 's/image: busybox/image: busybox:1.36/' \
/etc/kubernetes/manifests/log-agent.yaml
파일만 수정하면 kubelet이 자동 감지해서 파드를 재시작한다. kubectl apply 없이도 된다.
잘못된 이미지명으로 Static Pod를 만들어서 트러블슈팅을 연습했다.
kubectl run web-static --image=nginxxx --dry-run=client -o yaml \
> /etc/kubernetes/manifests/web-static.yaml
kubectl get pods -w
# web-static-kind-control-plane 0/1 ImagePullBackOff 0 30s
# web-static-kind-control-plane 0/1 ErrImagePull 0 31s
describe로 원인을 확인한다.
kubectl describe pods web-static-kind-control-plane
# Events:
# Warning Failed kubelet Failed to pull image "nginxxx":
# failed to resolve reference "docker.io/library/nginxxx:latest":
# pull access denied, repository does not exist
존재하지 않는 이미지라는 걸 확인하고 sed로 수정한다.
sed -i 's/image: nginxxx/image: nginx/' \
/etc/kubernetes/manifests/web-static.yaml
kubectl get pods -w
# web-static-kind-control-plane 0/1 Terminating 0 2m36s
# web-static-kind-control-plane 0/1 ContainerCreating 0 5s
# web-static-kind-control-plane 1/1 Running 0 57s
| 구분 | 일반 파드 | Static Pod |
|---|---|---|
| 관리 주체 | API 서버 + kubelet | kubelet 단독 |
| 설정 방법 | kubectl apply | manifest 파일 복사 |
| 수정 방법 | kubectl edit / apply | 파일 직접 수정 (sed 등) |
| 삭제 방법 | kubectl delete | 파일 삭제 |
| 주 용도 | 일반 워크로드 | 컨트롤 플레인 부트스트랩 |
Q1. nginx:1.27 이미지로 web-static Static Pod를 controlplane 노드에 생성하라.
→ staticPodPath 확인 후 --dry-run=client -o yaml로 manifest 생성, manifests 디렉토리에 저장
Q2. log-agent Static Pod의 이미지를 busybox에서 busybox:1.36으로 변경하라.
→ 에디터 없는 환경에서는 sed -i 's/old/new/' manifest.yaml 활용
Q3. CrashLoopBackOff 상태의 Static Pod를 트러블슈팅하여 Running 상태로 만들어라.
→ kubectl describe의 Events 섹션에서 원인 파악 (잘못된 이미지 or 즉시 종료되는 이미지)