
- 컨트롤러 객체는 다른 리소스를 관리하는 쿠버네티스 리소스이다.
- 쿠버네티스에서 컨트롤러는 클러스터의 상태를 관찰하고,
필요한 경우 쿠버네티스 API 와 통신하여 생성, 삭제, 변경 등을 요청하는 컨트롤 루프이다.
(컨트롤 루프: 시스템 상태를 조절하는 종료되지 않는 루프)
🏷️ 컨트롤러 객체를 사용하지 않으면
- 파드를 배포 하고 싶은 개수 만큼 n번 배포 해야한다.
- 파드를 스케일링 하고 싶을 때에도 사용자가 직접 유지보수 해야한다.
- 파드를 배포할 때 어떤 노드에 배포할 지 사용자가 직접 고민 해야한다.
- 파드 장애 발생 여부도 사용자가 직접 모니터링 하고 새로 배포 해야한다.
- 예시 외에도 파드만 독립적으로 사용할 경우 유지보수 문제점이 많이 발생한다.
이는 쿠버네티스 오케스트레이션을 온전히 사용하지 못하는 것을 의미한다.
디플로이먼트컨트롤러는 쿠버네티스에서 파드를 관리(스케일링, 롤링 업데이트 등)하는 워크로드 리소스 중 하나이다.
- 디플로이먼트를 이용하면, 아래 이미지와 같이 파드 여러개를 클러스터 내 노드에 적절히 분산 하여 배치 시킬 수 있다.
- 즉, 개발자가 파드를 어떤 노드에 배포할 지 직접 고민하지 않아도 된다.

- 디플로이먼트를 이용하여 파드를 배포 했다면, 혹시 노드 또는 파드에 장애가 발생 하더라도 디플로이먼트와 연관 된 리소스들이 자체적으로 판단하여, 아래와 같이 원래 배포 되었던 파드 개수를 유지하기 위해 자가 수복에 들어간다.

