본문 바로가기
Container/Kubernetes

3. Deployment

by wrynn 2022. 3. 9.

 운영 환경에 애플리케이션을 배포할 때, 일반적으로 하나만 배포하지 않고 여러 개의 애플리케이션 인스턴스를 배포합니다. 쿠버네티스에서 각 애플리케이션은 컨테이너(혹은 이를 감싸는 Pod) 형태로 배포됩니다.

 새로운 버전의 애플리케이션이 출시되어 업데이트를 수행할 때에는 실행 중인 컨테이너를 중단시키고 새로운 이미지를 사용하여 컨테이너를 다시 생성해야 합니다. 이 때, 모든 컨테이너를 한번에 중단시킨다면 사용자가 일시적으로 애플리케이션에 접근할 수 없어지는 문제가 발생하므로, 이를 해결하기 위해 일부 컨테이너만 순차적으로 재시작시키는 Rolling Update 전략을 사용하면 무중단 배포를 수행할 수 있습니다.

 또한 업데이트 도중 문제가 발견된다면, 일시적으로 중단하고 해결을 시도하거나 다시 이전 버전의 컨테이너로 복구를 시도할 수 있습니다. 쿠버네티스에서는 이 모든 기능을 Deployment 하나로 구현이 가능합니다.


Deployment

  Deployment를 생성하는 yaml 파일 양식은 아래와 같습니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

 이 가운데 주로 사용되는 필드 값들을 몇가지 살펴보겠습니다.

  • .spec.selector : Deployment에 의해 관리가 되는 Pod에 대한 label selector 입니다. (필수)
  • .spec.template : 실행할 Pod에 대한 정보를 기술합니다. apiVersion 및 kind 를 제외한 metadata 및 spec 정보만 작성하며, Deployment 생성 혹은 업데이트 시 해당 정보를 가진 Pod가 실행됩니다. (필수)
  • .spec.replicas : 필요한 Pod의 수를 지정합니다. (선택, 기본값 1)
  • .spec.strategy.type : 업데이트 시 동작 방식을 지정할 수 있습니다. RollingUpdate는 순차적으로 Pod를 교체하지만, Recreate는 이전 버전의 Pod를 한번에 중단시키고 새로운 버전의 Pod를 실행합니다. (선택, 기본값 RollingUpdate) 
  • .spec.strategy.rollingUpdate.maxUnavailable : Rolling 업데이트 중 사용할 수 없는 Pod의 최대 수를 지정합니다. 개수를 나타내는 숫자 혹은 replica 의 일정 비율을 나타내는 % 값이 올 수 있습니다. (선택, 기본값 25%)
  • .spec.strategy.rollingUpdate.maxSurge : Rolling 업데이트 시 새로 생성되는 Pod의 최대 수를 지정합니다. maxUnavailable과 마찬가지로 개수를 나타내는 숫자 혹은 replica 의 일정 비율을 나타내는 % 값이 올 수 있습니다. (선택, 기본값 25%)

 

 


Deployment Update

 Deployment를 생성하거나, Pod template을 업데이트하면 그 Deployment에 의해 관리되는 새로운 Replica Set이 만들어지고 결과적으로 Replica Set이 Pod를 생성하는 방식으로 동작합니다. 이러한 구조는 변경을 더 유연하게 만들어 줍니다. 예를 들어 새로운 버전의 애플리케이션이 출시되었다면 신규 컨테이너 이미지로 Pod를 새로 생성해야 합니다. kubectl set image 명령어로 Deployment가 관리하는 Pod의 이미지 정보를 교체할 수 있습니다.

$ kubectl set image deployment nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated

 이미지가 교체되면 Deployment는 새로운 이미지 정보를 포함하는 Replica Set을 하나 더 생성하고, 이 Replica Set은 새로운 이미지로 Pod를 생성합니다. 이에 따라 기존 이미지 정보를 가지고 있는 Replica Set은 관리하는 Pod 수를 줄여나가게 됩니다. 마지막에는 업데이트 시 새로 생성된 Replica Set이 관리하는 Pod만 남고 기존 버전의 Replica Set이 관리하는 replica 수는 0이 되며 업데이트가 종료됩니다. 

 하지만 위와 같이 이미지 하나만 바뀌는 것이 아니라, Deployment에 여러가지 수정 사항이 필요하다면 그 때 마다 Replica Set을 새로 생성해야 할까요? 그것은 아닙니다. kubectl rollout pause 명령을 통해 잠시 Deployment의 Rollout(Rolling Update)을 중단시킬 수 있습니다. 그리고 여러가지 수정을 거친 다음, kubectl rollout resume 명령으로 Rollout을 재개하여 변경 사항을 반영할 수 있습니다. 

