본문 바로가기
Cloud Native/Kubernetes

7. Deployment - Recreate, RollingUpdate

by jys275 2026. 1. 23.

개발보다 어려운 게 '무중단 배포'다. 서비스가 중단되는 순간 고객은 떠나고, 그 책임은 우리가 진다. 이번에는 서비스를 어떻게 안전하게 업그레이드할 것인지, 그 전략과 디플로이먼트(Deployment)의 실체에 대해 알아보자.

 

Deployment는 현재 한 서비스가 운영 중인데, 이 서비스를 업데이트 해야해서 재배포를 해야될 때 도움을 준다.

 

 


 

 

1. 서비스 업그레이드 전략: 상황에 맞는 선택

 

인프라를 어떻게 갈아끼울 것인가는 자원 상황과 서비스 중요도에 따라 결정된다.

  • Recreate (재생성): 기존 파드를 모두 죽이고 새 버전을 띄운다. 자원 사용량은 적지만 다운타임(Downtime)이 반드시 발생한다. 일시 정지가 허용되는 서비스에만 쓴다.
    • 파드 삭제 → 다운타임 → 자원 사용량 없어짐.
  • Rolling Update (롤링 업데이트): 파드를 하나씩 순차적으로 교체한다. 무중단 배포가 가능하며 쿠버네티스의 기본값이다. 배포 도중 추가 자원이 필요하다는 점을 명심하자.
    • 먼저 v2의 파드 1개 생성 → v1, v2 모두 서비스 운영 중 (랜덤 접속될 것)
    • → v1 파드 1개 삭제 → v2 파드 1개 더 생성 → v1 파드 남은 1개 삭제.
    • 즉, 위 과정에서 v2의 파드 1개 생성할 때 배포 도중 추가 자원이 필요해지게되는 것.
더보기

"서비스가 라벨을 보고 Pod를 찾는구나"

  • Blue/Green (블루/그린): 구버전(Blue)과 신버전(Green) 환경을 통째로 띄워놓고 서비스 셀렉터만 한 번에 바꾼다. 다운타임이 거의 없고 롤백이 매우 빠르지만, 자원이 2배로 든다.
    • Deployment 자체 제공 기능은 아니다. ReplicaSet과 같이 모든 컨트롤러를 이용해서 할 수 있음.
    • 컨트롤러를 통해 파드가 생성 → 파드에는 라벨 존재 → 서비스의 Selector와 연결
    • → 이 상태에서 컨트롤러를 하나 더 만든다(v2에 대한). → 이로써 기존 자원 사용량의 2배가 되는 것
    • → 이러면 준비가 완료된건데, 이때 서비스의 라벨을 완전히 v2로 교체해서 기존 파드(v1)과 관계를 끊어버려 변경이 된다. → 그래서 순간적으로 변경되기 때문에 다운타임이 거의 없는 것이다.
    • 롤백을 원할 때는 v1으로 간단하게 교체만 하면 되기 때문에 또 대중적이다.
  • Canary (카나리): 소수의 유입 트래픽에만 신버전을 노출(=실험체로 위험 검증)해 검증한 뒤 전체로 확대한다. 광산의 카나리아처럼 위험을 미리 감지하는 방식이다. 인그레스(Ingress) 등을 활용해 정교한 트래픽 제어가 가능하다. 다운타임이 거의 없고, 자원은 v2에 대한 파드(테스트용을 얼마나?)를 얼마나 만들 것이냐에 따라 증가한다.
[방법1]: 인프런_대세는 쿠버네티스
  • v1이 아닌 type:app으로 라벨을 만들어 서비스를 연결하는 것이다.
  • 이 상태에서 테스트 용으로 컨트롤러를 만든다. → ReplicaSet을 1로 설정하여 v2의 파드를 하나 만든다. → 똑같이 type:app이라고 라벨을 단다. → 자동으로 아까 서비스에 연결이 된다.
  • → 그러면 연결이 되어있으니 트래픽 중 일부가 v2로 접근이 될 것이고 자연스럽게 테스트가 진행된다.  그러다 문제가 발생하면 ReplicaSet을 0으로 만들면 간단하다.
[방법2]: 인프런_대세는 쿠버네티스
  • v1은 v1대로, v2는 v2대로 각각의 서비스를 만든다.
  •  IngressController라는 컨트롤러 유입되는 트래픽을 URL Path(/app, /v2/app)에 따라서 연결을 해주는 역할을 한다.
  • → Path 앞에 v2 (EN 등 다양함)가 있으면 새 버전에 대한 서비스가 사용되게 된다(이렇게 특정 타겟을 정해두고 테스트를 진행하는 것이다).
  • → 테스트 기간이 종료되는 v2의 파드를 1개에서 2개 등으로 증가시킨다.
  • → 기존 v1에 대한 내용과 파드를 삭제한다. → IngressController 설정을 그냥 /app으로 변경해주면 끝이다(자연스래 옮겨짐).

 


 

 

 

2. Deployment의 내부 동작 원리

 

