[k8s] Controller - Deployment와 Rolling Update

2022. 9. 11. 17:54[ DevOps ]/[ k8s ]

 

Deployment

- Controller인 ReplicaSet을 제어해주는 부모 역할을 한다.

- Deployment는 Rolling Update를 목적으로 만들어졌다.

- Deployment를 만들면 Deployment가 ReplicaSet을 만든다. 이때 Deployment는 실행시킬 Pod의 버전과 replicas를 ReplicaSet에게 전달한다. 그 후엔 ReplicaSet이 전달받은 정보를 기반으로 Pod를 생성하고 Pod 수를 보장하게 된다.

- 즉, Deployment가 ReplicaSet을 컨트롤하고 ReplicaSet이 Pod를 컨트롤하는 구조이다.

- 정리하자면, Deployment는 ReplicaSet Controller를 관리해서 Pod 수를 보장하고, 추가적으로 Rolling update를 지원하여 무중단으로 버전 업데이트를 지원한다.

- ReplicaSet과 Deployment의 차이는 Rolling Update의 사용 여부에 따라 결정하면 된다. 두 API의 definition file(yaml)도 kind 필드를 제외하고는 대부분이 동일하다. 즉, Deployment만으로도 ReplicaSet을 운영할 수 있다.

 

 

cf. Rolling Update란?

- 롤링 업데이트는 Pod를 하나씩 점진적으로 업데이트하여 새로운 버전으로 만들어서 Deployment 업데이트가 서비스 중단 없이 이루어질 수 있도록 해준다.

- 예시: Deployment를 이용해서 ReplicaSet에 nginx1.14를 실행시키면 서비스 중단 없이 pod(nginx)의 버전을 업데이트시킬 수 있게 한다.

- Deployment는 이러한 Rolling Update를 목적으로 만들어진 API 리소스이다. Pod의 버전을 서비스 중단 없이 업데이트(Rolling Update)하고 싶다면 Deployment로 요청하면 된다.

- 추가적으로, Rolling Back은 이전 버전으로 되돌아가는 것을 의미한다.

 

 

 

https://www.oreilly.com/library/view/cloud-native-devops/9781492040750/ch04.html

 

 

 


 

Rolling Update 과정 

롤링 업데이트가 시작되면 Deployment는 새로운 ReplicaSet 컨트롤러를 생성하고 새로운 버전의 컨테이너의 replicas를 1부터 시작한다. 그리고 해당 Pod(컨테이너)가 Running 상태가 되면 기존 ReplicaSet의 replicas를 1 줄인다. 이때 가장 오래된 Pod 하나가 삭제된다. 그리고 새로운 ReplicaSet의 replicas를 2로 늘리고 위 과정을 반복한다.

 

1) Deploy를 처음 실행했을 때 상태

 

2) 컨테이너를 1:15 버전으로 실행 (kubectl set image deployment)

 

 

 

- 새로운 Pod가 실행되면 기존 버전의 Pod를 삭제

 

 

3) 최종 

 

 

위와 같이 Rolling Update는 Pod를 '점진적으로' 업데이트하여 '서비스 중단 없이' Pod가 업데이트될 수 있도록 한다.

 


 

실습

- deploy-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      name: nginx-pod
      labels:
        app: webui
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.14

출처: https://github.com/237summit/Getting-Start-Kubernetes/blob/main/6/deploy-nginx.yaml

 

 

deployment 실행 후 확인

- Deploy, RS, Pod의 이름을 보면 알 수 있듯이, 부모의 이름이 앞에 붙는 형식이다. 따라서 Pod의 부모는 RS이고, RS의 부모는 Deploy임을 확인할 수 있다.

 

 

RS 삭제 후 확인

- RS를  삭제해도 Deployment에 의해 다시 생성되었음을 확인할 수 있다.

- Deploy가 RS를 컨트롤하는 API이기 때문에 deploy를 삭제해야 RS, Pod가 삭제된다.

 

 

Deployment로 Rolling Update/RollBack 하기