- 아래와 같이 컨트롤러 객체를 생성하면, 자신을 포함 하여 연관 있는 리소스를 함께 생성한다.
- hello-kiamol-2 이름의 디플로이먼트를 생성하고 디플로이먼트 객체 목록을 조회해 보자.
# 디플로이먼트 생성
$ kubectl create deployment hello-kiamol-2 --image=kiamol/ch02-hello-kiamol
>> deployment.apps/hello-kiamol-2 created
# 디플로이먼트 객체 목록 조회
$ kubectl get deployment
>>
NAME READY UP-TO-DATE AVAILABLE AGE
hello-kiamol-2 1/1 1 1 82m # --> {디플로이먼트이름}
- 디플로이먼트 구성도에 있는 레플리카셋 역시 아래와 같이 디플로이먼트만 생성 하였는데 배포 된 것을 볼 수 있다.
- 레플리카셋 이름은 디플로이먼트 이름에 랜덤 문자열이 suffix 로 추가 되어 상속 된 것을 알 수 있다.
- 지금은 레플리카셋이 정확히 무엇인지 살피지 않는다.
# 레플리카셋 객체 목록 조회
$ kubectl get replicasets
NAME DESIRED CURRENT READY AGE
hello-kiamol-2-7cb44d9bdd 1 1 1 84m # --> {디플로이먼트이름}-{레플리카셋랜덤문자열}
- 이어서, 디플로이먼트 배포 시 선언해둔 컨테이너를 실행하는 파드도 생성 된 것을 알 수 있다.
- 파드 이름은 레플리카셋 이름에 랜덤 문자열이 suffix 로 추가 되어 상속 된 것을 알 수 있다.
# 파드 목록 조회
$ kubectl get pods
>>
NAME READY STATUS RESTARTS AGE
hello-kiamol 1/1 Running 2 (6h15m ago) 20h # --> 이전에 파드 개념 살펴볼 때 생성 했던 파드
hello-kiamol-2-7cb44d9bdd-j8wnl 1/1 Running 0 76m # --> 이번에 디플로이먼트 생성할 때 배포 된 파드, {디플로이먼트이름}-{레플리카셋랜덤문자열}-{파드랜덤문자열}
📍 즉, 디플로이먼트만 배포 하면 필요한 파드를 대신 만들어 준다
- 디플로이먼트, 레플리카셋, 파드는 레이블(Labels)과 셀렉터(Selector) 를 이용하여 연결성을 유지 한다.
- 아래는 hello-kiamol-2 의 상세 정보이다.
- 디플로이먼트 정보에서 Selector 를 보면 레이블 중 app 이 hello-kiamol-2 인 리소스를 관리 대상으로 하는 것을 알 수 있다.
# 디플로이먼트 상세 정보 확인
$ kubectl describe deployment hello-kiamol-2
>>
Name: hello-kiamol-2 # 디플로이먼트 이름
Namespace: default
CreationTimestamp: Sun, 01 Sep 2024 20:24:17 +0900
Labels: app=hello-kiamol-2 # 디플로이먼트 레이블 중 app 이라는 key 의 value 는 hello-kiamol-2
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=hello-kiamol-2 # 해당 디플로이먼트는 레이블로 app 이라는 key 를 가지는 리소스들을 관리 대상으로 판별한다.
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=hello-kiamol-2 # 디플로이먼트를 배포하면서 같이 생성 되는 파드의 레이블 중 app(key) 의 value 를 hello-kiamol-2 로 상속 시킨다.
Containers:
ch02-hello-kiamol:
Image: kiamol/ch02-hello-kiamol
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-kiamol-2-7cb44d9bdd (1/1 replicas created)
Events: <none>
- 아래와 같이 디플로이먼트에서 상속 받은 레이블 값으로 리소스를 탐색할 수 있다.
# hello-kiamol-2 디플로이먼트의 레이블 정보만 조회하기
$ kubectl get deployment hello-kiamol-2 --output jsonpath='{.spec.template.metadata.labels}'
>> {"app":"hello-kiamol-2"}
# 레플리카셋의 레이블 정보 중 app 이 hello-kiamol-2 인 레플리카셋 조회하기
$ kubectl get replicasets -l app=hello-kiamol-2
>>
NAME DESIRED CURRENT READY AGE
hello-kiamol-2-7cb44d9bdd 1 1 1 113m
# 파드 레이블 정보 중 app 이 hello-kiamol-2 인 파드 조회하기
$ kubectl get pods -l app=hello-kiamol-2
>>
NAME READY STATUS RESTARTS AGE
hello-kiamol-2-7cb44d9bdd-j8wnl 1/1 Running 0 113
- 위와 같이 Labels 를 통해 리소스 연결성을 유지 한다는 것을 알았다.
- 이번에는 파드 개수를 유지하는 과정을 간단히 정리해 보자.
- 레플리카셋에서 파드 3개가 유지 되도록 하였는데, 하나의 파드가 유실된 상황을 가정하겠다.

