Kubernetes Deployment rollback 옵션 활용 가이드

이 포스트는 Kubernetes 클러스터의 Deployment 리소스의 효과적인 업데이트 및 rollback 을 위한 옵션에 관해 설명합니다. Deployment 리소스에 progressDeadlineSeconds 옵션을 사용하여 rolling-update 진행 중 지정된 시간을 초과하면 업데이트를 실패로 간주하도록 하고, revision history를 통해 이전 버전으로 롤백할 수 있는 revison의 최댓값을 RevisionHistoryLimit을 통해 설정 후 동작을 확인하겠습니다.

목차

1. Deployment rollback을 위한 yaml 구성
2. progressDeadlineSeconds를 통한 Deployment 업데이트 실패 확인

3. RevisionHistoryLimit을 통한 Deployment 업데이트 내역 관리 및 rollback
4. 결론

1. Deployment rollback 을 위한 yaml 구성

Deployment rollback 예제 구성을 위해 다음 yaml 파일을 사용했습니다.

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  progressDeadlineSeconds: 30  
  revisionHistoryLimit: 3 
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
  • progressDeadlineSeconds 값을 30으로 설정하여, 30초 동안 Deployment 업데이트가 성공하지 않을 때 업데이트를 실패로 간주하도록 설정했습니다. (기본값 600)
  • revisionHistoryLimit 값을 3으로 설정하여, Deployment의 rollback을 위해 이전 replicasets를 3개로 유지하도록 설정했습니다. (기본값 10)
  • replicas는 3으로 설정하여 Pod를 3개로 구성하고, maxSurge 값으로 1로 설정하여 업데이트 중 4개의 Pod가 존재할 수 있도록 구성했습니다. 또한 maxUnavailable 값을 1로 설정하여 업데이트 시 기존 Pod가 1개가 비활성화될 수 있습니다.

yaml 파일을 사용해 Deployment를 배포합니다.

$ kubectl apply -f deployment.yaml -n rollback

deployment.apps/nginx created
$ kubectl get deploy,pod

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   3/3     3            3           8s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6cfb64b7c5-8hbjv   1/1     Running   0          8s
pod/nginx-6cfb64b7c5-grcvd   1/1     Running   0          8s
pod/nginx-6cfb64b7c5-zplj8   1/1     Running   0          8s

2. progressDeadlineSeconds를 통한 Deployment 업데이트 실패 확인

1. 배포한 Deployment의 nginx 이미지를 존재하지 않는 태그로 설정하여, 의도적으로 실패하는 업데이트를 수행합니다.

$ kubectl set image deployment/nginx nginx=nginx:nonexistent

deployment.apps/nginx image updated

2. 명령어를 사용하여 Deployment의 업데이트 상태를 확인합니다.

$ kubectl rollout status deployment/nginx

Waiting for deployment "nginx" rollout to finish: 2 out of 3 new replicas have been updated...

# 30초 경과 후

error: deployment "nginx" exceeded its progress deadline

Deployment의 Rolling Update의 종료를 기다리다가, progressDeadlineSeconds 값인 30초를 넘기자 에러 메시지를 출력합니다.

3. 명령어를 사용해 Deployment와 Pod의 상태를 확인합니다.

$ kubectl get deploy,pod

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   2/3     2            2           6m53s

NAME                         READY   STATUS             RESTARTS   AGE
pod/nginx-57775b8976-cb2tl   0/1     ImagePullBackOff   0          4m47s
pod/nginx-57775b8976-gw7lk   0/1     ImagePullBackOff   0          4m47s
pod/nginx-6cfb64b7c5-8hbjv   1/1     Running            0          6m53s
pod/nginx-6cfb64b7c5-zplj8   1/1     Running            0          6m53s

기존 3개의 Pod에서 maxSurge 값으로 인해 1개의 Pod가 추가로 구성되어 총 4개의 Pod가 존재하고, maxUnavailable 값으로 인해 기존 Pod중 1개의 Pod가 비활성화된 것을 확인할 수 있습니다.

$ kubectl describe deployments nginx

Name:                   nginx
Namespace:              rollback
CreationTimestamp:      Mon, 25 Nov 2024 15:54:40 +0900
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 2
Selector:               app=nginx
Replicas:               3 desired | 2 updated | 4 total | 2 available | 2 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:         nginx:nonexistent
    Port:          80/TCP
    Host Port:     0/TCP
    Environment:   <none>
    Mounts:        <none>
  Volumes:         <none>
  Node-Selectors:  <none>
  Tolerations:     <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    False   ProgressDeadlineExceeded