$ kubectl rollout pause deployment/nginx-deployment
deployment.apps/nginx-deployment paused
...
$ kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed

 Deployment를 활용한 업데이트 시 알아두면 좋은 몇가지 사항을 소개합니다.

  • 쿠버네티스에서 업데이트 도중 중단되는 Pod는 최소 1개, 최대 Deployment에 명시된 replicas 수의 25%로 제한합니다. 하지만 업데이트 도중에 Deployment를 변경하는 경우, 바로 이전 Replica Set에 의해 생성된 Pod는 모두 한번에 중단될 수 있으므로 주의해야 합니다. 
  • 일반적으로 selector 정보를 변경하는 것은 권장하지 않습니다. 
  • Deployment에 의해 생성되는 Replica Set은 업데이트를 계속하면 점점 늘어만 갈까요? 쿠버네티스는 이러한 부분도 놓치지 않았습니다. Deployment 의 .spec.revisionHistoryLimit 필드는 남겨둘 Replica Set의 수를 지정할 수 있으며 기본값은 10입니다. 만약 이 값을 0으로 변경한다면 이전 변경 내역은 모두 사라지고 해당 Deployment는 롤백이 불가능한 상태가 됩니다.

Deployment scale

 실행할 Pod 수의 조정은 다음과 같이 수행합니다. kubectl scale 명령은 Pod template을 변경하는 것이 아니기 때문에 새로운 Replica Set을 생성하지 않습니다.

$ kubectl scale deployment/nginx-deployment --replicas=10
deployment.apps/nginx-deployment scaled

 

 또한 CPU 사용률에 따라 Pod 수를 자동으로 조절하게 만들수도 있습니다. 이렇게 하기 위해서는 클러스터가 CPU 사용률을 수집할 수 있는 metrics server가 별도로 구성되어야 합니다.

$ kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80
deployment.apps/nginx-deployment scaled

Deployment Rollback

 롤백을 위해서는 먼저 kubectl rollout history 명령을 통해 rollout 이력을 확인해야 합니다. CHANGE-CAUSE 열은 git의 commit message와 같이 변경에 대한 주석 역할을 하며, kubectl annotate 명령을 사용하여 변경 내용에 대한 설명을 작성할 수 있습니다.

$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION    CHANGE-CAUSE
1           kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
2           kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
3           kubectl set image deployment/nginx-deployment nginx=nginx:1.161

 각각 수정된 버전의 상세 정보를 보려면 kubectl rollout history 명령에 --revision 옵션을 주어 확인합니다.

$ kubectl rollout history deployment/nginx-deployment --revision=2
deployments "nginx-deployment" revision 2
  Labels:       app=nginx
          pod-template-hash=1159050644
  Annotations:  kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
  Containers:
   nginx:
    Image:      nginx:1.16.1
    Port:       80/TCP
     QoS Tier:
        cpu:      BestEffort
        memory:   BestEffort
    Environment Variables:      <none>
  No volumes.

 바로 이전 버전으로 롤백은 kubectl rollout undo 명령을 사용합니다.

$ kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back

 혹은 다음과 같이 --to-revision 옵션을 사용해 특정 버전으로 롤백할 수도 있습니다.

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

롤백 시 유의사항은 다음과 같습니다.

  •  Deployment에 의해 수행되는 롤백은 Pod template(.spec.template) 아래에 명시된 정보에 한해 수행된다는 점에 유의해야 합니다. 예를 들어 replica 수(.spec.replicas)와 같은 필드는 Pod template에 명시된 정보가 아니므로 롤백 시에도 그 값을 그대로 유지합니다. 하지만 이미지 정보를 변경한 경우 (.spec.template.spec.containers[0].image) 롤백 시에 이전 revision에 해당하는 정보로 변경됩니다.
  • kubectl rollout pause 명령으로 중단된 Deployment는 롤백을 수행할 수 없습니다. 반드시 kubectl rollout resume 명령으로 재개한 다음에 롤백을 수행할 수 있습니다. 

References

 

Deployments

A Deployment provides declarative updates for Pods and ReplicaSets. You describe a desired state in a Deployment, and the Deployment Controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new Rep

kubernetes.io

 

댓글