디플로이먼트 업데이트 전략의 기본값은 RollingUpdate 로, 매니페스트 파일의 spec.strategy.type 필드에서 설정을 변경할 수 있다.

전략 설명 비고
Recreate 모든 파드를 일괄 삭제하고 새로운 레플리카셋을 생성한 후 그 하위에 새로운 파드를 일괄 생성 - 서비스 다운타임 발생
- 전환 빠름
RollingUpdate 레플리카셋의 점진적 scaling 을 통해 기존 버전 레플리카 내 파드 수를 줄이고, 신규 버전 레플리카 내 파드 수를 늘리는 액션을 모든 파드가 전환될 때 까지 반복 수행 - 무중단 배포
- 전환 느림

 

1. Recreate

apiVersion: apps/v1
kind: Deployment
...
spec:
  strategy:
    type: Recreate
...

 

위와 같이 매니페스트의 spec.strategy.type: Recreate 만 지정해주면 된다. 업데이트시 추가적인 리소스 확보 필요 없이 일괄로 업데이트가 되지만, 서비스 다운타임이 몇초간 생기므로, 사용에 주의하여야 한다.

 

2. RollingUpdate

apiVersion: apps/v1
kind: Deployment
...
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  replicas: 3
...

 

위와 같이 매니페스트의 spec.strategy.type: RollingUpdate 와 spec.strategy.rollingUpdate 에 maxUnavailable, maxSurge 값을 지정해준다. 자세한 설명은 아래와 같다.

  • maxUnavailable: 업데이트중 동시에 정지상태가 될 수 있는 최대 파드 갯수
  • maxSurge: 업데이트중 동시에 추가 생성될 수 있는 최대 파드 갯수

즉, 이 두 값을 통해서 업데이트중에 최소 살아있어야 하는 pod 갯수와 over 하여 생성될 수 있는 pod 갯수를 제어할 수 있다. 두 값 모두 동시에 0으로 설정할 수는 없다. 설명이 조금 어려운데, 아래와 같이 이해하면 된다.

  • 업데이트 중 최소 파드 갯수: $replicas - $maxUnavailable
  • 업데이트 중 최대 파드 갯수: $replicase + $maxSurge

replicas: 3, maxUnavailable: 0, maxSurge: 1 로 설정한 경우 아래의 그림과 같이 업데이트된다.

  • 최소 파드 갯수: 3
  • 최대 파드 갯수: 4

 

replicas: 3, maxUnavailable: 1, maxSurge: 0 로 설정한 경우 아래의 그림과 같이 업데이트된다.

  • 최소 파드 갯수: 2
  • 최대 파드 갯수: 3

 

maxUnavailable, maxSurge 는 백분율 값으로도 지정할 수 있으며, 지정하지 않을 경우 기본값은 각각 25% 이다. 백분율로 설정 시 실제 pod 수 계산은 replicas 에 대한 백분율로 계산 되는데, 계산된 값이 정수로 맞아 떨어지지 않는 경우 아래와 같이 계산된다.

 

  • maxUnavailable: 소수점 내림(round down)
  • maxSurge: 소수점 올림(round up)

공식문서 참고

 

Deployments

A Deployment manages a set of Pods to run an application workload, usually one that doesn't maintain state.

kubernetes.io

이는 백분율 값 설정시 서비스가 너무 적은 리소스를 할당받아 제대로 서빙되지 못할 것을 우려한 보수적인 정책인 것으로 보인다.

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

파드를 업데이트 한다는 것은, 파드에 배포된 컨테이너의 내용을 변경하여 새로운 버전을 배포한다는 것과 동일한 의미이다. https://secjong.tistory.com/57 에서 다루었듯, Deployment 를 이용해 파드를 업데이트하면, 이전 배포 버전의 Replicaset 는 삭제되지 않고 살아있게 된다. 디플로이먼트의 롤백은 실제로는 이전 버전의 레플리카셋으로 전환하는 것이다.

 

롤백을 하기 위해 어떤 버전으로 롤백을 하고자 하는지 정해야 하므로, 아래 커맨드를 이용해 디플로이먼트의 변경 이력을 확인한다. 리비전이 곧 버전이 된다.

$ kubectl rollout history deployment sample-deployment
REVISION  CHANGE-CAUSE
3         <none>
4         <none>
5         <none>

 