Deployment는 파드를 직접 관리하지 않는다. 이 녀석은 리플리카셋(ReplicaSet)을 부리는 '관리자'일 뿐이다.

  • 리플리카셋 조종: 배포 시 디플로이먼트는 새로운 리플리카셋을 생성하고, 이전 리플리카셋의 복제본 수를 조정하며 파드를 교체한다.
    • 그리고, Deployment를 만들 때, Replica에서 넣었던 selector, replicas, template을 동일하게 넣는 것이다. (ReplicaSet을 만들고 값을 지정해주기 위한 용도임)
    • 그래서 파드들이 ReplicaSet을 기반으로 만들어진다. → 서비스를 만들고 Pod들과 연결된다.

  • Recreate 방식의 내부
    1. 이전 리플리카셋의 replicas 0으로 만든다.
    2. 다운타임이 생긴다.
    3. 새 리플리카셋을 원하는 수만큼 올린다.
  • 이력 관리 (Revision History): Optional인 revisionHistoryLimit 설정을 통해 구버전 리플리카셋을 남겨둘 수 있다. 기본값은 10개이며, 이를 이용해 언제든 안정적인 이전 버전으로 롤백할 수 있다.

  • Rolling Update 방식의 내부
    1. 새 리플리카셋을 하나씩 늘린다(Scale Up).
      • 즉, 새 리플리카셋의 replicas(오른쪽)를 처음에는 '1'로 설정하는 것이다.
      • 이 동안은 다운타임도 없고, v1 2개와 v2 1개가 서비스에 연결돼서 트래픽이 세 곳으로 분산될 것이다.
    2. 기존 리플리카셋을 하나씩 줄이며(Scale Down) 점진적으로 교체한다.
      • 기존 리플리카셋의 replicas(왼쪽)를 '2'에서 '1'로 줄인다 = 삭제된다.
      • 새 리플리카셋의 replicas(오른쪽)를 '1'에서 '2'로 늘린다.
      • 기존 리플리카셋의 replicas(왼쪽)를 '1'에서 '0'로 줄인다 = 완전 삭제된다.
  • 이력 관리 (Revision History): revisionHistoryLimit 설정을 통해 구버전 리플리카셋을 남겨둘 수 있다. 기본값은 10개이며, 이를 이용해 언제든 안정적인 이전 버전으로 롤백할 수 있다.
  • 고유 라벨 매칭: 롤링 업데이트 중 서로 다른 리플리카셋의 파드가 섞이지 않도록, 쿠버네티스는 내부적으로 고유한 해시 라벨을 생성해 관계를 정확히 유지한다.
    • 잘 생각해보면 라벨이 다 같은데, 새로운 ReplicaSet이 기존 ReplicaSet의 파드와 연결 안된다는 보장은 없으니, 추가적인 해시 라벨과 Selector를 더 만들어줘야하는 것인데, 실습에서 확인하자.

 

 

 

💡꼬리 질문

Q: 롤링 업데이트 시 서비스가 중단되지 않는 핵심 조건 중 하나는 '새로 뜬 파드가 실제로 요청을 받을 준비가 되었는가'를 판단하는 것이다. 이를 위해 디플로이먼트 스펙에서 반드시 함께 고려해야 할 기능은 무엇일까?

 

 

결론: Readiness Probe(준비성 프로브)와 minReadySeconds 설정을 함께 사용해야 한다.

  1. Readiness Probe: 쿠버네티스가 단순히 파드가 '실행 중(Running)'인 것을 넘어, 애플리케이션 초기화가 끝나고 실제 트래픽을 처리할 수 있는지 검사.
  2. 안전 장치: 이 프로브가 통과되어야만 해당 파드를 서비스 엔드포인트에 추가하고, 기존 파드를 삭제하기 시작.
  3. 지연 시간 부여: 강의에서 언급된 minReadySeconds는 파드가 준비된 후 다음 파드 교체로 넘어가기 전의 최소 대기 시간을 보장하여, 배포 과정의 안정성을 시각적으로 확인하거나 모니터링할 시간을 벌어준다.

 


 

 

배포(Deployment) 전략을 선택하는 기준은 딱 하나다. "우리 서비스가 1초의 중단도 허용하는가?" 중단이 허용되지 않는다면 롤링 업데이트나 블루/그린을, 자원이 부족하고 일시 정지가 가능하다면 Recreate를 선택하자.

 

 

1. Recreate (재생성): 확실하지만 아픈 방식

인프런_대세는 쿠버네티스

  • 동작 원리: 기존 리플리카셋의 복제본을 0으로 만든 뒤, 새 리플리카셋을 생성한다.
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: kubetm/app:v1
      terminationGracePeriodSeconds: 10
apiVersion: v1
kind: Service
metadata:
  name: svc-1
spec:
  selector:
    type: app
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  • 특징: app:v2로 업데이트(=수정) 하는 순간 어떻게 될까? 바로, 배포 순간에 파드를 다운시켜 다운타임(Downtime)이 발생하여 서비스가 끊긴다. v2로 재배포 될때까지 말이다. 대신 추가 자원이 동시에 소모되지 않는다는 장점이 있다.

  • 핵심 필드: pod-template-hash. 디플로이먼트는 이 고유 라벨을 통해 여러 리플리카셋 사이에서 자신의 파드를 정확히 식별한다.
  • 이력 관리: revisionHistoryLimit: 1로 설정하면 이전 리플리카셋을 딱 하나만 남기고 나머지는 삭제하여 클러스터를 깨끗하게 유지한다.
