HomeAbout
[Kubernetes] Kubernetes Controller 심층 분석: ReplicaSet, DaemonSet 실전 예제
Docker & Kubernetes
[Kubernetes] Kubernetes Controller 심층 분석: ReplicaSet, DaemonSet 실전 예제
NASA1515
NASA1515
June 26, 2021
5 min

목차

01
✔ Liveness Probe (Liveness Probe)
02
✌ ReplicaSet (RS)
03
👀 DaemonSet (DS)
04
🐱‍🏍 JOB
05
🎶 CRONJOB

✔ Liveness Probe (Liveness Probe)

사용자가 모든 오브젝트를 일일이 관리할 수는 없습니다.
관리하고자 하더라도 사용자의 사각지대에 있는 오브젝트를 실제 프로덕션 환경에서 관리하기 위해서는 수동 작업은 권장되지 않습니다.
실제로는 자동으로 안정 상태가 유지되고, Kubernetes는 이런 요구를 충족하기위해 Liveness Probe를 사용합니다.

Liveness Probe는 POD에 의해 컨테이너를 동작시키고 동작중인 컨테이너의 상태를 주기적으로 모니터링합니다.
POD에서 오류가 발생하면 해당 컨테이너를 재 시작시킵니다. Kubernetes의 핵심 동작이 바로 이 Liveness Probe로 실행됩니다.


Liveness Probe는 세 가지 방식으로 컨테이너의 상태를 모니터링 합니다.

  • HTTP GET 프로브 : HTTP 요청 / 응답으로 확인
  • TCP 소켓 프로브 : 포트 연결 시도해서 확인
  • Exec 프로브 : 컨테이너 내부의 바이너리를 실행하고 종료 코드 확인

Liveness Probe는 POD의 상태를 감지하고 재시작하는 것으로 그 역할을 다 하지만 여러 사유로 인해 POD가 삭제되거나 NODE 자체에 장애가 발생하는 경우에는
POD를 재 시작 할 수 없습니다. 이러한 상황에 대비해 가용성을 높이기 위해서는 RC, RS, DS 등의 Controller를 사용해야 합니다.


Liveness Probe 생성


Liveness Probe 생성 - 정상 상태

apiVersion: v1
kind: Pod
metadata:
name: nasa-pod-liveness
spec:
containers:
- image: nginx:latest
    name: nasa
    ports:
    - containerPort: 8080
    protocol: TCP
    livenessProbe:
    httpGet:
        path: /
        port: 8080
  • HTTP GET 프로브를 사용하였으며, 경로는 / 포트는 8080 입니다.

Config Discription

  • livenessProbe: Liveness Probe 정의
  • httpGet : HTTP GET 프로브 정의
  • tcpSocket : TCP 소켓 프로브 정의
  • Exec: Exec 프로브 정의

작성한 YAML 파일로 POD를 생성합니다.

[root@nasa-master nasa]# kubectl apply -f nasa-pod-liveness.yml 
pod/nasa-pod-liveness created
[root@nasa-master nasa]# kubectl get pods --watch
NAME                READY   STATUS    RESTARTS   AGE
nasa-pod-liveness   1/1     Running   0          19s
  • 라이브니스의 확인을 위해 --watch 옵션을 사용해 지속적으로 모니터링합니다.

정상적인 상태를 확인했으니 비정상 상태를 만들어 보겠습니다.

apiVersion: v1
kind: Pod
metadata:
name: nasa-pod-liveness-error
spec:
containers:
- image: nginx:latest
    name: nasa
    ports:
    - containerPort: 8081
    protocol: TCP
    livenessProbe:
    httpGet:
        path: /
        port: 8082
  • 위의 YAML파일과 모두 동일하지만 PORT를 임의로 다르게 주어 error상태를 발생시킵니다.

POD 를 생성 후 모니터링 해보겠습니다

