Kubernetes Controller

HamJina·2026년 9월 13일

Kubernetes

목록 보기
3/3

3. Controller

Controller란 무엇인가

Pod를 직접 만들면 관리는 사람의 몫이 된다. Pod가 죽어도 아무도 다시 만들어주지 않고, 트래픽이 늘어도 알아서 늘어나지 않으며, 버전을 올리려면 일일이 지우고 다시 만들어야 한다.

Controller는 Pod를 대신 관리해 주는 오브젝트다. 사용자가 원하는 상태를 선언해 두면, Controller가 현재 상태를 계속 감시하면서 그 상태에 맞추는 작업을 수행한다.

   [ Pod만 직접 만들 때 ]              [ Controller를 쓸 때 ]

   Pod가 죽음                          Pod가 죽음
        │                                   │
        ▼                                   ▼
   사람이 인지                         Controller가 즉시 인지
        │                                   │
        ▼                                   ▼
   사람이 다시 생성                    자동으로 새 Pod 생성

Controller가 제공하는 기능은 네 가지다.

기능설명사용하는 Controller
Auto Healing죽은 Pod를 감지해 새로 만든다ReplicationController, ReplicaSet, DaemonSet
Auto Scaling부하에 따라 Pod 수를 늘리고 줄인다HPA
Software Update여러 Pod의 버전을 일괄 업그레이드한다Deployment
Job필요한 순간에만 Pod를 만들어 작업을 수행한다Job, CronJob

3-1. Controller의 네 가지 기능

Auto Healing

Pod가 죽거나 Pod가 올라가 있는 Node 자체에 장애가 발생하면, Controller가 즉각적으로 인지해서 다른 Node에 Pod를 새로 만든다.

   ┌──────────────────┐
   │   Controller     │  ← 상태를 계속 감시
   └────┬────────┬────┘
        │        │
   장애 인지     새로 생성
        │        │
        ▼        ▼
  ┌──────────┐  ┌──────────┐
  │  Node1   │  │  Node2   │
  │ ┌──────┐ │  │ ┌──────┐ │
  │ │ Pod1 │ │  │ │ Pod1 │ │  ← 새 Node에 다시 생성
  │ │  ✗   │ │  │ │  ✓   │ │
  │ └──────┘ │  │ └──────┘ │
  │  ⚠ 장애  │  │          │
  └──────────┘  └──────────┘

사람이 개입하기 전에 복구가 끝나므로, 엔지니어는 복구 이력만 확인하면 된다.

담당 Controller: ReplicationController, ReplicaSet, DaemonSet

Auto Scaling

Pod의 리소스 사용량이 limit에 도달한 상태를 Controller가 인지하면, Pod를 하나 더 만들어서 부하를 분산시킨다.

   ┌──────────────────┐
   │   Controller     │  ← 리소스 사용량 감시
   └────────┬─────────┘
            │  Pod1이 limit 도달
            ▼
   ┌──────┐        ┌──────────┐
   │ Pod1 │ ─┬───▶ │  Pod1    │  부하 50%
   │ ███  │  │     │  ██      │
   │ 한계 │  │     └──────────┘
   └──────┘  │     ┌──────────┐
             └───▶ │  Pod2    │  부하 50%
                   │  ██      │  ← 새로 생성
                   └──────────┘

Pod를 늘려 부하를 나누므로 서비스가 느려지거나 멈추는 상황을 막을 수 있다.

담당 Controller: HPA (Horizontal Pod Autoscaler)

Software Update

여러 개의 Pod를 한 번에 새로운 버전으로 업그레이드한다. 업데이트 중 문제가 생기면 이전 버전으로 되돌리는 것도 가능하다.

   ┌──────────────────┐
   │   Controller     │
   └────────┬─────────┘
            │
   ┌────────┴─────────────────────┐
   │                              │
   ▼                              ▼
 v1 v1 v1                     v2 v2 v2
 ┌──┐┌──┐┌──┐    ──────▶     ┌──┐┌──┐┌──┐
 │P1││P2││P3│                │P1││P2││P3│
 └──┘└──┘└──┘                └──┘└──┘└──┘
 v1 v1 v1                     v2 v2 v2
 ┌──┐┌──┐┌──┐                ┌──┐┌──┐┌──┐
 │P4││P5││P6│                │P4││P5││P6│
 └──┘└──┘└──┘                └──┘└──┘└──┘

담당 Controller: Deployment

Job

일시적인 작업을 해야 하는 경우, Controller가 필요한 순간에만 Pod를 만든다. 작업이 끝나면 Pod가 사용하던 자원을 반납한다.

   ┌──────────────────┐
   │   Controller     │
   └───┬──────────┬───┘
       │          │
       ▼          ▼
  ┌─────────┐ ┌─────────┐ ┌─────────┐
  │  Pod    │ │  Pod    │ │  Pod    │
  │ (없음)  │→│ (실행)  │→│ (종료)  │
  └─────────┘ └─────────┘ └─────────┘
  Resource    Resource     Resource
  ┌─┐┌─┐┌─┐   ┌─┐┌ ┐┌ ┐    ┌─┐┌─┐┌─┐
  └─┘└─┘└─┘   └─┘└ ┘└ ┘    └─┘└─┘└─┘
  자원 여유    자원 사용중   자원 반납

Pod를 계속 띄워두지 않으므로 자원을 효율적으로 사용할 수 있다.

담당 Controller: Job, CronJob


3-2. ReplicationController와 ReplicaSet

두 Controller의 관계

Controller상태
ReplicationControllerDeprecated (더 이상 사용하지 않음)
ReplicaSetReplicationController를 대체(Replaced) 한 Controller

역할은 같지만 ReplicaSet이 더 발전된 selector 기능을 갖추면서 ReplicationController를 대체했다. 현재는 ReplicaSet을 사용한다.

두 Controller는 세 가지 요소로 구성된다.

구성 요소역할
Template새로 만들 Pod의 내용을 정의한다
ReplicasPod를 몇 개로 유지할지 정한다
Selector어떤 Pod를 관리 대상으로 삼을지 고른다

Template

Controller를 만들 때 Pod의 내용을 템플릿으로 넣어둔다. Controller가 Pod를 새로 만들어야 할 때 이 템플릿을 그대로 사용한다.

   ┌──────────────────────────────┐
   │       Replication            │
   │                              │        ┌──────────┐
   │  selector    template        │        │ Pod:v2   │
   │  ┌────────┐  ┌──────────┐    │        │          │
   │  │type:web│  │  Pod:v2  │◀───┼────────│ Template │
   │  └────────┘  └──────────┘    │        │  Update  │
   └───────┬──────────────────────┘        └──────────┘
           │
     Re-create
           │
   ┌───────┴──────┬──────────────┐
   ▼              ▼              ▼