# Kubectl 명령으로 Rollback

kubectl rollout undo deployment deployment-1 --to-revision=1
kubectl rollout history deployment deployment-1

 

 

 

 

 

2. RollingUpdate (롤링 업데이트): 쿠버네티스의 표준

인프런_대세는 쿠버네티스

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-2
spec:
  selector:
    matchLabels:
      type: app2
  replicas: 2
  strategy:
    type: RollingUpdate
  minReadySeconds: 10
  template:
    metadata:
      labels:
        type: app2
    spec:
      containers:
      - name: container
      image: kubetm/app:v1
      terminationGracePeriodSeconds: 0

위 같이 type을 RollingUpdate로 지정 후 생성하면, Deployment와 replicas: 2 만큼의 Pod 2개가 자동으로 생성되고, ReplicaSet 또한 자동으로 생성된다. 서비스는 아래와 같이 붙인다.

apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    type: app2
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  • 동작 원리: 파드를 하나씩 순차적으로 교체한다. 배포 중 V1과 V2 버전의 파드가 섞여서 서비스되는 구간이 존재한다.
    • Deployment에서 app:v1에서 app:v2로 바꾸면, 자동으로 v2 파드가 생성이되고, 섞여서 트래픽이 분산되다가
    • 점차적으로 v1이 삭제되다가 모두 v2로 바뀌게 되는 것이다.
  • 특징: 다운타임이 전혀 없다. 하지만 배포 중에 V1과 V2 파드가 공존하므로 일시적으로 더 많은 CPU/메모리 자원이 필요하다.


3. 필수 운영 명령어

  • 이미지 업데이트: kubectl set image deployment <이름> <컨테이너>=<이미지>
  • 이력 확인: kubectl rollout history deployment <이름>
  • 롤백 실행: kubectl rollout undo deployment <이름> --to-revision=<번호>

 

더보기

4. Blue/Green (블루/그린): 안정적인 즉시 전환

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica1
spec:
  replicas: 2
  selector:
    matchLabels:
      ver: v1
  template:
    metadata:
      labels:
        ver: v1
    spec:
      containers:
      - name: container
        image: kubetm/app:v1
      terminationGracePeriodSeconds: 0
apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:
    ver: v1
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080

수정

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replica2
spec:
  replicas: 2
  selector:
    matchLabels:
      ver: v2
  template:
    metadata:
      labels:
        ver: v2
    spec:
      containers:
      - name: container
        image: kubetm/app:v2
      terminationGracePeriodSeconds: 0
apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:
    ver: v2
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  • 동작 원리: 디플로이먼트 자체 기능이라기보다 서비스의 Selector를 변경하여 트래픽을 한 번에 전환하는 방식이다.
  • 특징: V2 환경을 완벽히 구축한 뒤 서비스 라벨만 ver: v1에서 ver: v2로 바꾸면 즉시 모든 트래픽이 이동한다. 장애 발생 시 셀렉터를 다시 원복하는 것만으로 초고속 롤백이 가능하다.

 

 

 

 

 

 

💡꼬리 질문

Q: 롤링 업데이트 중 새로운 버전(V2)의 파드에 심각한 버그가 있어 앱이 실행 직후 계속 크래시(Crash)가 난다면, 디플로이먼트는 배포를 어떻게 처리하며 기존 서비스(V1)는 안전할까?

 

 

결론: 기존 파드(V1)는 보존되며 배포는 중단된다.

  1. 배포 중단: 쿠버네티스는 새 파드가 정상 상태(Ready)가 되지 않으면 다음 파드 교체로 넘어가지 않는다. V2 파드가 계속 실패하면 배포 프로세스는 그 지점에서 멈춘다.
  2. 서비스 보호: 아직 삭제되지 않은 V1 파드들이 남아 있어 트래픽을 처리하므로, 전체 서비스가 완전히 죽는 최악의 상황은 면할 수 있다.
  3. 실무 대응: 이때 엔지니어는 kubectl rollout status로 배포 정지를 확인하고, kubectl rollout undo를 실행해 배포를 취소하여 클러스터를 안정적인 이전 상태로 되돌려야 한다.

 

 

 

 

 

위 학습용 정리 내용 및 사진 자료는 "인프런_대세는 쿠버네티스(https://inf.run/Lv5RV)" 강의를 소스로 작성하였습니다.

 

'Cloud Native > Kubernetes' 카테고리의 다른 글

1. Pod - Lifecycle  (0) 2026.01.24
8. DaemonSet, Job, CronJob  (1) 2026.01.24
6. ReplicaSet - Template, Replicas, Selector  (0) 2026.01.22
5. Namespace, ResourceQuota, LimitRange  (0) 2026.01.18
4. ConfigMap, Secret - Env, Mount  (0) 2026.01.18