- deployment에서 Rolling Update를 지원하기 위해, kubectl set image 커맨드를 지원한다.

 

1) rolling update 사용법

$ kubectl set image deployment <deploy_name> <container_name>=<new_version_image> --record

 

* Pod는 2개 이상의 컨테이너를 포함할 수 있기 때문에 container_name에서 업데이트할 컨테이너 이름을 명시해 줘야 한다. 

* --record 옵션을 설정하지 않으면 history를 남기지 않기 때문에 롤백할 수 없다.

 

 

cf. kubectl set 커맨드

- kubectl set 커맨드는 애플리케이션 리소스를 설정하는 커맨드로 env, image, resources, selector, serviceaccount, subject를 업데이트하거나 변경할 수 있다.

 

 

 

- deployment-exam1.yaml 파일 작성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deploy
spec:
  selector:
    matchLabels:
      app: webui
  replicas: 3
  template:
    metadata:
      labels:
        app: webui
    spec:
      containers:
      - image: nginx:1.14
        name: web
        ports:
        - containerPort: 80

출처: https://github.com/237summit/Getting-Start-Kubernetes/blob/main/6/deployment-exam1.yaml

 

 

 

nginx1.14 실행 후 1.15로 롤링 업데이트

* --record 옵션을 붙여야 현재 버전에 대한 히스토리를 남긴다. 즉, --record를 사용하지 않으면 rollback을 할 수 없다.

 

 

버전 확인 

- deploymenet에 의해 실행 중인 pod 중 하나를 kubectl describe 커맨드로 확인해본 결과 1.15로 롤링 업데이트되었음을 확인할 수 있다.

- 같은 방식으로 1.17 버전까지 올린 후 아래와 같이 리비전을 확인해본다.

 

[revision history 확인]

가장 마지막 revision이 현재의 deployment이다. revision 개수는 제한되어 있는데 default 값은 10이며 deployment yaml 파일에서 revisionHistoryLimit 필드를 사용하여 수정할 수 있다. revision 1번은 처음 deployment를 생성했을 때의 revision인데, 이때 --record를 설정하지 않았다면 해당 revision 1번은 <node>으로 보이게 된다. 이 경우 롤백을 할 수 없다.

 

 

2) rollback 사용법

# 1. revision history 확인
$ kubectl rollout history deployment <deploy_name>  

# 2-1. 실제 rollback 진행 (가장 최신 revision)
$ kubectl rollout undo deploy <deploy_name>

# 2-2. 실제 rollback 진행 (revision 번호 지정)
$ kubectl rollout undo deploy <deploy_name> --to-revision=<NUMBER>

 

- kubectl rollout 커맨드

ubuntu@master:~/k8s-practice$ kubectl rollout --help

Available Commands:
  history     View rollout history
  pause       Mark the provided resource as paused
  restart     Restart a resource // 방금 시작한 업데이트 재시작
  resume      Resume a paused resource // 일시 중지된 업데이트 재시작
  status      Show the status of the rollout
  undo        Undo a previous rollout // 업데이트 롤백

rollout 커맨드는 위와 같이 다양한 형태로 제공된다. 가장 아래 undo를 사용하면 Rolling Update에 대한 롤백을 진행할 수 있다.

 

 

- rollout undo 커맨드를 사용해서 이전 버전으로 롤백했더니 revision 순서에 가장 최신으로 변경되었음을 확인할 수 있다. 

- undo 커맨드에서 --to-revision을 명시하지 않으면 가장 이전의 버전으로 롤백된다.

- 3번 revision으로 롤백했기 때문에 history 상에서는 3번 revision이 보이지 않고 해당 revision이 5번(현재 revision)으로 변경되었다. 만약 위 상태에서 최신 버전으로 롤백하면 revision은 1, 2, 5, 6이 될 것이고 기존 4번 revision이 6번 revision이 된다.

- kubectl delete로 deploy를 삭제하면 rollout history를 확인할 수 없으니 주의해야 한다.

 

 

 

cf. deployment yaml 파일 추가 필드

- deployment-exam2.yaml 파일 작성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx
  annotations:
    kubernetes.io/change-cause: version 1.15
