코알못

[kubernetes] Deployment 란? 본문

ETC

[kubernetes] Deployment 란?

코린이s 2023. 5. 20. 23:12
728x90

 

 

이전 시간에는 ReplicaSet 을 통해 새 버전으로 배포하는 방법을 배웠다.

다시 복습하자면 세개의 작업을 통해 롤백이 가능하다.

  1. 새 버전으로 template 수정
  2. 기존 버전 파드 삭제 (scale 또는 lable 변경)
  3. 새 버전 파드 생성

만약 장애 상황이라면 급하게 해당 작업을 처리해야하는 상황이 오기도 한다.

사람이 아닌 쿠버네티스가 자동으로 해줄수 없을까? > Deployment 오브젝트를 사용하면 된다!

Deployment는 Pod 배포 자동화를 위한 오브젝트로 새로운 Pod를 롤아웃/롤백 할때 ReplicaSet 생성, Pod 복제를 대신 해준다.

Deployment는 ReplicaSet을 이용하여 배포하며 아래와 같이 두가지 배포 전략을 가지고 있다.

배포전략 설명
Recreate 모든 이전 파드를 종료하고 새로운 파드를 생성 (서비스 다운 타임 발생)
모두 종료하고 새 파드를 생성하니 Replicas 수 만큼만 리소스 필요
개발 단계에서 사용하기 좋음
RollingUpdate 이전 파드를 종료 하면서 새로운 파드를 생성 (서비스 다운 타임이 발생 하지 않음)
이전 파드와 새로운 파드가 공존하므로 Replicas 수 이상의 컴퓨팅 리소스 필요

배포 속도도 아래 옵션을 통해 조정이 가능하다.

제어 옵션 내용
maxUnavaliable Running 상태로 되어 있어야 하는 Pod 비율
만약 70 이라고 하면 70%는 running 이 되어 있어야 하므로(이전,새 파드의 합) 30% 파드는 즉시 종료가 가능하다.
maxSurge 최대 추가 Pod 비율
만약 30이라고 하면 파드 수의 합이 130%를 넘을수 없다.

롤백의 경우에는 버전 정보를 가지고 쉽게 롤백 할 수 있다.

Deployment는 Revision 으로 버전을 관리하며 숫자가 클수록 최신이며 배포 기록(Lable,containers 정보)을 가지고 있어 히스토리를 알 수 있다.

그리고 배포 기록 조회시 확인 가능한 pod-template-hash 라는 값은 template 값을 해쉬값으로 만든 것이므로 같은 값이라고 하면 같은 파드라고 볼 수 있다.

아래와 같은 방법으로 특정 버전(vision 1)으로 롤백 한다.

kubectl rollout undo deployment <deployment name> --to-revision=1

이제 부터 Deployment 오브젝트로 배포한 파드를 수정하는 실습 세가지 1) replica 수 늘리기 2) pod의 image 수정 3) pod의 label 수정을 진행한다.

1) replica 수 늘리기

Deployment yaml 파일을 작성해보자!

ReplicaSet과 동일하며 kind만 RepliaSet이 아닌 Deployment로 변경하면 된다.

# deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  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"

클러스터에 적용하고 확인해보면 정상적으로 2개의 파드가 배포 된것을 볼 수 있다.

$ kubectl apply -f deployment.yaml
deployment.apps/my-app created
$ kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP            NODE                                           NOMINATED NODE   READINESS GATES
my-app-5d6554bfbf-6n9zp   1/1     Running   0          15s   10.100.2.15   gke-corin-cluster-default-pool-d2d86113-zy02   <none>           <none>
my-app-5d6554bfbf-ww25v   1/1     Running   0          15s   10.100.3.20   gke-corin-cluster-default-pool-d2d86113-xq03   <none>           <none>
$ kubectl get pod --show-labels
NAME                      READY   STATUS    RESTARTS   AGE   LABELS
my-app-5d6554bfbf-6n9zp   1/1     Running   0          42s   app=my-app,pod-template-hash=5d6554bfbf
my-app-5d6554bfbf-ww25v   1/1     Running   0          42s   app=my-app,pod-template-hash=5d6554bfbf

deployment 상세정보를 보기 위해 아래와 같이 describe를 사용한다.

Deployment Events를 보면 ReplicaSet 'my-app-5d6554bfbf' 를 통해 2개의 파드로 Scaled up 한 것을 볼 수 있으며 