┌────────┐   ┌────────┐    ┌──────────┐
│  Pod   │   │  Pod   │    │  Pod:v2  │
│type:web│   │type:web│    │ type:web │
│  ⚠     │   │   ✗    │    │    ✓     │
└────────┘   └────────┘    └──────────┘
  기존 Pod    삭제하면       템플릿대로
              새로 생성됨     v2로 생성

여기서 중요한 동작이 있다. 템플릿을 v2로 수정해도 이미 실행 중인 Pod는 그대로 남는다. 기존 Pod를 삭제해야 그때 템플릿을 보고 v2 Pod가 새로 만들어진다.

이 성질을 이용하면 Pod를 하나씩 지우면서 버전을 올리는 것이 가능하다. 다만 수작업이므로, 실제 버전 업그레이드는 뒤에 나올 Deployment가 담당한다.

Pod를 직접 만드는 경우

apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
    type: web
spec:
  containers:
    - name: container
      image: tmkube/app:v1

ReplicationController로 만드는 경우

apiVersion: v1
kind: ReplicationController
metadata:
  name: replication-1
spec:
  replicas: 1
  selector:
    type: web
  template:
    metadata:
      name: pod-1
      labels:
        type: web
    spec:
      containers:
        - name: container
          image: tmkube/app:v2
항목설명
replicas유지할 Pod의 개수
selector관리 대상 Pod를 고르는 조건
template새 Pod를 만들 때 사용할 내용. Pod YAML의 metadataspec이 그대로 들어간다

template 안의 내용이 앞의 Pod YAML과 동일한 구조라는 점을 보면 이해하기 쉽다. Pod 정의를 Controller 안에 그대로 넣어둔 것이다.

Replicas

지정한 개수만큼 Pod가 유지되도록 관리한다.

   ┌──────────────────┐          ┌──────────────────┐
   │   Replication    │          │   Replication    │
   │                  │          │                  │
   │   replicas       │          │  replicas  template
   │   ┌────┐         │          │  ┌────┐  ┌──────┐│
   │   │ 3  │         │          │  │ 2  │  │ Pod  ││
   │   └────┘         │          │  └────┘  └──────┘│
   └──┬────┬────┬─────┘          └───┬──────────┬───┘
      │    │    │                    │    ⚠     │
      │    │    │  Scale Out         │  Pod 삭제 │
      ▼    ▼    ▼                    ▼          ▼
   ┌───┐┌───┐┌───┐                ┌───┐      ┌───┐
   │Pod││Pod││Pod│                │Pod│      │Pod│
   └───┘└───┘└───┘                └───┘      └───┘
                                        새로 생성됨
상황Controller의 동작
replicas를 1에서 3으로 변경Pod를 2개 더 만든다 (Scale Out)
Pod 하나가 삭제되거나 죽음개수를 채우기 위해 새 Pod를 만든다 (Auto Healing)
replicas를 3에서 1로 변경Pod 2개를 삭제한다 (Scale In)

여기서 알 수 있는 것은 Auto Healing과 Auto Scaling이 사실 같은 동작이라는 점이다. Controller는 "지정된 개수를 유지한다"는 하나의 원칙만 수행하며, 그 결과가 상황에 따라 복구로도 보이고 확장으로도 보이는 것이다.

또한 죽은 Pod를 되살리는 것이 아니라 항상 새 Pod를 만든다. 따라서 Pod 안에 저장한 데이터는 복구되지 않는다.

Selector

어떤 Pod를 관리 대상으로 삼을지 고르는 조건이다. Service의 selector가 트래픽을 보낼 Pod를 고르는 것과 같은 방식이다.

ReplicationController와 ReplicaSet의 가장 큰 차이가 여기에 있다.

   ReplicationController          ReplicaSet
   ─────────────────────          ──────────────────────────
   ┌──────────────┐               ┌──────────────────────────┐
   │  type: web   │               │ matchLabels  matchExpressions
   │              │               │ ┌────────┐  ┌───────────┐│
   │  (값이 정확히│               │ │type:web│  │key: ver   ││
   │   같아야 함) │               │ └────────┘  │operator:  ││
   └──────────────┘               │             │  Exists   ││
                                  │             └───────────┘│
                                  └──────────────────────────┘
구분ReplicationControllerReplicaSet
지정 방식값이 정확히 일치하는 조건만 가능matchLabels + matchExpressions
표현력단순key의 존재 여부, 포함, 제외까지 표현 가능

선택 결과 예시

세 개의 Pod가 있다고 하자.

  ┌────────────┐  ┌────────────┐  ┌────────────┐
  │   Pod1     │  │   Pod2     │  │   Pod3     │
  │ type: web  │  │ type: web  │  │ type: db   │
  │ ver : v1   │  │ ver : alpha│  │ ver : beta │
  └────────────┘  └────────────┘  └────────────┘
Controller조건선택되는 Pod
ReplicationControllertype: webPod1, Pod2
ReplicaSetmatchLabels: type: web + matchExpressions: {key: ver, operator: Exists}Pod1, Pod2

ReplicaSet에서 두 조건이 모두 지정되면 둘 다 만족하는 Pod만 선택된다.

matchExpressions의 operator

matchExpressions는 네 가지 연산자를 제공한다.

        Exists                          DoesNotExist
  ┌──────────────────┐            ┌──────────────────┐
  │   ReplicaSet     │            │   ReplicaSet     │
  │   Key: A         │            │   Key: A         │
  └──────────────────┘            └──────────────────┘
   ┌────┐┌────┐┌────┐              ┌────┐┌────┐┌────┐
   │Pod1││Pod2││Pod3│              │Pod1││Pod2││Pod3│
   │A:1 ││A:2 ││B:2 │              │A:1 ││A:2 ││B:2 │
   └────┘└────┘└────┘              └────┘└────┘└────┘
     ✓     ✓     ✗                   ✗     ✗     ✓
   A라는 key가 있으면 선택          A라는 key가 없으면 선택


          In                              NotIn
  ┌──────────────────┐            ┌──────────────────┐
  │   ReplicaSet     │            │   ReplicaSet     │
  │   Key: A         │            │   Key: A         │
  │   Values: 2,3    │            │   Values: 2,3    │
  └──────────────────┘            └──────────────────┘
   ┌────┐┌────┐┌────┐              ┌────┐┌────┐┌────┐
   │Pod1││Pod2││Pod3│              │Pod1││Pod2││Pod3│
   │A:1 ││A:2 ││A:3 │              │A:1 ││A:2 ││A:3 │
   └────┘└────┘└────┘              └────┘└────┘└────┘
     ✗     ✓     ✓                   ✓     ✗     ✗
   값이 2 또는 3이면 선택           값이 2, 3이 아니면 선택