하지만, 디플로이먼트 revision 인 3, 4, 5 값만으로는 어떤 배포버전을 의미하는 것인지 알기 힘들다. 실제로 실무에서는 커맨드로 직접 롤백하지 않고 형상관리 툴과 연결된 CI/CD 도구를 이용해서 git commit message 등을 조회하여 어떤 revision 이 어떤 배포 건인지 확인할 수 있기 때문에 직접 확인하지 않지만, 공부를 위해 확인해보자.

 

아래 커맨드를 이용해 특정 리비전이 가진 파드 템플릿 정보를 알 수 있다.

$ kubectl rollout history deployment sample-deployment --revision 3
deployment.apps/sample-deployment with revision #3
Pod Template:
  Labels:	app=sample-app
	pod-template-hash=7457fb97b6
  Containers:
   nginx-container:
    Image:	nginx:1.17
    Port:	80/TCP
    Host Port:	0/TCP
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>
  Node-Selectors:	<none>
  Tolerations:	<none>

 

또한 아래 커맨드를 통해 replicaset 의 자세한 정보에서도 revision 을 확인할 수 있다.

$ kubectl describe replicasets.apps sample-deployment-7457fb97b6
Name:           sample-deployment-7457fb97b6
Namespace:      default
Selector:       app=sample-app,pod-template-hash=7457fb97b6
Labels:         app=sample-app
                pod-template-hash=7457fb97b6
Annotations:    deployment.kubernetes.io/desired-replicas: 3
                deployment.kubernetes.io/max-replicas: 4
                deployment.kubernetes.io/revision: 3
Controlled By:  Deployment/sample-deployment
Replicas:       0 current / 0 desired
Pods Status:    0 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=sample-app
           pod-template-hash=7457fb97b6
  Containers:
   nginx-container:
    Image:         nginx:1.17
...

 

Annotations 의 deployment.kubernetes.io/revision 에서 revision 번호를, Pod Template 에서 컨테이너 이미지 버전 등을 확인할 수 있다. 우리는 이렇게 조회된 nginx 1.17 버전을 원한다고 가정하고, revision 3 으로 롤백을 진행하고 결과를 확인해보자.

$ kubectl rollout undo deployment sample-deployment --to-revision 3
deployment.apps/sample-deployment rolled back

$ kubectl get deployments.apps sample-deployment -o wide
롤백된 버전 확인

$ kubectl rollout history deployment sample-deployment
deployment.apps/sample-deployment
REVISION  CHANGE-CAUSE
4         <none>
5         <none>
6         <none>

$ kubectl get rs -l app=sample-app
# 해당 리비전의 replicaset 이 사용중인지 확인
NAME                           DESIRED   CURRENT   READY   AGE
sample-deployment-5d6c4c4b76   0         0         0       48m
sample-deployment-5f6db9bfb9   0         0         0       49m # 이전 레플리카셋
sample-deployment-7457fb97b6   3         3         3       47m # 현재 레플리카셋

 

위에 언급했듯, 실제 서비스 환경에서는 rollout undo 를 사용하지 않고, 매니페스트 파일의 형상을 이전 버전으로 되돌린 후에 다시 apply 하는 방식을 더 많이 쓴다. 이 측면이 형상관리 이력을 남긴다는 측면에서 더 이롭고, 동일한 파드 정의로 되돌리는 것이므로 파드 템플릿 해시값이 동일하게 적용되기 때문에 해당 리비전의 레플리카셋이 재활용된다는 것은 완벽히 동일하기 때문이다.

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,

Deployment 를 사용한 컨테이너 운영은 kubernetes 에서 가장 권장하는 방법이다.

컨테이너를 기동하는 방법에는

1. pod 를 직접 사용하는 방법(단순 기동)

2. replicaset 으로 파드의 replica 갯수를 설정된 상태에 맞도록 유지하도록 유지하는 방법(자동복구 + scaling 가능)

3. deployment 로 n개의 replicaset 을 제어하면서 전체 파드의 갯수는 설정된 상태에 맞도록 유지하는 방법(rolling update 가능)

 

pod < replicaset < deployment 순서로 포함하는 구조이며, 따라서 상위에서는 하위의 기능을 사용할 수 있다.

 

1. 디플로이먼트 생성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.16
          ports:
            - containerPort: 80

 

위 내용으로 디플로이먼트를 생성한 후, 아래 커맨드로 디플로이먼트 및 디플로이먼트가 관리하는 레플리카셋, 그리고 그 레플리카셋이 관리하는 파드를 조회할 수 있다.