$ kubectl describe deployment my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 20:40:21 +0900
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=my-app
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% 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 (2/2 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  109s  deployment-controller  Scaled up replica set my-app-5d6554bfbf to 2

Deployment에 의해 생성된 ReplicaSet 정보를 보면 2개의 파드를 원하며(desired) 현재 생성된 파드(current)는 2개 이며 사용할 준비된 파드(ready)는 2개라고 나온다.

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
my-app-5d6554bfbf   2         2         2       3m2s

deployment 의 경우 rollout 작업이 완료 되었는지 아래 명령어로 확인도 가능하다.

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

이제 scale 명령어를 통해 repliaca를 5개로 늘려본다.

$ kubectl scale deployment/my-app --replicas=5
deployment.apps/my-app scaled

describe로 확인하면 pod 자체는 변경 사항이 없기에 replicaSet은 'my-app-5d6554bfbf'로 동일하며 2개 > 5개로 늘어난 이벤트를 확인 할 수 있다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 20:40:21 +0900
Labels:                 <none>
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:  25% max unavailable, 25% 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
  ----           ------  ------
  Progressing    True    NewReplicaSetAvailable
  Available      True    MinimumReplicasAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-app-5d6554bfbf (5/5 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  4m13s  deployment-controller  Scaled up replica set my-app-5d6554bfbf to 2
  Normal  ScalingReplicaSet  19s    deployment-controller  Scaled up replica set my-app-5d6554bfbf to 5 from 2

정상적으로 rollout 이 됐는지 확인하면 완료 되었다고 나온다.

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

컨테이너가 정상인지 확인을 하기위해 포트포워딩을 진행하며

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

포워딩한 포트로 호출하면 정상적으로 버전 1로 나오는것을 볼 수 있다.

$ curl localhost:8080
Welcome to Version 1!

===== Host Info =====
HostIP: 10.100.2.15
HostName: my-app-5d6554bfbf-6n9zp

이제 첫번째 실습을 종료하기 위해 deployment 를 삭제 하면 replicaset, pod 모두 제거 된다.

$ kubectl delete deployment my-app
deployment.apps "my-app" deleted
$ kubectl get pod
No resources found in default namespace.
$ kubectl get deployment
No resources found in default namespace.
$ kubectl get rs
No resources found in default namespace.

2) pod의 image 수정

이제 파드의 이미지 버전을 수정해보자! (1.0 > 2.0 으로 변경 예정)

우선 deployment 를 생성하기 위한 파일을 작성하며 첫번째 실습과 다른점은 replica 수가 2>3 으로 변경 하였으며 deployment 의 label 값을 추가하였다.

# deployment-v2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  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-v2.yaml
deployment.apps/my-app created

정상적으로 적용 되었는지 이벤트를 확인하면 ReplicaSet 'my-app-5d6554bfbf'로 3개의 파드를 스케일 업 했다고 나오는 것을 보니 정상이다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 20:55:26 +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:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% 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 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  25s   deployment-controller  Scaled up replica set my-app-5d6554bfbf to 3

이제 명령어를 통해 이미지 버전을 1.0 > 2.0 으로 변경한다.

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

다시 Deployment의 이벤트를 보면 새로운 ReplicaSet 'my-app-856cb86fb4' 가 추가 되었으며 해당 ReplicaSet 을 통해 새 파드를 1개 생성한다. 그 뒤에 이전 ReplicaSet 'my-app-5d6554bfbf'으로 기존 파드 수를 3 > 2 로 스케일 다운 하는것을 볼 수 있다.

이렇게 deployment가 점진적으로 배포(새 파드 1개 생성, 구 파드 1개 제거)를 자동으로 하는것을 볼 수 있다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 20:55:26 +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:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% 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 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  3m29s  deployment-controller  Scaled up replica set my-app-5d6554bfbf to 3
  Normal  ScalingReplicaSet  40s    deployment-controller  Scaled up replica set my-app-856cb86fb4 to 1
  Normal  ScalingReplicaSet  29s    deployment-controller  Scaled down replica set my-app-5d6554bfbf to 2 from 3
  Normal  ScalingReplicaSet  29s    deployment-controller  Scaled up replica set my-app-856cb86fb4 to 2 from 1
  Normal  ScalingReplicaSet  18s    deployment-controller  Scaled down replica set my-app-5d6554bfbf to 1 from 2
  Normal  ScalingReplicaSet  18s    deployment-controller  Scaled up replica set my-app-856cb86fb4 to 3 from 2
  Normal  ScalingReplicaSet  7s     deployment-controller  Scaled down replica set my-app-5d6554bfbf to 0 from 1

배포 작업이 끝나고 ReplicaSet을 확인해보면 아래와 같이 이전 파드 관련 'my-app-5d6554bfbf' 은 현재 0개, 새 파드 관련 ReplicaSet인 'my-app-856cb86fb4'는 3개로 정상 배포 된것을 볼 수 있다.

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
my-app-5d6554bfbf   0         0         0       5m3s
my-app-856cb86fb4   3         3         3       2m14s

컨테이너가 정상 동작하는지 포트 포워딩을 통해 확인해보면

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

아래와 같이 version 2 로 정상 호출 되는것을 볼 수 있다.

$ curl localhost:8080
Welcome to Version 2!

===== Host Info =====
HostIP: 10.100.3.23
HostName: my-app-856cb86fb4-44492

이제 두번째 실습을 종료하며 모든 오브젝트를 삭제한다. 이번에는 deployment에 'app=my-app' lable 값을 붙였으니 해당 레이블로 모두 삭제 한다.

$ kubectl delete all -l app=my-app
pod "my-app-856cb86fb4-44492" deleted
pod "my-app-856cb86fb4-5l4g8" deleted
pod "my-app-856cb86fb4-skwpg" deleted
deployment.apps "my-app" deleted
$ kubectl get rs
No resources found in default namespace.
$ kubectl get deployment
No resources found in default namespace.
$ kubectl get pod
NAME                      READY   STATUS        RESTARTS   AGE
my-app-856cb86fb4-fcvrp   1/1     Terminating   0          19s
my-app-856cb86fb4-fdpmk   1/1     Terminating   0          20s
my-app-856cb86fb4-j4mcs   1/1     Terminating   0          18s
$ kubectl get pod
No resources found in default namespace.

3) pod의 label 수정

 