[root@nasa-master nasa]# kubectl apply -f nasa-pod-livness-error.yml 
pod/nasa-pod-liveness-error created
[root@nasa-master nasa]# kubectl get pods --watch
NAME                  READY   STATUS    RESTARTS   AGE
nasa-pod-liveness   1/1     Running   0          30s
nasa-pod-liveness-error   0/1     Pending   0          0s
nasa-pod-liveness-error   0/1     Pending   0          0s
nasa-pod-liveness-error   0/1     ContainerCreating   0          0s
nasa-pod-liveness-error   1/1     Running             0          5s
nasa-pod-liveness-error   1/1     Running             1          62s
nasa-pod-liveness-error   1/1     Running             2          2m1s
nasa-pod-liveness-error   1/1     Running             3          3m1s

WATCH로 모니터링중이던 터미널을 확인해보면 변화가 생겼습니다.

  • RESTARTS 필드가 0 에서 증가하는 것은 Liveness Probe가 해당 POD를 이상이 있는 것으로 판단하고 재 시작 시도 중임을 의미합니다.
nasa-pod-liveness-error   1/1     Running             4          4m2s
nasa-pod-liveness-error   1/1     Running             5          5m1s
nasa-pod-liveness-error   0/1     CrashLoopBackOff    5          5m58s
  • 잠시 후에 다시 확인해보면 상태가 CrashLoopBackOff 인 것을 확인할 수 있습니다.

POD의 Describe를 확인해보자

[root@nasa-master nasa]# kubectl describe pods nasa-pod-liveness-error
    ...
    ...
    State:          Running
    Started:      Fri, 17 Aug 2020 05:12:20 +0000
    Last State:     Terminated
    Reason:       Error
    Exit Code:    137
    Started:      Fri, 17 Aug 2020 05:11:20 +0000
    Finished:     Fri, 17 Aug 2020 05:12:16 +0000
    Ready:          True
    Restart Count:  3

Exit Code는 프로세스를 종료하기 위한 코드입니다. (137=128+9 , 9번 시그널 : SIGKILL)


종류

  • delay
  • timeout
  • period 가 추가로 존재 합니다.

컨테이너 실행 후로부터 모니터링을 시작하기까지 시간을 delay 모니터링사이에 시간 간격을 timeout으로 표기합니다.
POD가 실행되고 어플리케이션이 제대로 동작하기까지 시간이 걸리므로 초기 지연 시간을 initialDlaySecond 로 정의할 수 있습니다.
Event 필드는 POD의 상태를 시간대별로 확인할 수 있으며 이 경우 Liveness Probe에 문제가 있습니다는 사실을 확인할 수 있습니다.


✌ ReplicaSet (RS)

Kubernetes가 처음 나왔을 때는 POD를 복제하고 항상성을 유지시키기 위한 수단은 Replication Controller가 유일 했습니다.
그러나 Replication Controller의 몇 몇 문제점과 기능 개선을 위해 ReplicaSet이라는 Controller가 추가되었습니다. 최근에는 Replication Controller를 사용하지 않고 대부분 ReplicaSet을 사용하기에 Replication Controller에 대해서 다루진 않겠습니다.

Replication Controller와 ReplicaSet의 비교

  • POD의 다중 Label 지원
  • POD에 설정된 Label의 키만 선택 가능

Replication Controller에서는 POD의 여러 Label 중 하나의 Label에 대해서만 관리 POD를 지정할 수 있었고 반드시 Label의 key=value가 모두 일치해야만 POD를 지정할 수 있었습니다. 그러나 ReplicaSet은 다중 Label을 지정할 수 있고 key만 가지고도 Label을 지정할 수 있습니다.


ReplicaSet 생성

apiVersion: apps/v1 
kind: ReplicaSet 
metadata: 
name: replicaset-nasa 
spec: 
replicas: 3 
selector: 
    matchLabels: 
    app: nasa-nginx-pods-label 
template: 
    metadata: 
    name: nasa-nginx-pod 
    labels: 
        app: nasa-nginx-pods-label 
    spec: 
    containers: 
    - name: replicaset-nasa 
        image: nginx:latest 
        ports: 
        - containerPort: 80
  • Replication Controller에서는 Label Selector 항목에 Label을 직접 지정하지만 ReplicaSet은 matchLabelsmatchExpressions 필드로 Label을 선택합니다. ReplicaSet의 Label Selector는 kubectl explain replicaset.spec.selector로 지정할 수 있습니다.