OldReplicaSets:  nginx-6cfb64b7c5 (2/2 replicas created)
NewReplicaSet:   nginx-57775b8976 (2/2 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  5m34s  deployment-controller  Scaled up replica set nginx-6cfb64b7c5 to 3
  Normal  ScalingReplicaSet  3m28s  deployment-controller  Scaled up replica set nginx-57775b8976 to 1
  Normal  ScalingReplicaSet  3m28s  deployment-controller  Scaled down replica set nginx-6cfb64b7c5 to 2 from 3
  Normal  ScalingReplicaSet  3m28s  deployment-controller  Scaled up replica set nginx-57775b8976 to 2 from 1

Conditions 항목에서 Progressing의 False 상태와, ProgressDeadlineExceeded Reason을 확인할 수 있습니다. 또한 하단에 업데이트로 인해 생성된 Replicasets 정보와, Pod의 스케일링 이벤트를 확인할 수 있습니다.

3. RevisionHistoryLimit을 통한 Deployment 업데이트 내역 관리 및 rollback

Deployment 업데이트 시 Kubernetes는 기존 ReplicaSet을 유지하면서, 업데이트된 설정으로 새로운 ReplicaSet을 생성합니다. Kubernetes는 각 ReplicaSet의 스케일링을 통해 Pod의 개수를 조절하며 롤링 업데이트를 진행합니다.
이 과정에서, revisionHistoryLimit 설정을 통해 이전 ReplicaSet을 몇 개까지 유지할지 지정할 수 있습니다. 이를 통해 필요할 경우 이전 Deployment 설정으로 롤백할 수 있습니다.

1. 명령어를 사용하여 revision 히스토리를 확인합니다.

$ kubectl rollout history deployment/nginx

deployment.apps/nginx
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

특정 revision의 정보도 확인할 수 있습니다.

$ kubectl rollout history deployment/nginx --revision=1

deployment.apps/nginx with revision #1
Pod Template:
  Labels:       app=nginx
        pod-template-hash=6cfb64b7c5
  Containers:
   nginx:
    Image:      nginx
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>
  Node-Selectors:       <none>
  Tolerations:  <none>

$ kubectl rollout history deployment/nginx --revision=2

deployment.apps/nginx with revision #2
Pod Template:
  Labels:       app=nginx
        pod-template-hash=57775b8976
  Containers:
   nginx:
    Image:      nginx:nonexistent
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>
  Node-Selectors:       <none>
  Tolerations:  <none>

기존 1번 revision에서 이미지가 변경되어 2번 revision으로 기록된 것을 확인할 수 있습니다.

2. 명령어를 사용하여 이전 버전으로 Deployment를 rollback 합니다.

$ kubectl rollout undo deployment/nginx

deployment.apps/nginx rolled back

명령어에 옵션을 추가하여 특정 revision으로 rollback도 가능합니다.

# revision 1으로 rollback

$ kubectl rollout undo deployment/nginx --to-revision=1

3. 명령어를 사용하여 rollback 상태를 확인합니다.

$ kubectl rollout status deployment/nginx

deployment "nginx" successfully rolled out

4. Deployment와 Pod의 상태를 확인합니다.

$ kubectl get deploy,pod

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   3/3     3            3           13m

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6cfb64b7c5-8hbjv   1/1     Running   0          13m
pod/nginx-6cfb64b7c5-lrgjt   1/1     Running   0          3m21s
pod/nginx-6cfb64b7c5-zplj8   1/1     Running   0          13m

업데이트 중 비활성화되었다가, rollback 이후 새로 생성된 revision 1의 Pod를 확인할 수 있습니다.

4. 결론

이번 포스트에서는 Kubernetes 클러스터의 Deployment 업데이트 및 rollback 시 유용하게 사용할 수 있는 옵션들에 대해 알아봤습니다. progressDeadlineSeconds 옵션을 사용하여 지정된 시간을 초과한 업데이트는 실패로 간주하도록 하고, revisionHistoryLimit 옵션을 통해 Deployment의 업데이트 내역의 최대 개수를 설정했습니다.

progressDeadlineSeconds 옵션을 환경에 맞게 설정하면 비정상적인 업데이트 및 실패를 감지하고 클러스터의 안정성을 높일 수 있습니다. revisionHistoryLimit 옵션의 경우 Deployment가 이전 버전으로 rollback이 필요한 상황에도 손쉽고 빠르게 적용할 수 있어 유용합니다.
하지만 두 옵션 모두 환경에 맞는 적절한 설정이 필요합니다. progressDeadlineSeconds 옵션이 너무 짧게 설정될 경우 정상적인 업데이트로 실패로 간주될 수 있고, 너무 길 경우 문제 감지가 늦어지게 됩니다. revisionHistoryLimit 옵션은 너무 적게 설정 시 이전 버전으로 복구가 제한되고, 너무 많이 설정하면 etcd에 저장되는 데이터가 증가하여 불필요한 리소스 소비가 발생할 수 있습니다.

Kubernetes 클러스터에서 높은 점유율을 자랑하는 NGINX Ingress Controller의 상업용 엔터프라이즈 버전인 NGINX Plus Ingress Controller를 사용해 보고 싶으시다면, NGINX STORE를 통해 문의해 무료로 NGINX Plus trial을 체험해 보세요.

NGINX STORE를 통한 솔루션 도입 및 기술지원 무료 상담 신청

* indicates required