5 minute read

Deployment 배포 전략

Recreate 배포

Recreate 배포는 개발할 때 주로 사용하는 배포 전략입니다.
Recreate 전략을 개발 시에 사용하는 이유는 Recreate 전략을 사용하여 신규 버전을 배포하면 Deployment는 이전 Pod를 모두 종료하고 새로운 Pod를 replicas만큼 생성하기 때문입니다.
즉, 이전 버전의 Pod를 모두 삭제한 후에 새로운 Pod들을 생성하므로 필연적으로 Pod가 하나도 존재하지 않는 시점이 생겨 서비스 다운타임이 발생하기 때문에 개발 단계에서 주로 사용하며 운영 환경에서는 사용하기 적합하지 않습니다.

Recreate 배포의 동작 방식을 알아보기 위해 my-app이라는 deployment를 배포했다가 Image와 Label을 업데이트 하도록 하겠습니다.

Deployment 생성

Deployment를 배포하기 위해 아래 스펙대로 deployment.yml 파일을 작성합니다.

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
        project: deployment_sample
        env: local
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"

이 때 rollout 전략을 적용하기 위해 다음 부분이 추가되었음을 알 수 있습니다.

strategy:
  type: Recreate

deployment를 아래 명령어를 통해 생성합니다.

$ kubectl apply -f deployment.yml

deployment의 배포 진행 / 완료 상태를 확인하기 위해 아래 명령어를 사용합니다.

$ kubectl rollout status deployment/my-app

app=my-app 레이블을 갖는 모든 리소스를 조회하기 위해서는 아래 명령어를 사용할 수 있습니다.

$ kubectl get all -l app=my-app -o wide --show-labels

컨테이너 이미지와 레이블 변경

위에서 생성한 deployment의 컨테이너 이미지와 레이블을 변경해서 재배포해보도록 하겠습니다.
앞서 작성한 deployment.yml 파일을 아래와 같이 변경해줍니다.

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
        project: deployment_sample
        env: local
        version: v2
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:2.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"

labelsversion: v2를 추가했으며, image의 태그를 2.0으로 변경했습니다.

변경 후에 apply 명령어를 이용해 deployment를 재배포합니다.

$ kubectl apply -f deployment.yml

그리고 난 후 다음 명령어로 이벤트를 조회해봅니다.

$ kubectl describe deployment/my-app

기존에 생성되었던 replicaset의 pod 수를 0개로 줄인 후에 새로운 replicaset을 이용해 3개의 pod를 다시 띄우는 것을 확인할 수 있습니다.

replicaset의 상태 확인은 아래 명령어를 통해 가능합니다.

$ kubectl get rs -w

deployment 초기 배포시 생성되었던 replicaset의 개수를 0개까지 줄이고 새로운 replicaset을 통해 다시 pod를 3개 띄우는 것을 확인할 수 있습니다.

deployment의 상태 확인은 아래 명령어를 통해 가능합니다.

$ kubectl get deployment -w

Recreate 배포 전략 동작 방법

Recreate를 배포 전략으로 삼은 후 deployment에 업데이트 사항이 있을 때 pod와 replicaset은 다음 그림과 같이 동작합니다.

위의 그림에서 보면 알 수 있듯이 Recreate 전략 사용 시에는 기존 pod가 모두 제거되고 난 후에 새로운 pod가 생성됩니다.
따라서 Recreate 방식은 다운 타임이 발생하므로 운영에는 적합하지 않고 적은 리소스로 서비스를 확인해보는 개발 환경에 적합합니다.

RollingUpdate 배포

RollingUpdate는 운영 환경에서 사용 가능한 배포 전략입니다.
RollingUpdate 방식을 통해 배포를 하면 기존 pod를 다 삭제한 후 신규 pod를 띄우지 않기 때문에 기존 pod와 신규 pod가 동시에 존재하는 시점이 존재합니다.

RollingUpdate 방식으로 배포할 때 속도 제어 옵션을 사용할 수 있는데요, 옵션으로는 maxUnavailable과 maxSurge가 있습니다.

  • maxUnavailable: 기존의 Pod를 새로운 Pod로 전환하는 과정에서 Pod 제거와 생성을 반복할 때 최소로 유지해야하는 Pod의 개수
    • desired replicas - maxUnavailable
  • maxSurge: 기존 Pod를 새로운 Pod로 전환하는 과정에서 Pod 제거와 생성을 반복할 때 동시에 존재할 수 있는 최대 Pod의 개수
    • desired replicas + maxSurge