operator조건필요한 항목
Exists해당 key가 존재하면 선택key
DoesNotExist해당 key가 없으면 선택key
Inkey의 값이 values 안에 있으면 선택key, values
NotInkey의 값이 values 안에 없으면 선택key, values

값을 정확히 알지 못해도 "버전 정보가 붙어 있는 Pod 전부"처럼 유연한 조건을 만들 수 있다는 것이 ReplicaSet의 장점이다.

ReplicaSet YAML

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica-1
spec:
  replicas: 3
  selector:
    matchLabels:
      type: web
    matchExpressions:
      - {key: ver, operator: Exists}
  template:
    metadata:
      name: pod
      labels:
        type: web
        ver: v1
    spec:
      containers:
        - name: container
          image: tmkube/app
항목설명
apiVersion: apps/v1ReplicaSet은 v1이 아니라 apps/v1 을 사용한다
replicas: 3Pod 3개를 유지한다
matchLabels값이 정확히 일치해야 하는 조건
matchExpressionskey의 존재 여부나 포함 관계로 지정하는 조건
template새 Pod를 만들 때 사용할 정의

주의할 점 — template의 label은 selector를 만족해야 한다

selector 조건과 templatelabels가 맞지 않으면 문제가 생긴다.

   selector: type: web        template의 labels: type: db
        │                              │
        │  조건에 맞는 Pod를 찾음      │  이 Pod를 만듦
        ▼                              ▼
   조건에 맞는 Pod가 없음  ──────▶  계속 새 Pod 생성
                                       │
                                   무한 반복

Controller가 만든 Pod를 자기 자신이 인식하지 못하므로, 개수를 채우려고 Pod를 계속 만들어내게 된다. 쿠버네티스는 이런 설정을 아예 거부하여 ReplicaSet 생성을 막는다.

3-3. Deployment

Deployment란

Deployment는 Software Update를 담당하는 Controller다. 앞에서 본 ReplicaSet은 Pod의 개수를 유지할 뿐, 버전을 올리는 기능은 없었다.

Deployment는 ReplicaSet을 직접 관리하면서 버전 업그레이드를 처리한다.

   Deployment  ──관리──▶  ReplicaSet  ──관리──▶  Pod
   (버전 관리)            (개수 유지)          (실행)

사용자는 Deployment만 만들면 된다. ReplicaSet은 Deployment가 알아서 생성하고 관리한다.

배포 방식의 종류

Deployment는 두 가지 배포 방식을 직접 지원하고, 나머지 두 가지는 Service와 조합해 구현한다.

배포 방식Deployment 지원다운타임추가 자원
ReCreate지원 (strategy: Recreate)발생없음
Rolling Update지원 (strategy: RollingUpdate, 기본값)없음배포 중 일부 증가
Blue/Green미지원 (Controller 2개 + Service 활용)없음2배
Canary미지원 (Service + Ingress 활용)없음일부 증가

3-3-1. ReCreate

개념

기존 Pod를 전부 삭제한 뒤 새 버전의 Pod를 만드는 방식이다. 가장 단순하지만 다운타임이 발생한다.

동작 과정

v1 Pod 2개를 v2로 올리는 상황이다.

① 초기 상태

              ┌──────────────┐
              │   Service    │
              └──┬────────┬──┘
                 │        │
          ┌──────▼──┐ ┌───▼─────┐
          │ Pod v1  │ │ Pod v1  │
          └─────────┘ └─────────┘

   자원 사용량:  ██ ██        (2개)
   서비스 상태:  정상

② v1 Pod를 모두 삭제

              ┌──────────────┐
              │   Service    │
              └──────────────┘
                 연결할 Pod 없음

          ┌─────────┐ ┌─────────┐
          │ Pod v1  │ │ Pod v1  │
          │    ✗    │ │    ✗    │
          └─────────┘ └─────────┘

   자원 사용량:  □□ □□        (0개, 자원도 함께 반납됨)
   서비스 상태:  ⚠ Downtime 발생

이 시점에 사용자가 접속하면 연결할 Pod가 없어 서비스가 중단된다.

③ v2 Pod 2개 생성

              ┌──────────────┐
              │   Service    │
              └──┬────────┬──┘
                 │        │
          ┌──────▼──┐ ┌───▼─────┐
          │ Pod v2  │ │ Pod v2  │
          └─────────┘ └─────────┘

   자원 사용량:  ██ ██        (2개)
   서비스 상태:  정상 복구

자원 사용량의 변화

   사용량
     │
   2 │ ██ ██              ██ ██
     │
   0 │        □□ □□
     └────────────────────────────▶ 시간
       초기    삭제 후     생성 후
              (Downtime)

배포 중 자원 사용량이 0으로 떨어진다. 추가 자원이 필요 없다는 것이 유일한 장점이다.

YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-1
spec:
  selector:
    matchLabels:
      type: app
  replicas: 2
  strategy:
    type: Recreate
  revisionHistoryLimit: 1
  template:
    metadata:
      labels:
        type: app
    spec:
      containers:
        - name: container
          image: tmkube/app:v1
항목설명
strategy.type: Recreate전부 삭제 후 재생성하는 방식을 사용한다
revisionHistoryLimit롤백을 위해 보관할 이전 ReplicaSet의 개수. 기본값은 10

내부에서 일어나는 일

Deployment는 ReplicaSet의 replicas 수를 조절하는 방식으로 동작한다.

   ┌────────────────────────────────────────────┐
   │              Deployment                     │
   │   selector   replicas   template            │
   │   type:app      2       Pod v2  ◀── 템플릿 변경
   └───────┬────────────────────┬───────────────┘
           │                    │
    ┌──────▼──────┐      ┌──────▼──────┐
    │ ReplicaSet  │      │ ReplicaSet  │
    │  (v1용)     │      │  (v2용)     │
    │ replicas 0  │      │ replicas 2  │
    └─────────────┘      └──────┬──────┘
      Pod 없음                  │
                         ┌──────┴──────┐
                         ▼             ▼
                   ┌─────────┐   ┌─────────┐
                   │ Pod v2  │   │ Pod v2  │
                   └─────────┘   └─────────┘

기존 ReplicaSet의 replicas2에서 0으로 내리고, 새 ReplicaSet의 replicas0에서 2로 올린다. 두 작업이 순차적으로 일어나므로 그 사이에 Pod가 하나도 없는 구간이 생긴다.

기존 ReplicaSet은 삭제되지 않고 replicas: 0 상태로 남는다. 롤백할 때 다시 이 값을 올리기 위해서다.