아래와 같이 deployment 를 생성한다.

# deployment-v3.yaml

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

클러스터에 적용한다.

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

정상적으로 생성 되었는지 이벤트를 확인하며 3개의 파드를 정상적으로 생성함을 확인 할 수 있었다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 21:14:57 +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:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% 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 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  19s   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 3

이제 deployment yaml 파일의 label env 를 추가해본다!

# deployment-v3.yaml

spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        env: prod

클러스터에 변경 사항을 적용한다.

$ kubectl apply -f deployment-v3.yaml
deployment.apps/my-app configured

정상적으로 적용 되었는지 상세 이벤트를 보면 Pod 정보가 변경(label 추가) 되어 ReplicaSet 이 새로 생성 되었으며(replicaset 의 뒤에 template 해쉬 번호가 다르다.) 스케일업/다운이 이뤄진것을 볼 수 있다.

$ kubectl describe deployment/my-app
Name:                   my-app
Namespace:              default
CreationTimestamp:      Sat, 20 May 2023 21:14:57 +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:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=my-app
           env=prod
  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-94cc98846 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  11m   deployment-controller  Scaled up replica set my-app-856cb86fb4 to 3
  Normal  ScalingReplicaSet  59s   deployment-controller  Scaled up replica set my-app-94cc98846 to 1
  Normal  ScalingReplicaSet  49s   deployment-controller  Scaled down replica set my-app-856cb86fb4 to 2 from 3
  Normal  ScalingReplicaSet  49s   deployment-controller  Scaled up replica set my-app-94cc98846 to 2 from 1
  Normal  ScalingReplicaSet  40s   deployment-controller  Scaled down replica set my-app-856cb86fb4 to 1 from 2
  Normal  ScalingReplicaSet  40s   deployment-controller  Scaled up replica set my-app-94cc98846 to 3 from 2
  Normal  ScalingReplicaSet  29s   deployment-controller  Scaled down replica set my-app-856cb86fb4 to 0 from 1

ReplicaSet을 보면 아래와 같이 이전 버전의 ReplicaSet은 Pod 0개, 새 ReplicaSet은 Pod 3개로 정상 배포 된것을 볼 수 있다.

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
my-app-856cb86fb4   0         0         0       12m
my-app-94cc98846    3         3         3       108s

이제 Pod Label 정보까지 확인해보면 정상적으로 env Lable 이 모두 붙어 있는것을 볼 수 있다.

$ kubectl get pod --show-labels
NAME                     READY   STATUS    RESTARTS   AGE     LABELS
my-app-94cc98846-5bfc9   1/1     Running   0          2m26s   app=my-app,env=prod,pod-template-hash=94cc98846
my-app-94cc98846-brzlw   1/1     Running   0          2m7s    app=my-app,env=prod,pod-template-hash=94cc98846
my-app-94cc98846-hzg7q   1/1     Running   0          2m16s   app=my-app,env=prod,pod-template-hash=94cc98846

이제 실습이 완료 되어 모든 pod, replicaset, deployment 를 제거한다!

$ kubectl delete all -l app=my-app
pod "my-app-94cc98846-5bfc9" deleted
pod "my-app-94cc98846-brzlw" deleted
pod "my-app-94cc98846-hzg7q" deleted
deployment.apps "my-app" deleted
$ kubectl get pod
No resources found in default namespace.
$ kubectl get rs
No resources found in default namespace.
$ kubectl get deployment
No resources found in default namespace.

이번 실습을 통해 deployment 오브젝트를 통해 변경 사항이 있다면 자동으로 배포 되는 부분을 확인 하였다.

다음 시간에는 배포 전략을 변경하며 배포하는 실습을 진행해보자!

끝!

728x90
Comments