spec:
  progressDeadlineSeconds: 600
  revisionHistoryLimit: 10
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      labels:
        app: webui
    spec:
      containers:
      - name: web
        image: nginx:1.15
        ports:
        - containerPort: 80

출처: https://github.com/237summit/Getting-Start-Kubernetes/blob/main/6/deployment-exam2.yaml

 

 

1) revisionHistoryLimit

- 최대로 남길 revision 개수에 대한 설정이다.

 

2) progressDeadlineSeconds (default 600)

- 업데이트를 위한 timeout이다. 설정한 시간 내에 업데이트하지 못하면 업데이트를 취소한다. default 값은 600이다.(10분)

 

3) maxSurge (default 25%)

- 현재 설정된 replicas 개수의 maxSurge(%) 개수만큼 업데이트를 동시에 진행한다. 한 번에 많이 업데이트하면 업데이트가 빨라질 것이다. 즉, 얼마나 빠르게 업데이트할 것인지를 설정하는 것이다.

- 예시: replicas가 3이고 maxSurge가 25%라고 가정하면 3의 25%는 0.75(반올림하면 1)이다. 즉, Rolling Update시 1개씩 점진적으로 업데이트하도록 설정한 것이다. 반대로 maxSurge가 50%이면 3의 50%는 1.5(반올림하면 2)이다. 따라서 이 경우에는 2개씩 동시에 Rolling Update를 진행한다.

 

4) maxUnavailable (default 25%)

- 동시에 Terminating 하는 개수를 지정한다.

 

5) type

- RollingUpdate는 롤링 업데이트를 적용하겠다는 의미이며, 이 외 Recreate type이 있는데 이는 기존 Pod를 먼저 삭제하고 새로운 Pod를 실행시키는 전략이다.

 

6) annotations

annotations를 활용해서 쿠버네티스의 동작 방식을 컨트롤할 수 있다. 그중 하나가 annotations필드에 change-cause를 활용하는 것인데, 위와 같이 change-cause에 버전을 명시하고 추후 Rolling Update가 필요한 시점에 위 파일의 change-cause의 버전 부분을 변경하면 커맨드 없이도 자동으로 Rolling Update가 진행된다. 즉, yaml 파일을 기반으로 Rolling Update를 진행할 수 있다.

 

 

 

cf. 롤링 업데이터 일시정지 또는 재시작 활용

'kubectl rollout < pause / resume > deployment <deploy_name>' 커맨드로 deployment의 롤링 업데이트를 일시 정지하거나 재시작할 수 있다. 이는 새로운 버전의 pod를 일부 업데이트한 후 모니터링하여 정상적으로 수행 중인지를 확인하는 데 사용된다. 모니터링 결과 새로운 버전에 문제가 없다면 롤링 업데이트를 resume 하여 재시작한다.

 

 


 

annotations의 change-cause 기반으로 Rolling Update 실습

위 deployment-exam2.yaml 파일의 annotation을 기반으로 Rolling Update를 실습한다.

 

1) deployment 실행 후 deployment 파일 수정

 

2) deployment 파일 수정: 버전 변경

- 위와 같이 annotations의 change-cause 부분과 template, containers의 image 버전을 모두 변경해야 한다.

 

 

3) 변경사항 적용

 

4) 변경 정보 확인

- kubectl describe pod 커맨드로 실행 중인 pod 중 하나를 확인한 결과 버전업이 정상적으로 반영되었음을 확인할 수 있다.

 

- history에도 정상적으로 반영되어 있다.

 

위와 같이 annotation을 기반으로 Rolling Update 하는 방식을 활용하면 최신 버전의 정보를 yaml 파일로 남겨둘 수 있기 때문에 관리에 더욱 용이하다.

 

 

 

 

 

 

 

Reference

- 따배쿠, https://youtu.be/L5LDBWrP6QU

- k8s docs 롤링 업데이트, https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/update/update-intro/

- update type, https://www.kubermatic.com/blog/introduction-to-deployment-strategies/