사용하는 경우

  • 개발 환경처럼 다운타임이 허용되는 경우
  • v1과 v2가 동시에 떠 있으면 안 되는 경우 (같은 DB 스키마를 공유하는데 호환되지 않는 경우 등)

3-3-2. Rolling Update

개념

Pod를 하나씩 교체하는 방식이다. Deployment의 기본값이며, 다운타임이 없다.

동작 과정

replicas: 2, 기본값인 maxSurge: 1, maxUnavailable: 0 기준이다. Pod 개수는 2 → 3 → 2 → 3 → 2로, 3에서 머무르지 않고 매번 2로 돌아온 뒤 다시 늘어난다.

① 초기 상태 (2개)

              ┌──────────────┐
              │   Service    │
              └──┬────────┬──┘
                 │        │
          ┌──────▼──┐ ┌───▼─────┐
          │ Pod v1  │ │ Pod v1  │
          └─────────┘ └─────────┘

   자원 사용량:  ██ ██        (2개)

② v2 Pod 하나 생성 → Ready 대기 (3개)

              ┌──────────────────┐
              │     Service      │
              └──┬───────┬────┬──┘
                 │       │    │
          ┌──────▼──┐ ┌──▼───┐ ┌─▼──────┐
          │ Pod v1  │ │Pod v1│ │Pod v2  │  ← 새로 생성, Ready 대기
          └─────────┘ └──────┘ └────────┘

   자원 사용량:  ██ ██ ██     (3개, 증가)
   서비스 상태:  v1과 v2가 동시에 서비스 중

여기가 Rolling Update의 특징이다. 이 시점에 접속하는 사용자는 v1에 연결될 수도 있고 v2에 연결될 수도 있다. Service가 두 버전의 Pod에 모두 트래픽을 분배하기 때문이다.

③ v2가 Ready 되면, v1 하나 삭제 (2개로 감소)

              ┌──────────────┐
              │   Service    │
              └──┬────────┬──┘
                 │        │
          ┌──────▼──┐ ┌───▼─────┐
          │ Pod v1  │ │ Pod v2  │
          └─────────┘ └─────────┘

   자원 사용량:  ██ ██        (2개, 다시 감소)
   서비스 상태:  v1 1개, v2 1개

maxUnavailable: 0이므로 새 Pod가 Ready 상태가 되어야만 기존 Pod를 삭제한다. "삭제"와 "생성"은 동시에 일어나는 것이 아니라 항상 하나씩 순차적으로 일어난다.

④ v2 Pod 하나 더 생성 → Ready 대기 (3개로 증가)

              ┌──────────────────┐
              │     Service      │
              └──┬───────┬────┬──┘
                 │       │    │
          ┌──────▼──┐ ┌──▼───┐ ┌─▼──────┐
          │ Pod v1  │ │Pod v2│ │Pod v2  │  ← 새로 생성, Ready 대기
          └─────────┘ └──────┘ └────────┘

   자원 사용량:  ██ ██ ██     (3개, 다시 증가)
   서비스 상태:  v1 1개, v2 2개

⑤ 남은 v1 삭제 → 완료 (2개)

              ┌──────────────┐
              │   Service    │
              └──┬────────┬──┘
                 │        │
          ┌──────▼──┐ ┌───▼─────┐
          │ Pod v2  │ │ Pod v2  │
          └─────────┘ └─────────┘

   자원 사용량:  ██ ██        (2개, 원상 복귀)
   서비스 상태:  정상

자원 사용량의 변화

   사용량
     │
   3 │      ██        ██
     │     ╱  ╲       ╱ ╲
   2 │ ██ ╱    ██   ╱     ██
     │
     └──────────────────────────▶ 시간
       초기  생성  삭제  생성  삭제
             (v2)  (v1) (v2)  (v1)

3에서 머무르지 않고 생성 → 삭제 → 생성 → 삭제를 한 번에 한 동작씩 순서대로 밟으며 3과 2 사이를 오간다. Pod 개수가 많아질수록 이 오르내림이 그만큼 더 반복된다. 배포 중 일시적으로 추가 자원을 요구한다는 것이 ReCreate와의 차이이며, 대신 다운타임이 없다.

내부에서 일어나는 일

   ┌────────────────────────────────────────────┐
   │              Deployment                     │
   │   selector   replicas   template            │
   │   type:app      2       Pod v2              │
   └───────┬────────────────────┬───────────────┘
           │                    │
    ┌──────▼──────┐      ┌──────▼──────┐
    │ ReplicaSet  │      │ ReplicaSet  │
    │  (v1용)     │      │  (v2용)     │
    │ 2 → 2 → 1 → │      │ 0 → 1 → 1 → │
    │     1 → 0   │      │     2 → 2   │
    └─────────────┘      └─────────────┘
       한 번에 한 칸씩만 움직인다

한 번에 한 ReplicaSet의 값만 1씩 움직이며, 두 ReplicaSet의 합이 replicas + maxSurge(여기선 3)를 넘지 않고 replicas - maxUnavailable(여기선 2) 밑으로 내려가지도 않도록 조절된다.

ReCreate가 2 → 00 → 2로 한 번에 크게 움직였다면, Rolling Update는 한 칸씩 번갈아 가며 조절한다. 그래서 두 버전의 Pod가 잠시 공존한다.

YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-2
spec:
  selector:
    matchLabels:
      type: app
  replicas: 2
  strategy:
    type: RollingUpdate
  minReadySeconds: 10
  template:
    metadata:
      labels:
        type: app
    spec:
      containers:
        - name: container
          image: tmkube/app:v1
항목설명
strategy.type: RollingUpdate하나씩 교체하는 방식. 생략해도 기본값
minReadySecondsPod가 Ready 상태가 된 후 다음 Pod로 넘어가기까지 대기할 시간(초)

minReadySeconds가 필요한 이유가 있다. Pod가 Ready 상태가 되었더라도 애플리케이션이 완전히 안정화되지 않았을 수 있다. 이 값을 두면 각 단계마다 잠시 기다리므로, 문제가 있는 버전이 한꺼번에 배포되는 것을 막을 수 있다.

주의할 점

v1과 v2가 동시에 서비스되는 구간이 있으므로, 두 버전이 공존해도 문제가 없어야 한다.

  • API 응답 형식이 바뀌면 클라이언트가 혼란을 겪을 수 있다
  • DB 스키마가 바뀌면 한쪽 버전에서 오류가 발생할 수 있다

이런 경우에는 ReCreate나 Blue/Green을 고려해야 한다.

3-3-3. Blue/Green

개념

Controller를 하나 더 만들어서 새 버전을 통째로 준비해 두고, Service의 연결 대상만 바꾸는 방식이다.

