쿠버네티스에서 컨트롤러는 클러스터의 상태를 관찰한 다음 필요한 경우에 생성 또는 변경을 요청하는 컨트롤 루프로 즉, 파드를 관리하는 역할을 한다.
다양한 목적에 따라 쿠버네티스에서 제공하는 컨트롤러를 사용하면 되는데 컨트롤러의 종류는 다음과 같이 있다.

이번 글에서는 쿠버네티스에서 제공되는 컨트롤러의 종류와 특징, 예제를 한번 살펴보도록 하자.
가장 기본적인 컨트롤러이다. 요구하는 pod의 개수를 보장하며 pod 집합의 실행을 항상 안정적으로 유지하는 것을 목표로 한다.
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-rc
spec:
replicas: 3
selector:
app: web
template:
metadata:
name: nginx-pod
labels:
app: web
spec:
containers:
- name: nginx-container
image: nginx:1.14
replicas: 단일 포드의 정보를 몇개 복제할지 작성
selector: Replication Controller가 담당할 pod의 범위를 지정
※ seletor가 가지고 있는 key:value를 pod template에서 라벨로 가지고 있어야함! ※
template: 레플리카 컨트롤러에게 어떤 POD 를 기준으로 생성하라고 선언해주어야 함
seletor가 가지고 있는 key:value를 pod template에서 라벨로 가지고 있어야함!
$ kubectl create -f rc-nginx.yaml
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-rc-mpwjm 1/1 Running 0 14s 10.0.0.- test-cluster-worker2 <none> <none>
nginx-rc-xl2sq 1/1 Running 0 14s 10.0.0.- test-cluster-worker3 <none> <none>
nginx-rc-zfbmk 1/1 Running 0 14s 10.0.0.- test-cluster-worker <none> <none>
$ kubectl get replicationcontrollers 혹은 kubectl get rc
NAME DESIRED CURRENT READY AGE
nginx-rc 3 3 3 3m10s
pod의 이름을 보면 해시값으로 랜덤하게 이름이 생성되고 replicas 3개를 보장하고 있는 것을 확인할 수 있다.
만일 세개의 pod 중 하나를 삭제하면 컨트롤러는 곧바로 새로운 pod를 생성할 것이다.
설정을 변경하는 방법은 두가지 방법이 있는데 2번째 명령어로 곧바로 수정사항을 반영할 수 있다.
$ kubectl scale rc nginx-rc --replicas=4
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-rc-8zl4g 1/1 Running 0 3m35s
nginx-rc-l4nnh 1/1 Running 0 3m35s
nginx-rc-r66w9 1/1 Running 0 3m35s
nginx-rc-sfpjt 1/1 Running 0 4s
만일 kubectl edit 명령어를 사용하여 image: nginx:1.14를 1.15로 변경하고 저장한다면 어떻게 될까?
$ kubectl describe pod nginx-rc-8zl4g
...
Containers:
nginx-container:
Container ID: containerd://5ed323a4dafa55557580280da4c775cb6a8a45-
Image: nginx:1.14
pod 정보를 확인하면 이미 동작중이기 때문에 nginx-rc-8zl4g의 nginx 버전이 그대로 1.14임을 알 수 있다. 현재 상태에서 pod를 종료한다면 그 이후부터는 1.15버전으로 동작하는 것을 확인 할 수 있을 것이다.
$ kubectl delete pod nginx-rc-8zl4g
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-rc-95nrn 0/1 ContainerCreating 0 4s
nginx-rc-r66w9 1/1 Running 0 24m
$ kubectl describe pod nginx-rc-95nrn
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 20s default-scheduler Successfully assigned default/nginx-rc-95nrn to test-cluster-worker3
Normal Pulling 20s kubelet Pulling image "nginx:1.15"
Normal Pulled 9s kubelet Successfully pulled image "nginx:1.15" in 11.385s (11.385s including waiting). Image size: 41971871 bytes.
Normal Created 8s kubelet Created container nginx-container
Normal Started 8s kubelet Started container nginx-container
Replication controller와 같은 역할을 하는 컨트롤러로, 보다 풍부한 selector를 지원한다.
selector:
matchLabels:
app: web
matchExpressions:
- {key: version, operator: In, values: ["1.14", "1.15"]}
matchLabels: key:value
matchExpressions: vaule의 값이 '1.14', '1.15' 상관이 없으므로 해당되는 버전의 app:web에 맞는 pod를 운영 요청
※ Replication controller의 경우 셀렉터를 여러개 쓸경우 and 조건으로 동작한다. ※
ReplicaSet 컨트롤러가 동작하고 있다고 할때 replicas를 2개로 변경하고 컨트롤러만 삭제하여 2개의 pod만 남아있다고 가정해보자.
$ kubectl get replicaset 혹은 kubectl get rs
$ kubectl scale rs nginx-rs --replicas=4
$ kubect delete rs nginx-rs --cascade=false
--cascade=false 옵션을 부여한다면 컨트롤러만 삭제되고 pod는 남아있다.
현재 상태에서 기존의 yaml 파일을 통해 컨트롤러를 생성한다면 이미 두개의 pod가 운영중이기 때문에 하나의 pod만 추가되는 것을 확인할 수 있을 것이다.
ReplicaSet을 제어해주는 부모 역할을 하며 pod의 수를 결정한다. 롤링 업데이트 기능을 쓰지 않는다면 ReplicaSet과 동일하다고 보면 된다.
$ kubectl create -f deployment-nginx.yaml
deployment.apps/nginx-deploy created
$ kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deploy 3/3 3 3 3m27s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deploy-7db9766f79 3 3 3 3m27s
NAME READY STATUS RESTARTS AGE
pod/nginx-deploy-7db9766f79-8ngcf 1/1 Running 0 3m27s
pod/nginx-deploy-7db9766f79-h5rmb 1/1 Running 0 3m27s
pod/nginx-deploy-7db9766f79-lskd8 1/1 Running 0 3m27s
pod의 이름을 보면 컨트롤러를 의미하는 해시값들을 확인할 수 있는데 각각 'pod/nginx-deploy'는 Deployment의 이름을, '7db9766f79'는 컨트롤러 이름, '8ngcf'는 pod의 이름임을 알 수 있다.
Deployment는 ReplicaSet을 삭제해도 새로 생성한다는 특징이 있다.
$ kubectl create -f deployment-nginx.yaml --record
deployment.apps/app-deploy created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
app-deploy-c7fcfbf44-gqj5b 1/1 Running 0 4s
app-deploy-c7fcfbf44-hlkcr 1/1 Running 0 4s
app-deploy-c7fcfbf44-wzmgp 1/1 Running 0 4s
※ 새로운 컨트롤러를 생성할때 --record 옵션을 사용하는 이유? ※
--record 옵션을 사용하지 않으면 history를 조회했을때 다음과 같이 나온다.
$ kubectl rollout history deployment app-deploy
deployment.apps/app-deploy
REVISION CHANGE-CAUSE
1 <none>
업데이트된 기록이 나오지 않아 나중에 롤백할때 문제가 될 수 있다. 따라서 레코드 옵션을 항상 잘 적용해주도록 하자.
$ kubectl rollout history deployment app-deploy
deployment.apps/app-deploy
REVISION CHANGE-CAUSE
1 kubectl create --filename=deployment-nginx.yaml --record=true
다시 돌아와서 롤링 업데이트를 진행해보자.
$ kubect set image deployment <deploy_name> <container_name> = <new_version_name>
$ kubectl set image deployment app-deploy app=nginx:1.15 --record
컨테이너를 새로운 버전으로 업데이트 과정은 다음과 같다.
아래 명령어를 통해 업데이트가 성공적으로 완료된 것을 확인할 수 있다.
$ kubectl rollout status deployment app-deploy
deployment "app-deploy" successfully rolled out
// 업데이트 일시정지/재시작 명령어
$ kubectl rollout pause/resume
히스토리를 조회하여 업데이트 직전의 버전과 특정 버전으로 롤백할 수 있다.
$ kubectl rollout history deployment app-deploy
deployment.apps/app-deploy
REVISION CHANGE-CAUSE
1 kubectl create --filename=deployment-nginx.yaml --record=true
2 kubectl set image deployment app-deploy app=nginx:1.15 --record=true
undo 명령어는 히스토리를 기준으로 바로 직전의 단계로 되돌아갈 수 있다.
$ kubectl rollout undo deployment app-deploy
deployment.apps/app-deploy rolled back
만일 특정 버전으로 롤백하고 싶다면 히스토리의 REVISION 번호를 통해 되돌아갈 수 있다.
$ kubectl rollout undo deployment app-deploy —to-revision=2
DaemonSet의 경우 노드당 1개의 pod를 보장해준다. 로그 수집기, 모니터링 에이전트와 같은 프로그램 실행시 사용된다.
또한 이미 노드가 보장되어있기 때문에 replicas 설정이 필요없다.
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
test-cluster-control-plane Ready control-plane 77d v1.30.0
test-cluster-worker Ready <none> 77d v1.30.0
test-cluster-worker2 Ready <none> 77d v1.30.0
$ kubectl create -f daemonset-nginx.yaml
daemonset.apps/nginx-daemonset created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-daemonset-8jm8h 1/1 Running 0 16s 10.244.0.- test-cluster-worker2 <none> <none>
nginx-daemonset-pjvlc 1/1 Running 0 16s 10.244.0.- test-cluster-worker <none> <none>
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
nginx-daemonset 2 2 2 2 2 <none> 13m
컨트롤러를 생성 후 pod 정보를 확인해보면 각 노드 별로 한개씩 두개의 pod가 생성된 것을 볼 수 있다.
kubectl edit 명령어를 통해 nginx의 버전을 1.15 버전으로 변경해보자.
$ kubectl edit daemonset nginx-daemonset
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-daemonset-hc846 1/1 Running 0 4s
nginx-daemonset-pljtl 1/1 Running 0 1s
$ kubectl describe pod nginx-daemonset-hc846
...
Containers:
nginx:
Container ID: containerd://768003dd7ff3045cd8d63be4-
Image: nginx:1.15
DaemonSet의 경우 이미지 버전을 변경한 즉시 업데이트를 실행한다.
롤백 명령어는 Deployment와 동일하다.
$ kubectl rollout undo daemonset nginx-daemonset
pod의 상태(pod 이름, 볼륨(스토리지))를 유지해주는 컨트롤러이다.
예를들어 ReplicaSet으로 생성된 pod 이름의 경우 해시값으로 랜덤하게 생성되지만 statefulSet의 경우 스케일 인/아웃시에 pod의 이름에 번호가 부여되어 증감하기 때문에 pod의 이름을 미리 알 수 있다.
metadata:
name: sf-nginx
spec:
replicas: 3
serviceName: sf-service
podManagementPolicy: Parallel
name: sf-nginx-0, sf-nginx-1 …. 이런식으로 부여되는 특징이 있다.
podManagementPolicy: OrderedReady(Default) : 순차적으로 증감
podManagementPolicy: Parallel : 0, 1, 2번을 동시에 평행하게 사용
statefulSet의 경우 어느 노드에 배치되는지는 보장되지 않기 때문에 랜덤하게 생성된다.
$ kubectl create -f statefulset-nginx.yaml
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sf-nginx-0 1/1 Running 0 9s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-1 1/1 Running 0 9s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-2 1/1 Running 0 9s 10.244.0.- test-cluster-worker <none> <none>
만일 파드를 삭제할 경우 이름을 보장하기 때문에 동일한 이름으로 생성된다.
$ kubectl delete pod sf-nginx-1
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sf-nginx-0 1/1 Running 0 87s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-1 1/1 Running 0 1s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-2 1/1 Running 0 87s 10.244.0.- test-cluster-worker <none> <none>
이름이 보장되는 것을 더 확인해보자.
$ kubectl scale statefulset sf-nginx --replicas=4
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sf-nginx-0 1/1 Running 0 2m57s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-1 1/1 Running 0 91s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-2 1/1 Running 0 2m57s 10.244.0.- test-cluster-worker <none> <none>
sf-nginx-3 1/1 Running 0 2s 10.244.0.- test-cluster-worker <none> <none>
$ kubectl scale statefulset sf-nginx --replicas=2
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sf-nginx-0 1/1 Running 0 3m36s 10.244.0.- test-cluster-worker2 <none> <none>
sf-nginx-1 1/1 Running 0 2m10s 10.244.0.- test-cluster-worker2 <none> <none>
※ statefuleSet의 롤링 업데이트는 순차적으로 종료 후 업데이트를 진행한다.
쿠버네티스는 기본적으로 pod를 항상 러닝중인 상태를 유지하는데 잡 컨트롤러는 pod의 애플리케이션(job) 실행이 완료/종료되는 것에 초점을 맞춘 컨트롤러이다.
레플리케이션, 레플리카셋, 데몬셋의 경우 pod의 애플리케이션이 지속적으로 잘 동작하는 것을 초점에 맞춘것과 대비되는데 애플리케이션이 실행되고 실행이 완료되면 pod의 할 일이 끝난 것으로 간주하고 pod를 종료시킨다.
즉, 잡 컨트롤러를 사용하여 애플리케이션을 실행시켰을때 완료가 정상인지 비정상인지 체크하여 비정상 종료시 재실행, 정상 종료시 완료하는 것을 보장하는 컨트롤러이다.
apiVersion: batch/v1
kind: Job
metadata:
name: job-example
spec:
completions: 5
parallelism: 2
activeDeadlineSeconds: 15
template:
spec:
containers:
- name: centos-container
image: centos:7
command: ["bash"]
args:
- "-c"
- "echo 'Hello World'; sleep 5; echo 'Bye'"
restartPolicy: Never / OnFailure
backoffLimit: 3
$ kubectl create -f job-centos.yaml
$ kubectl describe job job-example
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m17s job-controller Created pod: job-example-255p7
Normal Completed 101s job-controller Job completed
job의 이벤트를 확인해보자.
위처럼 ‘Job completed’가 되면 컨트롤러가 종료되어서 이후 삭제되는 파드는 정상적인 것으로 간주하고 정상 삭제된다.
그러나 ‘Job completed’가 아닐 경우 pod를 삭제시키면 비정상 종료라고 판단하여 pod를 새로 생성하게 된다.
그렇다면 backoffLimit:3 에 실패한 pod를 확인해보자.
yaml 설정값을 다음과 같이 설정했다고 가정한다.
restartPolicy: OnFailure
backoffLimit: 3
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
job-example-688zv 0/1 RunContainerError 0 2s 10.244.0.- test-cluster-worker <none> <none>
…
최대 3번까지 pod를 재실행한다.
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
job-example-688zv 0/1 Terminationg 3 (28s ago) 70s 10.244.0.- test-cluster-worker <none> <none>
전부 실패하면 리소스를 아예 삭제해버린 것을 확인할 수 있다.
$ kubectl get pod
No resources found in default namespace.
잡 컨트롤러를 제어해서 사용자가 원하는 시간에 잡이 실행되도록 지원해준다.
설정 값은 평소 우리가 알고있는 cron과 비슷하다고 보면된다.
Cronjob schedule: “0 0 0 0 0”
분/시간/일/월/주중(0-6)
쿠버네티스에 원하는 동작을 잡 컨트롤러를 통해 실행한다면 잡 컨트롤러는 동작 수행 후 complite로 종료 시킨다. 잡 컨트롤러가 cronJob에게 스케줄링에 따라 작업해달라고 요청하여 동작하는 것이 cronJob이다.
- 매주 일요일 새벽 3시에 잡을 실행해줘 -> 0 3 * * 0
- 매월 1일 아침 9시 정각에 잡을 실행해줘 -> 0 9 1 * *
- 주중 새벽 3시에 잡을 실행해줘 -> 0 3 * * 1-5
- 주말 새벽 3시에 잡을 실행해줘 -> 0 3 * * 0,6
- 잡을 5분마다 반복해서 실행해줘 -> /5 * * *
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo Hello
restartPolicy: OnFailure