"이렇게 되어 있어라" 를 저장하면 시스템이 스스로 맞추는 방식.
-
명령형 — "컨테이너를 3개 띄워라"
- 하나 죽으면 누군가 알아채고 다시 명령해야 한다
-
선언형 — "항상 3개가 떠 있는 상태여야 한다"
- 시스템이 계속 비교하고 스스로 맞춘다
조정 루프
컨트롤러가 무한히 반복한다
현재 상태를 관찰한다 → 파드가 2개 떠 있다
원하는 상태와 비교한다 → 3개여야 한다
차이를 줄이는 동작을 한다 → 1개를 더 만든다
이 루프가 쿠버네티스의 거의 모든 기능을 설명한다 Deployment · Service · Job · 오토스케일러 · 인그레스 컨트롤러 — 전부 자기 종류의 리소스를 보고 같은 루프를 돈다
apply 는 실행이 아니라 선언이다
kubectl apply 는 '원하는 상태' 를 etcd 에 저장할 뿐이다 실제로 맞추는 것은 컨트롤러다
- 명령이 성공했다고 파드가 떴다는 뜻이 아니다
- 그래서 apply 뒤에 rollout status 로 결과를 확인한다
- 반대로 리소스를 손으로 지워도 컨트롤러가 다시 만든다
- (Deployment 의 파드를 지우면 곧 새로 생긴다)
spec 과 status
- spec — 원하는 상태 — 우리가 쓴다
- status — 현재 상태 — 시스템이 쓴다
모든 리소스가 이 두 필드를 갖는다 트러블슈팅은 결국 '둘이 왜 다른가' 를 찾는 일이다
kubectl get deploy web -o yaml 로 둘을 나란히 보면 무엇이 원하는 것이고 무엇이 실제인지가 바로 갈린다
확장도 같은 모양이다
- CRD — 새 kind 를 등록한다. 그 순간부터 kubectl 로 다룰 수 있다
- 오퍼레이터 — 그 CRD 를 보고 조정 루프를 도는 컨트롤러
즉 '쿠버네티스를 확장한다' 는 것은
- ① 새 리소스 종류를 정의하고
- ② 그것을 보는 컨트롤러를 만드는 것 이 둘뿐이다. 내부 구조와 완전히 같다
명령형 명령을 쓰는 자리도 있다
# 빠르게 만들 때 — 시험·실습·임시 확인
kubectl create deployment web --image=nginx --dry-run=client -o yaml > web.yaml
kubectl run tmp --rm -it --image=busybox -- sh
kubectl expose deploy web --port=80 --target-port=8080 --dry-run=client -o yaml
--dry-run=client -o yaml 조합이 실무에서 가장 유용하다 YAML 을 처음부터 쓰지 않고 뼈대를 뽑아 고친다 필드 이름을 외울 필요가 없어진다
운영 리소스는 파일로 관리하고 apply 로 적용한다 (GitOps)
- 무엇이 배포됐는지가 git 에 남는다
- kubectl edit 으로 고치면 다음 apply 때 되돌아간다
필드를 찾는 법
kubectl explain deployment.spec.strategy --recursive
kubectl api-resources | grep -i ingress
문서를 열지 않고 CLI 에서 스펙을 확인할 수 있다. 시험에서도 실무에서도 가장 쓸모 있는 명령이다.
면접 함정
- ❌ "apply가 성공하면 배포가 끝난 것" → 선언만 저장된다. 결과는 따로 확인해야 한다.
- ❌ "파드를 지우면 없어진다" → 컨트롤러가 관리하는 파드는 다시 생긴다.