Deployment가 직접 지원하는 기능이 아니라, Controller 두 개와 Service의 Label을 이용해 직접 구현한다.

동작 과정

① v1 Controller와 Pod만 존재 (Blue)

   ┌──────────────┐
   │  Controller  │
   │    (v1)      │
   └──┬────────┬──┘
      │        │
 ┌────▼────┐ ┌─▼───────┐
 │ Pod     │ │ Pod     │
 │ ver: v1 │ │ ver: v1 │
 └────┬────┘ └────┬────┘
      │           │
      └─────┬─────┘
            │
      ┌─────▼──────┐
      │  Service   │
      │  ver: v1   │  ← selector가 v1을 가리킴
      └────────────┘

   자원 사용량:  ██ ██        (2개)

② v2 Controller를 새로 생성 (Green)

   ┌──────────────┐        ┌──────────────┐
   │  Controller  │        │  Controller  │
   │    (v1)      │        │    (v2)      │  ← 새로 생성
   └──┬────────┬──┘        └──┬────────┬──┘
      │        │              │        │
 ┌────▼────┐ ┌─▼───────┐ ┌────▼────┐ ┌─▼───────┐
 │ Pod     │ │ Pod     │ │ Pod     │ │ Pod     │
 │ ver: v1 │ │ ver: v1 │ │ ver: v2 │ │ ver: v2 │
 └────┬────┘ └────┬────┘ └─────────┘ └─────────┘
      │           │
      └─────┬─────┘         트래픽 없음 (대기 상태)
            │
      ┌─────▼──────┐
      │  Service   │
      │  ver: v1   │
      └────────────┘

   자원 사용량:  ██ ██ ██ ██   (4개, 2배)

이 시점에서 v2 Pod는 떠 있지만 Service가 연결하지 않으므로 트래픽을 받지 않는다. 이 상태에서 v2를 충분히 검증할 수 있다.

③ Service의 Label만 v2로 변경

   ┌──────────────┐        ┌──────────────┐
   │  Controller  │        │  Controller  │
   │    (v1)      │        │    (v2)      │
   └──┬────────┬──┘        └──┬────────┬──┘
      │        │              │        │
 ┌────▼────┐ ┌─▼───────┐ ┌────▼────┐ ┌─▼───────┐
 │ Pod     │ │ Pod     │ │ Pod     │ │ Pod     │
 │ ver: v1 │ │ ver: v1 │ │ ver: v2 │ │ ver: v2 │
 └─────────┘ └─────────┘ └────┬────┘ └────┬────┘
                              │           │
   트래픽 없음                └─────┬─────┘
                                    │
                              ┌─────▼──────┐
                              │  Service   │
                              │  ver: v2   │  ← selector 변경
                              └────────────┘

Service의 selectorver: v1에서 ver: v2로 수정하는 것만으로 순간적으로 전환된다. Pod를 만들거나 지우는 과정이 없으므로 다운타임이 없다.

④ v1 Controller 삭제

                           ┌──────────────┐
                           │  Controller  │
                           │    (v2)      │
                           └──┬────────┬──┘
                              │        │
                         ┌────▼────┐ ┌─▼───────┐
                         │ Pod     │ │ Pod     │
                         │ ver: v2 │ │ ver: v2 │
                         └────┬────┘ └────┬────┘
                              └─────┬─────┘
                              ┌─────▼──────┐
                              │  Service   │
                              │  ver: v2   │
                              └────────────┘

   자원 사용량:  ██ ██        (2개로 복귀)

자원 사용량의 변화

   사용량
     │
   4 │     ████ ████
     │
   2 │ ██ ██        ██ ██
     │
     └───────────────────────────▶ 시간
       초기  배포 중     완료
            (2배 사용)

장점과 단점

구분내용
장점 — 다운타임 없음Label 변경만으로 전환되므로 순간적으로 바뀐다
장점 — 롤백이 쉬움문제가 생기면 Service의 Label을 다시 v1로 되돌리면 끝이다
장점 — 사전 검증 가능v2가 트래픽을 받기 전에 충분히 테스트할 수 있다
단점 — 자원 2배두 버전의 Pod가 모두 떠 있어야 하므로 자원이 두 배로 필요하다

롤백의 차이가 특히 중요하다. Rolling Update는 롤백할 때도 Pod를 하나씩 다시 교체해야 하지만, Blue/Green은 Label 하나만 되돌리면 즉시 복구된다. 그래서 실패했을 때의 영향이 가장 적은 방식이다.


3-3-4. Canary

개념

새 버전을 일부 트래픽에만 먼저 노출해서 검증한 뒤, 문제가 없으면 전체로 확대하는 방식이다.

이름은 탄광에서 유독가스를 미리 감지하던 카나리아 새에서 유래했다.

방법 1 — Pod 개수로 비율 조절

가장 단순한 구현이다. Service 하나가 v1과 v2 Pod를 모두 선택하도록 하고, Pod 개수로 트래픽 비율을 조절한다.

   ┌──────────────┐        ┌──────────────┐
   │  Controller  │        │  Controller  │
   │    (v1)      │        │    (v2)      │
   └──┬────────┬──┘        └──────┬───────┘
      │        │                  │
 ┌────▼────┐ ┌─▼───────┐    ┌─────▼─────┐
 │ Pod     │ │ Pod     │    │ Pod       │
 │ ty: app │ │ ty: app │    │ ty: app   │
 │ ver: v1 │ │ ver: v1 │    │ ver: v2   │
 └────┬────┘ └────┬────┘    └─────┬─────┘
      │           │               │
      └───────────┼───────────────┘
                  │
            ┌─────▼──────┐
            │  Service   │
            │  ty: app   │  ← ver를 조건에 넣지 않음
            └────────────┘

   트래픽 비율:  v1 67%  /  v2 33%

Service의 selector가 ty: app만 보므로 v1, v2 Pod를 모두 선택한다. v2 Pod가 1개, v1 Pod가 2개이므로 트래픽의 약 1/3이 v2로 간다.

문제가 없으면 v2 Pod를 늘리고 v1 Pod를 줄여가며 비율을 조정한다.

방법 2 — Ingress Controller로 경로 분기

URL 경로에 따라 서비스를 나누는 방식이다. Ingress Controller를 활용한다.

   ┌──────────────┐        ┌──────────────┐
   │  Controller  │        │  Controller  │
   │    (v1)      │        │    (v2)      │
   └──┬────────┬──┘        └──────┬───────┘
      │        │                  │
 ┌────▼────┐ ┌─▼───────┐    ┌─────▼─────┐
 │ Pod     │ │ Pod     │    │ Pod       │
 │ ver: v1 │ │ ver: v1 │    │ ver: v2   │
 └────┬────┘ └────┬────┘    └─────┬─────┘
      └─────┬─────┘               │
            │                     │
      ┌─────▼──────┐        ┌─────▼──────┐
      │  Service   │        │  Service   │
      │  ver: v1   │        │  ver: v2   │
      └─────┬──────┘        └─────┬──────┘
            │                     │
          /app                 /v2/app
            │                     │
            └──────────┬──────────┘
                       │
           ┌───────────▼────────────┐
           │  Ingress Controller    │
           └────────────────────────┘
