코알못

[kubernetes] Deployment - 배포 전략 Recreate, RollingUpdate 및 롤백 본문

ETC

[kubernetes] Deployment - 배포 전략 Recreate, RollingUpdate 및 롤백

코린이s 2023. 5. 26. 23:25
728x90

저번시간에 Deployment 배포 전략 두가지에 대해서 간단하게 개념을 배웠고 이번시간 실습을 통해 익혀보도록 하자! 추가로 롤백 하는 방법도 알아보도록 하며 실습 내용은 아래와 같다.

  1. 배포전략 Recreate 실습
  2. 배포전략 RollingUpdate 실습
  3. Revision 을 통한 롤백 실습

우선 배포전략 Recreate 실습을 진행해보자!

아래와 같이 Deployment 오브젝트 yaml 파일을 작성한다.

# deployment-v4.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"

클러스터에 적용한다.

$ kubectl apply -f deployment-v4.yaml
deployment.apps/my-app created

정상적으로 배포 됐는지 상세정보를 확인하며 정상적으로 3개의 파드를 생성하였다.

$ kubectl describe deployment/my-app
Name:               my-app
Namespace:          default
CreationTimestamp:  Sun, 21 May 2023 16:51:06 +0900
Labels:             app=my-app
Annotations:        deployment.kubernetes.io/revision: 1
Selector:           app=my-app
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=my-app
  Containers:
   my-app:
    Image:      yoonjeong/my-app:1.0
    Port:       8080/TCP
    Host Port:  0/TCP
    Limits:
      cpu:        50m
      memory:     64Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-app-5d6554bfbf (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  42s   deployment-controller  Scaled up replica set my-app-5d6554bfbf to 3

이제 배포 과정을 보기 위해 이미지 버전을 1.0 > 2.0으로 변경 해본다.

우선 기존 deployment 파일의 image 부분을 1.0 > 2.0으로 수정한다.

# deployment-v4.yaml

spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:2.0

deployment 상세 설명을 보면 기존 ReplicaSet의 Pod 모두 종료후 새 ReplicaSet의 Pod 생성 하는것을 볼 수 있다.

$ kubectl describe deployment/my-app
Name:               my-app
Namespace:          default
CreationTimestamp:  Sun, 21 May 2023 16:51:06 +0900
Labels:             app=my-app
Annotations:        deployment.kubernetes.io/revision: 2
Selector:           app=my-app
Replicas:           3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       Recreate
MinReadySeconds:    0
Pod Template:
  Labels:  app=my-app
  Containers:
   my-app:
    Image:      yoonjeong/my-app:2.0
    Port:       8080/TCP
    Host Port:  0/TCP
    Limits:
      cpu:        50m
      memory:     64Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-app-856cb86fb4 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  17m   deployment-controller  Scaled up replica set my-app-5d6554bfbf to 3
  Normal  ScalingReplicaSet  63s   deployment-controller  Scaled down replica set my-app-5d6554bfbf to 0 from 3
  Normal  ScalingReplicaSet  61s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 3

이제 RollingUpdate(점진전 배포 전략)을 실습 해보자!

저번 시간에 간단하게 본 개념을 다시 짚어보자면!

maxUnavaliable은 최대 이용 불가능 파드이며 maxSurge는 한시점 파트 최대 추가 파드 갯수 (최대 파드 수 : replicas + maxSurge) 이다.

예시로 replicas 3, maxUnavaliable 1, maxSurge 1 이라면 최소 떠있어야 하는 파드는 2개(replicas-maxUnavaliable), 최대 파드는 4개(replicas+maxSurge)가 된다.

실습을 위해 deployment 오브젝트의 yaml 파일을 만들고

replicas 5, maxUnavailable 2, maxSurge 1로  최소 3개의 파드, 최대 6개의 파드가 뜰 수 있도록 한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 5
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 2
      maxSurge: 1
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"

클러스터에 적용한다.

$ kubectl apply -f deployment-v5.yaml
deployment.apps/my-app created

deployment 의 상세정보를 보면 정상적으로 5개의 pod 를 생성 하였다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Fri, 26 May 2023 21:11:15 +0900
Labels:                 app=my-app
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=my-app
Replicas:               5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  2 max unavailable, 1 max surge
Pod Template:
  Labels:  app=my-app
  Containers:
   my-app:
    Image:      yoonjeong/my-app:1.0
    Port:       8080/TCP
    Host Port:  0/TCP
    Limits:
      cpu:        50m
      memory:     64Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-app-5d6554bfbf (5/5 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  20m   deployment-controller  Scaled up replica set my-app-5d6554bfbf to 5

파드 항목을 조회하여 정상적으로 떴는지 확인하며

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
my-app-5d6554bfbf-5h896   1/1     Running   0          20m
my-app-5d6554bfbf-l5pnz   1/1     Running   0          20m
my-app-5d6554bfbf-pdkns   1/1     Running   0          20m
my-app-5d6554bfbf-vjzmr   1/1     Running   0          20m
my-app-5d6554bfbf-z4kmj   1/1     Running   0          20m

롤아웃이 정상적으로 이뤄졌는지 체크한다.

$ kubectl rollout status deployment/my-app
deployment "my-app" successfully rolled out

이제 replicaset의 상태를 보면 5개가 정상적으로 레디 된것을 볼 수 있다.

$ kubectl get rs -w
NAME                DESIRED   CURRENT   READY   AGE
my-app-5d6554bfbf   5         5         5       29m

이제 버전을 1.0 > 2.0 으로 변경하여 배포 전략을 지켜 보도록 하자!

아래와 같이 image 부분을 1.0 > 2.0 으로 변경한다.

# deployment-v5.yaml 

  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:2.0

클러스터에 적용 한다.

$ kubectl apply -f deployment-v5.yaml

 

deployment 이벤트를 상세적으로 보면 아래와 같으며 해석 해보면

최소 3개의 파드, 최대 6개의 파드가 있을수 있으니 새로운 파드를 하나 띄우고, 최소 3개의 파드니 기존 파드 2개를 죽이고 그 뒤는 점진적 배포를 진행한다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Fri, 26 May 2023 21:11:15 +0900
Labels:                 app=my-app
Annotations:            deployment.kubernetes.io/revision: 2
Selector:               app=my-app
Replicas:               5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  2 max unavailable, 1 max surge
Pod Template:
  Labels:  app=my-app
  Containers:
   my-app:
    Image:      yoonjeong/my-app:2.0
    Port:       8080/TCP
    Host Port:  0/TCP
    Limits:
      cpu:        50m
      memory:     64Mi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-app-856cb86fb4 (5/5 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  32m   deployment-controller  Scaled up replica set my-app-5d6554bfbf to 5
  Normal  ScalingReplicaSet  50s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 1
  Normal  ScalingReplicaSet  50s   deployment-controller  Scaled down replica set my-app-5d6554bfbf to 3 from 5
  Normal  ScalingReplicaSet  50s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 3 from 1
  Normal  ScalingReplicaSet  40s   deployment-controller  Scaled down replica set my-app-5d6554bfbf to 2 from 3
  Normal  ScalingReplicaSet  40s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 4 from 3
  Normal  ScalingReplicaSet  39s   deployment-controller  Scaled down replica set my-app-5d6554bfbf to 1 from 2
  Normal  ScalingReplicaSet  39s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 5 from 4
  Normal  ScalingReplicaSet  39s   deployment-controller  Scaled down replica set my-app-5d6554bfbf to 0 from 1

위에서 확인한 새로운 template hash 번호로 파드가 뜬 것을 확인할 수 있다.

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
my-app-856cb86fb4-q64gr   1/1     Running   0          4m12s
my-app-856cb86fb4-q7ltx   1/1     Running   0          4m23s
my-app-856cb86fb4-rhsnc   1/1     Running   0          4m23s
my-app-856cb86fb4-stsft   1/1     Running   0          4m23s
my-app-856cb86fb4-zmskv   1/1     Running   0          4m13s

정상적으로 서비스가 되는지 확인 하기 위해 포트 포워딩으로 pod 에 호출 해본다.

$ kubectl port-forward deployment/my-app 8080:8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

포트 포워드는 로드 밸런싱 되지 않으니 하나의 파드에만 호출 되며 변경된 이미지의 버전인 v2를 바라보는것을 확인 할 수 있다.

$ curl localhost:8080
Welcome to Version 2!

===== Host Info =====
HostIP: 10.100.2.27
HostName: my-app-856cb86fb4-q7ltx

$ curl localhost:8080
Welcome to Version 2!

===== Host Info =====
HostIP: 10.100.2.27
HostName: my-app-856cb86fb4-q7ltx

Welcome to Version 2!

$ curl localhost:8080
===== Host Info =====
HostIP: 10.100.2.27
HostName: my-app-856cb86fb4-q7ltx%

이제 실습을 종료하며 아래와 같이 label 이 my-app 인 모든 오브젝트를 제거한다.

$ kubectl delete all -l app=my-app
pod "my-app-856cb86fb4-q64gr" deleted
pod "my-app-856cb86fb4-q7ltx" deleted
pod "my-app-856cb86fb4-rhsnc" deleted
pod "my-app-856cb86fb4-stsft" deleted
pod "my-app-856cb86fb4-zmskv" deleted
deployment.apps "my-app" deleted

이제 Revision을 통해 롤백 하는 실습을 진행해보자!

그전에 관련 명령어를 보자!

배포 히스토리를 조회 하는 방법은 아래와 같으며

$ kubectl rollout history deployment/my-app

 

특정 배포 번호의 Template 확인을 위해서는 아래와 같이 --revision 옵션을 사용하면 된다.

$ kubectl rollout hisotry deployment/my-app --revision=[배포 버전]

롤백 방법은 아래와 같이 두가지가 있다.

아래와 같이 버전을 명시하여 롤백하는 방법이 있으며

$ kubectl rollout undo deployment/my-app --to-revision=[롤백 되길 원하는 배포 버전]

--to-revision 옵션을 주지 않으면 바로 직전으로 롤백된다.

$ kubectl rollout undo deployment/my-app

 

 

롤백 사유(배포 변경 사유)는 기본 설정된 값을 사용하며 만약 수정하고 싶다면 아래와 같이 annotate 를 이용하면 된다.

$ kubectl annotate deployment/my-app kubernetes.io/change-cause=[배포 설명]

 

명령어 학습을 했다면 실습을 진행해보자!

우선 이미지 1.0 으로 배포 후에 2.0 > 1.0 > 2.0 으로 배포 해보도록 한다.

아래와 같이 1.0 배포 파일을 생성한다.

# deployment-v6.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
  annotations:
    kubernetes.io/change-cause: "image version 1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "64Mi"
            cpu: "50m"

클러스터에 적용한다.

$ kubectl rollout status deployment/my-app
deployment "my-app" successfully rolled out

롤아웃 히스토리를 확인하면 아래와 같이 배포 버전 1이 생성 된것을 볼 수 있다.

REVISION은 배포 번호로 숫자가 크면 최신이며 CHANGE-CAUSE는 배포 설명이다.

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
1         image version 1.0

이제 이미지의 버전을 2.0으로 변경한다.

$ kubectl set image deployment/my-app my-app=yoonjeong/my-app:2.0
deployment.apps/my-app image updated

정상적으로 2.0으로 변경 되었는지 확인하면 정상적으로 변경 됨을 확인 할 수 있다.

$ kubectl get deployment/my-app -o wide
NAME     READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES                 SELECTOR
my-app   3/3     3            3           3m3s   my-app       yoonjeong/my-app:2.0   app=my-app

배포 히스토리를 보면 배포 버전 2가 새로 생성된것을 볼 수 있다. 그러나 배포 설명이 기본으로 yaml 파일에 'annotations' 부분에 정의한 내용으로 동일하게 나오니 배포 사유를 수정 해보도록 하자!

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
1         image version 1.0
2         image version 1.0

아래와 같이 annotate 명령어를 이용하여 배포 설명을 수정한다.

$ kubectl annotate deployment/my-app kubernetes.io/change-cause="image update to 2.0"
deployment.apps/my-app annotated

다시 히스토리를 확인하면 정상적으로 변경 됨을 확인 할 수 있다.

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
1         image version 1.0
2         image update to 2.0

히스토리 상세적으로 보기 위해 --revision 으로 원하는 버전을 입력하여 확인한다. 

내용중 pod-template-hash 번호와 현재 파드명의 hash 번호가 일치하여 2버전이 정상 배포됨을 확인 할 수 있다.

% kubectl rollout history deployment/my-app --revision=2
deployment.apps/my-app with revision #2
Pod Template:
  Labels:	app=my-app
	pod-template-hash=856cb86fb4
  Annotations:	kubernetes.io/change-cause: image update to 2.0
  Containers:
   my-app:
    Image:	yoonjeong/my-app:2.0
    Port:	8080/TCP
    Host Port:	0/TCP
    Limits:
      cpu:	50m
      memory:	64Mi
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
my-app-856cb86fb4-dq5vv   1/1     Running   0          4m11s
my-app-856cb86fb4-m7l7n   1/1     Running   0          4m11s
my-app-856cb86fb4-zx8tt   1/1     Running   0          4m1s

이제 2.0 > 1.0 으로 롤백을 진행해보자!

아래와 같이 입력하면 revision 을 따로 입력하지 않았기에 바로 직전 배포 버전인 1로 롤백을 진행한다.

$ kubectl rollout undo deployment/my-app
deployment.apps/my-app rolled back

배포 상태 확인시 완료 됐다는 메세지가 나오며

$ kubectl rollout status deployment/my-app
deployment "my-app" successfully rolled out

히스토리를 보면 롤백 되고 배포 버전 1이였던것이 3으로 변경 되었다.

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
2         image update to 2.0
3         image version 1.0

롤백 사유를 입력하기 위해 annotate 명령어를 통해 변경 한다.

$ kubectl annotate deployment/my-app kubernetes.io/change-cause="rollback for some bugs"
deployment.apps/my-app annotated

다시 확인해보면 정상적으로 설명이 변경 되었다!

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
2         image update to 2.0
3         rollback for some bugs

이제 배포 버전 상세 설명의 pod-hash 번호와 현재 파드의 명이 일치 하는지 보면 정상적으로 버전 3으로 배포 됨을 확인할 수 있다.

$ kubectl rollout history deployment/my-app --revision=3
deployment.apps/my-app with revision #3
Pod Template:
  Labels:	app=my-app
	pod-template-hash=5d6554bfbf
  Annotations:	kubernetes.io/change-cause: rollback for some bugs
  Containers:
   my-app:
    Image:	yoonjeong/my-app:1.0
    Port:	8080/TCP
    Host Port:	0/TCP
    Limits:
      cpu:	50m
      memory:	64Mi
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>

$ kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
my-app-5d6554bfbf-72p2s   1/1     Running   0          2m33s
my-app-5d6554bfbf-gh26m   1/1     Running   0          2m33s
my-app-5d6554bfbf-wq2tr   1/1     Running   0          2m24s

이제 버전명을 명시하여 배포 버전 2(image 2.0) 롤백을 진행한다.

$ kubectl rollout undo deployment/my-app --to-revision=2
deployment.apps/my-app rolled back

배포 히스토리를 보면 정상적으로 롤백 되고 revision 번호가 4로 새로 부여된것을 확인할 수 있다.

$ kubectl rollout history deployment/my-app
deployment.apps/my-app
REVISION  CHANGE-CAUSE
3         rollback for some bugs
4         image update to 2.0

이제 실습을 종료하며 모든 오브젝트를 제거한다.

$ kubectl delete all -l app=my-app
pod "my-app-856cb86fb4-97rh5" deleted
pod "my-app-856cb86fb4-h9vvd" deleted
pod "my-app-856cb86fb4-rjb86" deleted
deployment.apps "my-app" deleted

끝!

728x90
Comments