$ kubectl get deployments.apps sample-deployment
sample-deployment

$ kubectl get replicasets.apps -l app=sample-app
sample-deployment-79cd77b9d6

$ kubectl get pods -l app=sample-app
sample-deployment-79cd77b9d6-767b4
sample-deployment-79cd77b9d6-7j2zh
sample-deployment-79cd77b9d6-ksjpf

 

조회 결과를 보면, 디플로이먼트 > 레플리카셋 > 파드 순서로 네이밍 규칙을 이어받아 따르는 것을 알 수 있다.

  • deployment 명: {deployment 명}
    • ex) sample-deployment
  • replicaset 명: {deployment 명}-{10자리 랜덤hash 문자열}
    • ex) sample-deployment-79cd77b9d6
  • pod 명: {replicaset 명}-{5자리 랜덤hash 문자열}
    • ex) sample-deployment-79cd77b9d6-767b4

 

2. 디플로이먼트 업데이트

이제 deployment 매니페스트 파일의 컨테이너 이미지의 nginx 버전을 1.16 -> 1.17로 변경하고 apply 하면, 자동으로 새로운 replicaset 이 생성되며 rolling update 가 진행된다. 즉, 디플로이먼트가 알아서 rolling update 방식으로 무중단 배포를 진행해준다.

# 매니페스트 파일 수정 후
$ kubectl apply -f sample-deployment.yaml
$ kubectl get replicasets.apps -l app=sample-app
# rolling update 를 위한 새로운 replicaset 이 추가로 생성되었는지 확인

 

참고로, 다시 nginx 버전을 1.17 -> 1.16 으로 변경하여 rolling update 를 진행한 후 pod 명을 확인해보면, replicaset 과는 다르게 pod 는 재활용되지 않고 새로 생성된 것을 알 수 있다.(파드명이 다름)

  • replicaset 은 업데이트시 삭제되지 않고 유지되며, 다시 동일한 spec.template 으로 업데이트시 재사용된다.
    • 즉, spec.template 내용의 변경이 있으면 해당 내용으로 레플리카셋이 새로 생성된다.
    • 실제로 레플리카셋명의 hash 값은 spec.template 아래의 값으로부터 생성된다.(파드 템플릿 해시)
    • nginx 버전을 1.16 -> 1.17 -> 1.16 으로 변경한 경우에 1.16 버전 파드 템플릿 해시값이 동일할 것이므로, 레플리카셋이 새로 생성되지 않고 재사용되는 것이다.
  • pod 는 업데이트시 삭제되고 새롭게 생성된다.
# 최초 상태
$ kubectl get rs
sample-deployment-558978b4c5   3         3         3       2m40s
sample-deployment-79cd77b9d6   0         0         0       17m

$ kubectl get po
sample-deployment-558978b4c5-6d9gw   1/1     Running   0          3m56s
sample-deployment-558978b4c5-c7qjx   1/1     Running   0          3m57s
sample-deployment-558978b4c5-tffhz   1/1     Running   0          3m55s

# 첫번째 rolling update 후 => 새로운 replicaset 이 생성되고, 기존 replicaset 는 유지됨. 새로운 replicaset 하위로 pod 가 생성됨.
$ kubectl get rs
sample-deployment-558978b4c5   0         0         0       8m26s
sample-deployment-79cd77b9d6   3         3         3       23m

$ kubectl get po
sample-deployment-79cd77b9d6-56vlj   1/1     Running   0          4s
sample-deployment-79cd77b9d6-rznvh   1/1     Running   0          2s
sample-deployment-79cd77b9d6-tlk5f   1/1     Running   0          4s

# 두번째 rolling update 후 => replicaset 은 유지되나, 그 하위 pod 는 새로 생성됨
$ kubectl get rs
sample-deployment-558978b4c5   3         3         3       8m50s
sample-deployment-79cd77b9d6   0         0         0       24m

$ kubectl get po
sample-deployment-558978b4c5-c4dwd   1/1     Running   0          20s
sample-deployment-558978b4c5-hkb7p   1/1     Running   0          19s
sample-deployment-558978b4c5-tcrtx   1/1     Running   0          18s

 

블로그 이미지

망원동똑똑이

프로그래밍 지식을 자유롭게 모아두는 곳입니다.

,