요청 경로연결되는 버전
/appv1
/v2/appv2

특정 사용자에게만 /v2/app 경로를 안내해 새 버전을 먼저 써보게 할 수 있다. 검증이 끝나면 Ingress 설정을 바꿔 /app 요청이 v2로 가도록 전환한다.

   검증 전:  /app     ──▶  v1
             /v2/app  ──▶  v2

   전환 후:  /app     ──▶  v2

자원 사용량의 변화

   사용량
     │
   3 │      ███ ███ ███
     │
   2 │ ██ ██          ██ ██
     │
     └───────────────────────────▶ 시간
       초기  검증 중     완료

v2 Pod를 조금만 띄우므로 Blue/Green처럼 2배가 필요하지는 않다.

장점과 단점

구분내용
장점 — 다운타임 없음기존 v1이 계속 서비스하는 상태에서 v2를 추가한다
장점 — 위험 최소화문제가 생겨도 영향받는 사용자가 일부로 제한된다
장점 — 실제 환경 검증테스트 환경이 아닌 실제 트래픽으로 새 버전을 확인할 수 있다
단점 — 구성이 복잡Controller, Service, Ingress를 직접 구성하고 관리해야 한다
단점 — 모니터링 필요v2에 문제가 있는지 판단할 지표와 관찰 체계가 갖춰져 있어야 의미가 있다

네 가지 배포 방식 비교

   ReCreate           Rolling Update      Blue/Green         Canary
   ────────           ──────────────      ──────────         ──────
   v1 v1              v1 v1               v1 v1  v2 v2       v1 v1 v2
     ↓                  ↓                    ↘  ↙              ↓  ↓
   (없음) ⚠            v1 v2              Service 전환      Service
     ↓                  ↓                    ↓                 ↓
   v2 v2              v2 v2               v2 v2             비율 조정

   Downtime 발생      Zero Downtime       Zero Downtime     Zero Downtime
   자원 추가 없음      자원 일부 증가       자원 2배          자원 일부 증가
구분ReCreateRolling UpdateBlue/GreenCanary
다운타임발생없음없음없음
배포 중 자원감소 (0까지)일부 증가2배일부 증가
두 버전 공존없음있음없음 (전환 순간만)있음 (의도적)
롤백 속도느림 (재배포)느림 (재교체)즉시 (Label 변경)빠름 (v2 제거)
Deployment 지원RecreateRollingUpdate미지원 (직접 구성)미지원 (직접 구성)
구성 난이도매우 쉬움쉬움보통어려움

선택 기준

  • 다운타임이 허용되고 두 버전이 공존하면 안 되는가 → ReCreate
  • 무난하게 무중단 배포를 하고 싶은가 → Rolling Update (가장 일반적)
  • 자원에 여유가 있고 즉시 롤백이 중요한가 → Blue/Green
  • 새 버전의 위험이 크고 실제 트래픽으로 검증하고 싶은가 → Canary

3-4. DaemonSet, Job, CronJob

3-4-1. DaemonSet

개념

ReplicaSet은 "Pod를 몇 개 유지할지"를 정하고, 스케줄러가 자원 여유를 보고 배치할 Node를 고른다. 그래서 Pod가 특정 Node에 몰리거나, 어떤 Node에는 하나도 배치되지 않을 수 있다.

DaemonSet은 다르다. Node의 자원 상태와 상관없이 모든 Node에 Pod를 하나씩 생성한다.

   [ ReplicaSet ]                    [ DaemonSet ]
   ──────────────                    ─────────────
   ┌────────────┐                    ┌────────────┐
   │ ReplicaSet │                    │ DaemonSet  │
   └─┬────┬─────┘                    └─┬───┬───┬──┘
     │    │                            │   │   │
   ┌─▼────▼──────┐                   ┌─▼───────────┐
   │   Node1     │                   │   Node1     │
   │  Pod  Pod   │                   │    Pod      │
   │  ▓▓ ▓▓ ▓▓   │  자원 여유 많음   │             │
   └─────────────┘                   └─────────────┘
   ┌─────────────┐                   ┌─────────────┐
   │   Node2     │                   │   Node2     │
   │    Pod      │                   │    Pod      │
   │  ▓▓ ▓▓      │                   │             │
   └─────────────┘                   └─────────────┘
   ┌─────────────┐                   ┌─────────────┐
   │   Node3     │                   │   Node3     │
   │  (없음)     │  자원 부족        │    Pod      │
   │  ▓          │                   │             │
   └─────────────┘                   └─────────────┘

   자원 여유에 따라 배치            Node마다 무조건 1개

Node가 새로 추가되면 DaemonSet이 그 Node에도 자동으로 Pod를 하나 생성한다. Node가 제거되면 그 Pod도 함께 사라진다.

사용 사례

Node마다 하나씩 떠 있어야 의미가 있는 작업에 사용한다.

용도대표 도구하는 일
PerformancePrometheus (Node Exporter)Node의 CPU, 메모리, 디스크 사용량을 수집
LoggingFluentdNode에 쌓인 로그를 수집해 중앙 서버로 전송
StorageGlusterFSNode의 디스크를 묶어 분산 스토리지로 제공

공통점은 Node 하나하나의 정보에 접근해야 한다는 것이다. 로그를 수집하려면 모든 Node에 수집기가 있어야 하고, 한 Node라도 빠지면 그 Node의 로그는 유실된다.

Volume에서 다룬 hostPath가 DaemonSet과 함께 쓰이는 이유도 여기에 있다. 모든 Node에 Pod를 하나씩 띄우고, 각 Pod가 자기 Node의 /var/log를 마운트해 로그를 읽는 구조다.

nodeSelector — 특정 Node에만 배치

모든 Node가 아니라 조건에 맞는 Node에만 배치할 수도 있다.

   ┌──────────────────────────────┐
   │        DaemonSet             │
   │  selector    template        │
   │  type:app    Pod             │──▶ nodeSelector: os: centos
   └───┬──────────┬───────────┬───┘
       │          │           │
       ▼          ▼           ✗
  ┌─────────┐┌─────────┐┌─────────┐
  │  Node1  ││  Node2  ││  Node3  │
  │  Pod    ││  Pod    ││ (없음)  │
  │os:centos││os:centos││os:ubuntu│
  └─────────┘└─────────┘└─────────┘