RollingUpdate는 배포가 점진적으로 일어나며, 아래 그림과 같은 과정을 거쳐 신규 Pod로 모든 Pod들이 대체됩니다.
. 배포 과정 중 아래와 같이 기존 pod가 1개 더 종료되고있을 때 replicas = 3, maxSurge=0임을 감안하여, 한번에 정상 동작중인 pod가 최대 3개까지 가능하므로 2개의 신규 pod를 동시에 생성할 수 있습니다.

추가적으로 maxSurge=1인 상황에 대해서 알아보도록 하겠습니다.
아래와 같은 상황에서 동시에 존재할 수 있는 pod 개수의 최소값은 2이고, 최대값은 4가 됩니다.

배포 과정 중 아래와 같이 기존 pod가 1개 더 종료되고있을 때 replicas = 3, maxSurge=1임을 감안하여, 한번에 정상 동작중인 pod가 최대 4개까지 가능하므로 3개의 신규 pod를 동시에 생성할 수 있습니다.

RollingUpdate 배포 전략 동작 방법

RollingUpdate를 배포 전략으로 삼은 후 deployment에 업데이트 사항이 있을 때 pod와 replicaset은 다음 그림과 같이 동작합니다.
아래 그림은 relicas=3, maxUnavailable=1, maxSurge=1인 경우 재배포가 있을 때 동작 흐름입니다.
maxSurge=1이기 때문에 재배포 시작 즉시 신규 pod를 하나 생성할 수 있습니다.
그 후부터는 기존 pod가 하나 제거될 때마다 새로운 pod 배포가 가능합니다.
따라서 Ready 상태로 유지해야 하는 최소 ~ 최대 pod replicas 구간은 <2개 ~ 4개> 임을 알 수 있습니다.

Deployment 생성

Deployment를 배포하기 위해 아래 스펙대로 deployment.yml 파일을 작성합니다.

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
        project: deployment_sample
        env: local
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:1.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"

strategy 항목을 보면 type을 RollingUpdate로 정의했으며, maxUnavailable을 2로, maxSurge를 1로 설정했음을 확인할 수 있습니다.

deployment를 아래 명령어를 통해 생성합니다.

$ kubectl apply -f deployment.yml

deployment의 배포 진행 / 완료 상태를 확인하기 위해 아래 명령어를 사용합니다.

$ kubectl rollout status deployment/my-app

app=my-app 레이블을 갖는 모든 리소스를 조회하기 위해서는 아래 명령어를 사용할 수 있습니다.

$ kubectl get all -l app=my-app -o wide --show-labels

컨테이너 이미지와 레이블 변경

위에서 생성한 deployment의 컨테이너 이미지와 레이블을 변경해서 재배포해보도록 하겠습니다.
앞서 작성한 deployment.yml 파일을 아래와 같이 변경해줍니다.

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
        project: deployment_sample
        env: local
        version: v2
    spec:
      containers:
      - name: my-app
        image: yoonjeong/my-app:2.0
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"

변경 후에 apply 명령어를 이용해 deployment를 재배포합니다.

$ kubectl apply -f deployment.yml

그리고 난 후 다음 명령어로 이벤트를 조회해봅니다.

$ kubectl describe deployment/my-app


기존에 생성되었던 replicaset의 pod 수를 0개로 줄인 후에 새로운 replicaset을 이용해 5개의 pod를 다시 띄우는 것을 확인할 수 있습니다.

replicaset의 상태 확인은 아래 명령어를 통해 가능합니다.

$ kubectl get rs -w


deployment 초기 배포시 생성되었던 replicaset의 개수를 0개까지 줄이고 새로운 replicaset을 통해 다시 pod를 5개 띄우는 것을 확인할 수 있습니다.

deployment의 상태 확인은 아래 명령어를 통해 가능합니다.

$ kubectl get deployment -w

RollingUpdate 배포 전략 동작 방법

위의 실습에서 RollingUpdate를 배포 전략으로 삼아 deployment를 업데이트해보았습니다.
이 때 각 단계별로 replicaset과 pod는 다음과 같이 동작합니다.

maxUnavailabe=2이므로 재배포 직후 기존 pod를 2개까지 즉시 삭제할 수 있으며, maxSurge=1이기 때문에 최대 6개까지 동시에 pod를 띄울 수 있어 신규 pod 3개를 즉시 생성 가능합니다.
모든 pod가 신규 pod로 배포될 때까지 주어진 maxUnavailablemaxSurge값에서 벗어나지 않는 선에서 신규 pod로 변경되고 있음을 확인할 수 있습니다.
rollingupdate는 이와 같이 서비스 다운타임이 발생하지 않으며, maxUnavailablemaxSurge값을 통해 서버 자원 사용량을 조절 가능하다는 점에서 운영 환경에서 쓰이기 적합합니다.