[ Pod 유실 후 복구 순서 ]
1. Pod 가 유실 된다.
2. 유실된 Pod 와 같은 Node 에 있는 Kubelet 이 Pod 유실을 감지한다.
3. Kubelet 이 Pod 유실 상태를 API Server 에게 전달한다.
4. API Server 는 etcd 에 Pod 유실 상태를 업데이트 한다.
5. Replicaset 이 API Server 를 통해 현재 Pod 상태를 감지한다.
(실행 중인 Pod 가 3개보다 적다는 것을 인지)
6. Replicaset 이 API Server 에게 새로운 Pod 생성을 요청한다.
7. API Server 는 전달 받은 Pod 배포 정보를 Scheduler 에게 전달한다.
8. Scheduler 는 Pod 를 어떤 Node 에 배포할 지 결정하고, API Server 에게 배포 명령을 전달한다.
9. API Server 는 결정된 Node 에 위치한 Kubelet 에게 Pod 를 실행 하라고 명령한다.
10. Kubelet 은 해당 Node 에 Pod 를 실행하고 모니터링 한다.
11. Kubelet 이 API Server 에게 Pod 상태를 전달한다.
12. API Server 는 etcd 에 Pod 상태를 업데이트한다.
13. Replicaset 은 API Server 를 통해 Pod 상태를 감지하고 안정화 한다.
🏷️ 위 과정에서 유실 된 파드에 Labels 가 Deployment, Replicaset 에서 상속 받은 값과 동일해야 자가 수복을 진행한다.
- 디플로이먼트에 의해 배포 된 파드를 강제로 삭제 하고 새로운 파드가 생성 되는지 확인 해보자.
# Pod 목록 조회
$ kubectl get pods
>>
NAME READY STATUS RESTARTS AGE
hello-kiamol-2-7cb44d9bdd-j8wnl 1/1 Running 0 3h38m
# Deployment 의해 생성된 Pod 삭제
$ kubectl delete pod/hello-kiamol-2-7cb44d9bdd-j8wnl
>> pod "hello-kiamol-2-7cb44d9bdd-j8wnl" deleted
# Pod 목록 한 번 더 조회
$ kubectl get pods
>>
NAME READY STATUS RESTARTS AGE
hello-kiamol-2-7cb44d9bdd-jmjzm 1/1 Running 0 3s
🏷️ 파드 삭제 전/후로 파드 이름을 보면 suffix 로 붙은 파드 랜덤 문자열이 변경 된 것을 확인할 수 있다.
🏷️ 만약 파드의 Labels 값을 강제로 변경하더라도 Selector 에 일치하는 파드가 유실 된 것으로 간주하고 하나의 파드를 추가로 배포 한다. 따라서, 리소스들 끼리 연결된 Lables 는 주의해서 변경 해야한다.
- 실습에서 디플로이먼트로 배포한 파드는 웹 애플리케이션이다.
- 디플로이먼트의 replicas(파드 복제본 수)를 3으로 변경하고, 웹 애플리케이션에 네트워크 트레픽을 보내보자.
# 디플로이먼트의 replicas 수를 3으로 업데이트
$ kubectl scale deployment/hello-kiamol-2 --replicas=3
>> deployment.apps/hello-kiamol-2 scaled
# Pod 목록 조회
>>
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-kiamol 1/1 Running 2 (9h ago) 23h
hello-kiamol-2-7cb44d9bdd-54mbm 1/1 Running 0 9s
hello-kiamol-2-7cb44d9bdd-dxkkg 1/1 Running 0 9s
hello-kiamol-2-7cb44d9bdd-jmjzm 1/1 Running 0 54m
- 위와 같이 디플로이먼트에 의해 배포된 파드가 3개로 증가 했다.
- 이전에는 파드 하나를 독립적으로 배포 한 후 파드에 포트 포워딩 하여 접속 했다.
- 그렇다면, 지금은 세 개의 파드에 모두 포트 포워딩 해야 할까? 그렇지 않다.
- 디플로이먼트에 포트 포워딩 하면 디플로이먼트 컨트롤러가 관리하는 파드 리소스에 네트워크 트레픽을 분산 시킨다.
# 디플로이먼트에 포트 포워딩
$ kubectl port-forward deployment/hello-kiamol-2 8080:80
# http://localhost:8080 으로 접속
이번에 정리한 내용 말고도 컨트롤러 객체의 훨씬 복잡하고 다양한 내용이 많지만, 쿠버네티스에서 파드를 독릭접으로 잘 사용하지 않고 컨트롤러를 더 많이 이용한다는 느낌을 잡을 수 있는 정도는 됐을 것 같다.
다음 게시글에서는 애플리케이션 매니페스트 정의 방법을 정리해볼 예정이다.