pod와 다르게 추가된 내용만 있습니다. replicas는 생성할 pod의 개수를 설정합니다. 그리고 Replicas가 POD를 생성할 때 사용할 템플릿을 정의합니다.


생성 후 RS확인

[root@nasa-master nasa]# kubectl apply -f nasa-rs.yml 
replicaset.apps/replicaset-nasa created

ReplicaSet 동작 확인

[root@nasa-master nasa]# kubectl get replicasets.apps
NAME              DESIRED   CURRENT   READY   AGE
replicaset-nasa   3         3         3       3m9s

POD 확인

[root@nasa-master nasa]# kubectl get po
NAME                    READY   STATUS    RESTARTS   AGE
replicaset-nasa-7fvdx   1/1     Running   0          2m21s
replicaset-nasa-gbft4   1/1     Running   0          2m21s
replicaset-nasa-r84dt   1/1     Running   0          2m21s
  • 모두 정상적을 동작 합니다!! 하지만 RS의 기능 중의 하나를 더 알아 봅시다!

ReplicaSet Label Selector 사용

  • matchLabels Label Selector (matLabels Label Selector는 오브젝트 파일에서 다음과 같은 형식으로 정의합니다.
...
spec:
selector:
    matchLabels:
    key: value
...
  • matchLabels로 Label Selector를 사용하는 경우 Replication Controller와 ReplicaSet이 동일하게 동작합니다.

matchExpressions Label Selector

spec:
selector:
    matchExpressions:
    - key: <stirng>
    operator: <In | NotIn | Exists | DoesNotExist>
    values:
    - <string>
  • 위의 매치Label과 다른 점은 keyvalues를 따로 지정합니다는 점입니다.

operator 필드는 key와 value 사이의 연산을 담당하는 부분으로 아래 네 가지 중 하나를 선택해서 매칭시킬 수 있습니다.

  • In : Label의 키와 값이 지정된 값으로 일치해야 함
  • NotIn: Label의 키와 값이 지정된 값과 일치하지 않아야 함
  • Exists: Label의 키가 포함되어야 함
  • DoesNotExists: Label의 키가 포함되지 않아야 함

이번에는 같은 label을 갖고있는 replicas의 수를 증가시켜보겠습니다. yaml 파일의 replicas를 4로 변경하고 다시 실행하면 변경된 것을 확인 할 수 있습니다.

replicas: 4 
[root@nasa-master nasa]# vim nasa-rs.yml 
[root@nasa-master nasa]# 
[root@nasa-master nasa]# kubectl apply -f nasa-rs.yml 
replicaset.apps/replicaset-nasa configured

이전에는 created라는 출력이 나왔는데 이번에는 configured라는 출력이 나왔습니다.

[root@nasa-master nasa]# kubectl get po
NAME                    READY   STATUS    RESTARTS   AGE
replicaset-nasa-bpmbg   1/1     Running   0          52s
replicaset-nasa-lkv4h   1/1     Running   0          32s
replicaset-nasa-s2tlp   1/1     Running   0          52s
replicaset-nasa-wxhq6   1/1     Running   0          52s
  • POD도 확인해보면 이전에 생성되었던 POD는 종료되지 않고 새로운 POD만 추가 실행 된 것을 확인 할 수 있습니다.

동작 원리

ReplicaSet은 자동으로 복구해주고 생성을 확인하는 것을 보면 tracking 하고 있는 것 같습니다.

이러한 것은 어떻게 이루어 지는 것일까요??

  • ReplicaSet이 labelSelector로 같은 label을 갖고 있는 POD들을 계속 확인합니다. 실제로 동일한 label이 설정한 Replica 개수만큼 다시 복구해줍니다.
    그리고 동일한 POD의 개수가 Replicas에 설정한 개수와 같다면 특별한 작업을 진행하지 않습니다.
    결론적으로 ReplicaSet은 POD의 개수를 일정한 개수를 유지하는 기능을 합니다.

그리고 추가로 pod의 metadata 변경도 가능합니다.

  • edit 옵션을 사용해 특정 POD의 Label을 edit-test로 바꾸어 보았습니다
[root@nasa-master nasa]# kubectl edit pod replicaset-nasa-bpmbg
pod/replicaset-nasa-bpmbg edited
[root@nasa-master nasa]# 
[root@nasa-master nasa]# kubectl get po
NAME                    READY   STATUS              RESTARTS   AGE
replicaset-nasa-72hgn   0/1     ContainerCreating   0          4s
replicaset-nasa-bpmbg   1/1     Running             0          6m5s
replicaset-nasa-lkv4h   1/1     Running             0          5m45s
replicaset-nasa-s2tlp   1/1     Running             0          6m5s
replicaset-nasa-wxhq6   1/1     Running             0          6m5s
[root@nasa-master nasa]#
[root@nasa-master nasa]#
[root@nasa-master nasa]#
[root@nasa-master nasa]# kubectl get po --show-labels
NAME                    READY   STATUS    RESTARTS   AGE     LABELS
replicaset-nasa-72hgn   1/1     Running   0          66s     app=nasa-nginx-pods-label
replicaset-nasa-bpmbg   1/1     Running   0          7m7s    app=edit-test
replicaset-nasa-lkv4h   1/1     Running   0          6m47s   app=nasa-nginx-pods-label
replicaset-nasa-s2tlp   1/1     Running   0          7m7s    app=nasa-nginx-pods-label
replicaset-nasa-wxhq6   1/1     Running   0          7m7s    app=nasa-nginx-pods-label

👀 DaemonSet (DS)

  • DaemonSet은 모든 NODE가 POD의 사본을 실행하도록 하는 역할을 합니다.
    Kubernetes 클러스터에서 NODE가 추가되면 POD도 추가됩니다.
    NODE가 클러스터에서 제거되면 해당 POD는 가비지(garbage)로 넘어갑니다. DaemonSet을 삭제하면 DaemonSet이 생성한 POD들도 정리됩니다.

DaemonSet의 정확한 용도는 다음과 같습니다.

  • 모든 NODE에서 클러스터 스토리지 데몬 실행
  • 모든 NODE에서 로그 수집 데몬 실행
  • 모든 NODE에서 NODE 모니터링 데몬 실행


이러한 작업의 처리를 위해서 모든 NODE 단위로 커버하는 DaemonSet이 사용됩니다.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nasa-ds
spec:
  selector:
    matchLabels:
      app: nasa-ds
  template:
    metadata:
      labels:
        app: nasa-ds
    spec:
      nodeSelector:
        node: nasa  
      containers:
      - name: nasa
        image: nginx:latest
        ports:
          - containerPort: 80
  • apiVersion apps/v1 → Kubernetes의 apps/v1 API를 사용 합니다.
  • kind: DaemonSet → DaemonSet의 작업으로 명시 합니다.
  • metadata.name → DaemonSet의 이름을 설정 합니다.
  • metadata.namespace → 네임스페이스를 지정 합니다.
  • metadata.labels → DaemonSet를 식별할 수 있는 Label을 지정 합니다.
  • spec.selector.matchLabels → 어떤 Label의 POD를 선택하여 관리할 지 설정 합니다.
  • spec.template.metadata.labels.name → 생성할 POD의 Label을 POD명: ” ” 으로 지정 합니다.
  • spec.template.spec.containers → 하위 옵션들은 컨테이너의 설정을 정의합니다.

DaemonSet 생성

[root@nasa-master nasa]# kubectl apply -f nasa-ds.yml 
daemonset.apps/nasa-ds created

[root@nasa-master nasa]# kubectl get ds
NAME      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
nasa-ds   0         0         0       0            0           node=nasa       32s
  • 시간이 충분이 지난 후에도 DESIRED, CURRENT, READY 탭의 값이 모두 0입니다. POD가 아예 생성되지 않습니다.
    이유는 정의할 때 NODE Selector로 node=nasa Label을 선택하도록 했기에 매칭되는 NODE가 없으므로 아무 POD도 생성되지 않은 것입니다.

DaemonSet 동작을 위해 NODE를 지정해보겠습니다.

[root@nasa-master nasa]# kubectl label nodes nasa-node1 node=nasa
node/nasa-node1 labeled

다시 한번 DaemonSet을 확인해보면

[root@nasa-master nasa]# kubectl get nodes nasa-node1 --show-labels
NAME         STATUS   ROLES    AGE   VERSION   LABELS
nasa-node1   Ready    <none>   24d   v1.15.5   ... .... ,node=nasa
[root@nasa-master nasa]# kubectl get daemonsets.apps 
NAME      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
nasa-ds   1         1         1       1            1           node=nasa       6m1s

DaemonSet이 동작함에 의해 POD가 1개 생성 되었습니다.

[root@nasa-master nasa]# kubectl get pods
NAME                    READY   STATUS    RESTARTS   AGE
nasa-ds-7jsgd           1/1     Running   0          106s

테스트를 모두 완료했으니 NODE와 DS를 삭제합니다!

[root@nasa-master nasa]# kubectl label nodes nasa-node1 node-
node/nasa-node1 labeled


🐱‍🏍 JOB

  • JOB Controller는 POD의(컨테이너)의 어플리케이션(JOB) 실행 완료에 초점을 맞춘 Controller입니다.
    즉, 끝이 정해진 작업을 하는 어플리케이션을 JOB Controller가 관리합니다.
    POD가 작업을 마치고 성공적으로 종료되면 JOB Controller는 성공적으로 완료된 JOB을 추적합니다. JOB을 삭제하면 JOB이 생성한 POD도 정리됩니다.
    물론 POD가 중간에 실패하는 경우 JOB 오브젝트는 새로운 POD를 가동시킨다. JOB은 임시 작업, 배치 작업에 유용하게 사용될 수 있습니다.
    JOB Controller는 RC, RS, DS처럼 계속 동작하는 방식이 아니라 재시작 정책(restartPolicy)을 기본값이 Always가 아닌 Onfailuer나 Never로 선언해야 합니다.
    이렇게 하면 JOB Controller의 POD는 재 실행되지 않습니다.

job.spec.template.spec.restartPolicy

  • Always : 종료/실패시 항상 재시작(default)
  • Onfailure: 실패식 재시작 (정상 종료시 재시작하지 않음)
  • Never : 종료 또는 오류 발생시 재시작하지 않음

JOB Controller 생성

apiVersion: batch/v1
kind: Job
metadata:
name: nasa-job
spec:
template:
    metadata:
    labels:
        app: nasa-job
    spec:
    restartPolicy: OnFailure
    containers:
    - name: nasa
        image: busybox
        command: ["sleep", "60"]
[root@nasa-master nasa]# kubectl apply -f nasa-jop.yml 
job.batch/nasa-job created

JOB Controller를 확인해보겠습니다.

[root@nasa-master nasa]# kubectl get job.batch
NAME       COMPLETIONS   DURATION   AGE
nasa-job   0/1           33s        33s


[root@nasa-master nasa]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
nasa-job-84s8x   1/1     Running   0          40s

하나의 POD가 있고 아직 JOB이 완료되지 않아서 COMPLETIONS에 0/1이라고 표기됩니다. POD는 정상 동작중입니다.

[root@nasa-master nasa]# kubectl get job.batch
NAME       COMPLETIONS   DURATION   AGE
nasa-job   1/1           64s        104s
[root@nasa-master nasa]# 


[root@nasa-master nasa]# kubectl get pods
NAME             READY   STATUS      RESTARTS   AGE
nasa-job-84s8x   0/1     Completed   0          107s
  • 다시 POD를 다시 확인 해보니 STATUS가 Completed로 표기되고 JOB Controller에서도 확인해보니 COMPLETIONS가 1/1로 바뀌었습니다. (JOB 완료)

다중 JOB Controller

spec:
completions: 3
  • completions: 3 설정만 YAML 파일에 추가해주면 여러 번의 작업을 값만 큼 순차적으로 실행합니다.
    하나의 POD가 생성되어 JOB이 실행되고 완료되면 두 번째 POD가 생성되고 완료되고 , 그 다음 POD가 생성되고 완료되기를 지정된 횟수만큼 반복하는 것입니다.

병렬 다중 JOB Controller

spec:
completions: 3
parallelism: 3

( 병렬로 처리하기 위해서는 parallelism: 3 설정을 추가해주면 됩니다 그럼 3개의 3이 동시에 3번의 작업을 진행합니다!!


🎶 CRONJOB

  • JOB Controller에서 JOB을 실행하는 목적은 끝이 있는 작업을 하는 어플리케이션 때문입니다. CRONJOB은 이름에서 알 수 있듯이 주기적으로 반복된 작업을 하며, 그 작업이 시작과 끝이 있는 작업일 때 사용합니다. 리눅스의 crontab과 같습니다.

이론 보다는 실습!! 바로 CRONJOB을 생성해보겠습니다.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello World
spec:
schedule: "*/1 * * * *"
jobTemplate:
    spec:
    template:
        spec:
        containers:
        - name: hello World
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello NASA! from the Kubernetes cluster
        restartPolicy: OnFailure

가장 중요한 부분은 스케줄 필드로, cronjob.spec.schedule 필드를 사용해 주기적인 시간을 구성합니다.

  • 스케줄을 구성하는 값은 다섯 개의 필드로 구분되어 다음과 같은 순서입니다.

그냥 리눅스랑 똑같다!

  • 요일(0 : 일요일, 1: 월요일, 6: 토요일)
[root@nasa-master nasa]# kubectl apply -f nasa-cron.yml 
cronjob.batch/hello created

생성 후 CRON JOB Controller 및 POD 확인

[root@nasa-master nasa]# kubectl get cronjobs.batch
NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        <none>          28s
  • 최초 생성된 직후 ACTIVE 상태의 JOB은 없습니다. 마지막으로 동작한 LAST SCHEDULE도 없습니다.

잠시 기다린 후에 다시 조회해보면 다음과 같이 변합니다.

[root@nasa-master nasa]# kubectl get cronjobs.batch
NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     1        10s             4m

POD를 조회해보면 다음과 같습니다.

[root@nasa-master nasa]# kubectl get po
\NAME                     READY   STATUS      RESTARTS   AGE
hello-1600331820-5jmd4   0/1     Completed   0          2m36s
hello-1600331880-jhs6s   0/1     Completed   0          96s
hello-1600331940-kkzwh   0/1     Completed   0          36s

CRONJOB Controller의 제한사항

  • CRONJOB Controller는 일정 실행시간마다 하나의 JOB 오브젝트를 생성합니다. 특정한 상황에서는 하나가 아닌 여러 개의 JOB이 생성되는 경우도 있습니다. 이러한 상황을 제어하기 위해서 CRONJOB Controller에서는 JOB의 제한사항을 지정할 수 있습니다.

cronjob.spec.startingDeadlineSeconds : 시작 데드라인 시간

  • 어떤 이유든 예정된 시간에 JOB을 시작해야 하는 데드라인. 초단위로 입력해서 현재로부터 n초 안에 일정을 놓친 JOB이 있는지 확인.

cronjob.spec.concurrrencyPolicy : 동시 실행 정책

  • Allow: JOB이 동시 실행될 수 있음(default)
  • Forbid: 동시 실행 금지. JOB이 아직 완료되지 않은 경우 다음 JOB을 건너 뜀.
  • Replace: 현재 실행중인 JOB을 취소하고 새 JOB으로 교체

위 설정들을 예를들면 startingDeadlineSeconds가 100초이고, concurrencyPolicy가 Allow이면 이전에 놓친 JOB이 있으면 해당 JOB을 실행하게 됩니다.

spec:
schedule: "*/1 * * * *"
startingDeadlineSeconds: 10
concurrencyPolicy: Forbid

Tags

#Kubernetes
NASA1515

NASA1515

Data Engineer

Hello I'M Wonseok aka NASA1515

Expertise

Public Cloud
k8s/Docker
Python

Social Media

instagramwebsitelinkedingithub

Related Posts

[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
[Kubernetes] VSCode (VisualStudio Code)로 Kubernetes 클러스터 관리 : 초보자를 위한 완벽 가이드
2021-08-19
2 min

Topics

CloudDevelop

Social Media