os: centos Label이 붙은 Node에만 Pod가 생성되고, os: ubuntu인 Node3에는 생성되지 않는다.

hostPort — Node의 포트로 직접 접근

DaemonSet은 Node마다 Pod가 하나씩이므로, Node의 포트를 Pod에 직접 연결할 수 있다.

   ┌─────────────────┐  ┌─────────────────┐
   │     Node1       │  │     Node2       │
   │   ┌─────────┐   │  │   ┌─────────┐   │
   │   │  Pod    │   │  │   │  Pod    │   │
   │   │  8080   │   │  │   │  8080   │   │
   │   └────┬────┘   │  │   └────┬────┘   │
   │        │        │  │        │        │
   │   [ 18080 ]     │  │   [ 18080 ]     │
   └────────┬────────┘  └────────┬────────┘
            │                    │
        Node IP : 18080 로 직접 접근
항목설명
containerPort컨테이너가 사용하는 포트
hostPort그 컨테이너를 연결할 Node의 포트

NodePort와 비슷해 보이지만 차이가 있다. NodePort는 Service를 거쳐 어느 Node로 들어와도 Pod가 있는 Node로 전달되지만, hostPort그 Node의 Pod에 직접 연결된다. 각 Node의 상태를 개별적으로 확인해야 하는 모니터링 도구에 적합하다.

YAML

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-1
spec:
  selector:
    matchLabels:
      type: app
  template:
    metadata:
      labels:
        type: app
    spec:
      nodeSelector:
        os: centos
      containers:
        - name: container
          image: tmkube/app
          ports:
            - containerPort: 8080
              hostPort: 18080
항목설명
replicas 없음DaemonSet에는 replicas가 없다. 개수는 Node 수로 결정되기 때문
nodeSelector조건에 맞는 Node에만 Pod를 배치
hostPortNode의 포트를 Pod에 직접 연결

replicas가 없다는 점이 다른 Controller와 가장 뚜렷한 차이다.


3-4-2. Job

Pod, ReplicaSet, Job의 차이

세 오브젝트 모두 Pod를 만들지만, Pod가 종료되었을 때의 동작이 다르다.

   ┌──────────────┐
   │     Pod      │   Node1 장애 시 →  Pod 사라짐, 복구 없음
   └──────────────┘

   ┌──────────────┐                    ┌─────────────────────┐
   │  ReplicaSet  │   Node1 장애 시 →  │ Node2에 Recreate    │
   └──────────────┘                    │ 계속 Running 유지   │
                                       └─────────────────────┘

   ┌──────────────┐                    ┌─────────────────────┐
   │     Job      │   Node1 장애 시 →  │ Node2에 Recreate    │
   └──────────────┘                    │ 작업 끝나면 Finish  │
                                       └─────────────────────┘
구분PodReplicaSetJob
Node 장애 시복구되지 않음다른 Node에 재생성다른 Node에 재생성
Pod 종료 후종료된 상태로 남음계속 Restart (서비스 유지)Finish (작업 완료로 처리)
목적일회성 실행계속 떠 있어야 하는 서비스끝이 있는 작업

핵심은 ReplicaSet은 Pod가 끝나는 것을 장애로 보고 다시 띄우지만, Job은 정상 종료로 인정한다는 점이다.

웹 서버가 꺼지면 문제이므로 다시 띄워야 하지만, 백업 작업이 끝난 것은 성공이므로 다시 띄우면 안 된다. 이 차이 때문에 Job이 따로 존재한다.

사용 사례

용도설명
Backup데이터베이스를 백업 파일로 내보내는 작업
Checking데이터 정합성 검사, 업데이트 확인
Messaging대량 메일이나 알림 발송

작업이 끝나면 Pod가 종료되고 자원이 반납되므로, 항상 띄워두는 것보다 자원을 효율적으로 쓸 수 있다.

completions — 몇 번 실행할 것인가

   ┌─────────────────────────────────┐
   │            Job                   │
   │       completions : 6            │
   │   ┌────┐ ┌────┐ ┌────┐          │
   │   │Pod │ │Pod │ │Pod │          │
   │   └────┘ └────┘ └────┘          │
   │   ┌────┐ ┌────┐ ┌────┐          │
   │   │Pod │ │Pod │ │Pod │          │
   │   └────┘ └────┘ └────┘          │
   └─────────────────────────────────┘
        Pod 6개가 순차적으로 실행되고 완료

completions: 6성공적으로 완료되어야 하는 Pod의 수를 뜻한다. 6개가 모두 성공해야 Job이 완료 상태가 된다.

parallelism — 몇 개를 동시에 실행할 것인가

   parallelism: 2

   ┌────┐ ┌────┐     ┌────┐ ┌────┐     ┌────┐ ┌────┐
   │Pod │ │Pod │  →  │Pod │ │Pod │  →  │Pod │ │Pod │
   └────┘ └────┘     └────┘ └────┘     └────┘ └────┘
    1회차 (2개)       2회차 (2개)       3회차 (2개)

        합계 6개 = completions

기본값은 1이라 하나씩 순차 실행되지만, parallelism: 2를 주면 2개씩 동시에 실행된다. 6개를 처리하는 데 걸리는 시간이 줄어든다.

activeDeadlineSeconds — 제한 시간

   ┌────┐                              ┌ ─ ─┐
   │Job │ ────────────────────────────▶  Job
   └────┘                              └ ─ ─┘
     시작              30초 경과        강제 종료

작업이 지정한 시간 안에 끝나지 않으면 강제로 종료한다. 무한 루프에 빠지거나 응답 없는 외부 시스템을 기다리며 Pod가 영원히 남는 상황을 막는다.

YAML

apiVersion: batch/v1
kind: Job
metadata:
  name: job-1
spec:
  completions: 6
  parallelism: 2
  activeDeadlineSeconds: 30
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: container
          image: tmkube/init
항목설명
apiVersion: batch/v1Job과 CronJob은 apps/v1이 아니라 batch/v1 을 사용한다
completions성공해야 하는 Pod의 총 개수
parallelism동시에 실행할 Pod의 개수
activeDeadlineSeconds작업의 제한 시간(초). 초과하면 강제 종료
restartPolicy: NeverPod가 실패해도 컨테이너를 재시작하지 않는다
selector 없음Job은 selector를 지정하지 않는다. 쿠버네티스가 자동으로 부여한다

restartPolicy는 Job에서 반드시 지정해야 하는 값이다.

동작
Never실패 시 컨테이너를 재시작하지 않고 새 Pod를 만든다
OnFailure실패 시 같은 Pod 안에서 컨테이너를 재시작한다

Always는 Job에서 사용할 수 없다. 작업이 끝나도 계속 재시작하게 되어 Job의 목적과 맞지 않기 때문이다.


3-4-3. CronJob

개념

CronJob은 Job을 정해진 일정에 따라 반복 생성하는 Controller다. Job을 직접 만드는 것이 아니라, Job을 만드는 Controller라는 점이 핵심이다.

   ┌─────────────────────────────────────────┐
   │              CronJob                     │
   │   schedule : */1 * * * *                 │
   │   jobTemplate : Job                      │
   └────┬──────────────┬──────────────┬──────┘
        │              │              │
     1 Min          2 Min          3 Min
        │              │              │
        ▼              ▼              ▼
   ┌─────────┐   ┌─────────┐   ┌─────────┐
   │   Job   │   │   Job   │   │   Job   │
   └────┬────┘   └────┬────┘   └────┬────┘
        │             │             │
        ▼             ▼             ▼
   ┌─────────┐   ┌─────────┐   ┌─────────┐
   │   Pod   │   │   Pod   │   │   Pod   │
   └─────────┘   └─────────┘   └─────────┘

1분마다 Job이 하나씩 생성되고, 각 Job이 Pod를 만들어 작업을 수행한다.

schedule — 일정 지정

리눅스의 cron 표현식을 그대로 사용한다.

   * * * * *
   │ │ │ │ │
   │ │ │ │ └── 요일 (0~6, 0=일요일)
   │ │ │ └──── 월 (1~12)
   │ │ └────── 일 (1~31)
   │ └──────── 시 (0~23)
   └────────── 분 (0~59)
표현식의미
*/1 * * * *1분마다
0 * * * *매시 정각
0 2 * * *매일 새벽 2시
0 3 * * 0매주 일요일 새벽 3시

concurrencyPolicy — 이전 작업이 안 끝났을 때

정해진 시간이 되었는데 이전 Job이 아직 끝나지 않은 경우를 어떻게 처리할지 정한다.

        Allow                   Forbid                  Replace
   ┌───────────────┐     ┌───────────────┐      ┌───────────────┐
   │1min 2min 3min │     │1min 2min 3min │      │1min 2min 3min │
   │               │     │      skip     │      │               │
   │ Job  Job  Job │     │ Job   ⚠   Job │      │ Job  Job  Job │
   │  │    │    │  │     │  │        │   │      │  │ ✗  │    │  │
   │ Pod  Pod  Pod │     │ Pod ────▶ Pod │      │ Pod  Pod  Pod │
   └───────────────┘     └───────────────┘      └───────────────┘

   이전 Job과 상관없이   이전 Job이 실행 중이면   이전 Job을 삭제하고
   무조건 새로 생성       이번 차례는 건너뜀       새 Job으로 교체
동작사용하는 경우
Allow (기본값)이전 Job과 무관하게 새 Job을 생성한다. 여러 Job이 동시에 실행될 수 있다작업들이 서로 영향을 주지 않는 경우
Forbid이전 Job이 실행 중이면 이번 실행을 건너뛴다같은 작업이 중복되면 안 되는 경우 (예: DB 백업)
Replace이전 Job을 삭제하고 새 Job으로 교체한다최신 결과만 중요한 경우 (예: 캐시 갱신)

Suspend와 Manual Trigger

   ┌─────────────────────────────────┐
   │           CronJob               │◀── Suspend (일시 중지)
   │   schedule : */1 * * * *        │
   │   jobTemplate : Job             │◀── Manual Trigger (수동 실행)
   └─────────────────────────────────┘
기능설명
Suspend스케줄을 일시 중지한다. CronJob은 남아 있지만 Job을 만들지 않는다
Manual Trigger일정과 무관하게 지금 즉시 Job을 실행한다. 테스트나 긴급 작업에 사용
# 일시 중지
kubectl patch cronjob cron-job -p '{"spec":{"suspend":true}}'

# 수동 실행
kubectl create job --from=cronjob/cron-job manual-job-1

YAML

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job
spec:
  schedule: "*/1 * * * *"
  concurrencyPolicy: Allow
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: container
              image: tmkube/app
항목설명
scheduleJob을 생성할 일정 (cron 표현식)
concurrencyPolicy이전 Job이 실행 중일 때의 처리 방식
jobTemplate생성할 Job의 내용

구조가 한 겹 더 깊다는 점에 주의해야 한다.

   CronJob
     └── jobTemplate        ← Job의 정의
           └── template     ← Pod의 정의
                 └── containers

CronJob이 Job을 만들고, Job이 Pod를 만들기 때문에 템플릿이 두 번 중첩된다.


Job과 CronJob의 공통점과 차이점

공통점

항목내용
목적끝이 있는 일시적인 작업을 수행한다
apiVersion둘 다 batch/v1을 사용한다
Pod 종료 처리작업이 끝나면 Pod를 Finish로 처리하고 재시작하지 않는다
자원 효율작업이 끝나면 자원을 반납한다
restartPolicyNever 또는 OnFailure만 사용 가능하다
사용 사례Backup, Checking, Messaging

차이점

        Job                          CronJob
   ────────────                 ──────────────────
   ┌──────────┐                 ┌──────────┐
   │   Job    │                 │ CronJob  │
   └────┬─────┘                 └────┬─────┘
        │                            │ 일정마다
        ▼                       ┌────┼────┬────┐
   ┌──────────┐                 ▼    ▼    ▼    ▼
   │   Pod    │              ┌────┐┌────┐┌────┐
   └──────────┘              │Job ││Job ││Job │
                             └─┬──┘└─┬──┘└─┬──┘
   한 번 실행하고 끝            ▼     ▼     ▼
                             Pod   Pod   Pod

                             일정에 따라 반복
구분JobCronJob
실행 시점생성하는 즉시 1회 실행일정에 따라 반복 실행
만드는 대상Pod를 직접 생성Job을 생성 (Job이 Pod를 생성)
반복 여부반복하지 않음계속 반복
고유 설정completions, parallelism, activeDeadlineSecondsschedule, concurrencyPolicy, jobTemplate
템플릿 깊이template (Pod)jobTemplatetemplate (Job → Pod)
사용 예일회성 데이터 마이그레이션매일 새벽 2시 DB 백업

관계로 정리하면 이렇다.

   CronJob  ──생성──▶  Job  ──생성──▶  Pod
   (일정 관리)        (작업 관리)      (실제 실행)

CronJob은 Job을 대체하는 것이 아니라 Job을 반복 실행해 주는 상위 개념이다. 한 번만 실행할 작업이면 Job을, 주기적으로 실행할 작업이면 CronJob을 사용한다.

0개의 댓글