[Kubernetes] 무중단 업데이트 방법

Dev·2022년 12월 29일
0

1. Application Update

  • 클라이언트가 파드에 서비스를 통해 접근하며, 파드들은 ReplicaSet에 의해 관리된다.
  • 파드에서 실행중인 애플리케이션의 버전을 바꾸고 싶을 때 기존 파드를 모두 삭제한 다음 새 파드를 시작하는 방식이 있다. 이는 간단해보이지만, 잠시동안 애플리케이션이 중단되는 문제가 있다.
  • 혹은 새로운 파드를 모두 추가한 다음 한꺼번에 기존 파드를 삭제하는 방식도 있다. 리소스가 2배 더 소요되는 문제가 있다.
  • 순차적으로 새로운 파드를 추가하고 기존 파드를 점진적으로 제거하는 방식도 있다. 이는 동시에 두가지 버전을 실행하기 때문에, 새로운 버전이 이전 버전을 손상시키는 케이스에선 사용하면 안된다.

2. 업데이트 종류

[1] 오래된 파드를 삭제하고 새 파드로 교체하는 '수동' 방식

  • v1 pod set을 관리하는 'Replication Controller'가 있는 경우, v2를 참조하도록 pod template을 수정한 다음 이전 파드 인스턴스를(v1) 삭제해 쉽게 교체할 수 있다. 자연스럽게 RC는 v2를 참조하도록 변경했기 때문에 v2의 파드들을 생성한다.
  • 이 방법은 이전 pod 가 삭제되고 새 pod 가 시작되는 동안 짧은 시간의 downtime 을 허용할 수 있어야 한다.

[2] Blue Green 배포

  • 새 버전을 실행하는 파드를 불러오는 동안 서비스는 파드의 이전 버전에 연결된다. 새 파드가 모두 실행되면 서비스의 레이블 셀렉터를 변경하고, 서비스를 새 파드로 전화한다. 즉, 한 번에 이전 버전에서 새 버전으로 전환하는 방식이다.
  • downtime 이 발생하지 않고 한번에 여러 version 의 application 이 실행되는 것을 지원하는 경우에 사용한다. 단, 잠시동안 두 배의 파드가 실행되므로 더 많은 리소스가 필요하다.

[3] Rolling 배포

  • 이전 파드를 한번에 삭제하는 방법 대신 파드를 단계적으로 교체하는 롤링 업데이트를 수행할 수도 있다. 두 개의 레플리카셋을 이용해서 상태를 보면서 점진적으로 수행한다.
  • downtime 이 발생하지 않고 한번에 여러 version 의 application 이 실행되는 것을 지원하는 경우에 사용한다.

쿠버네티스는 무중단 배포를 위해 'Deployment Resource'를 제공한다. (1) Label/ ReplicaSet을 관리할 필요가 없으며, (2)수동이 아닌 자동으로, (3) '명령형'이 '선언형'으로 처리할 수 있다.

3. Deployment Resource

  • Deployment는 애플리케이션의 무중단 배포를 지원하는 리소스다.
  • Deployment를 생성하면 ReplicaSet 리소스가 그 아래 생성된다.
  • 무중단 배포를 위해 추가 ReplicaSet 및 Label을 관리해야하는데, 이를 Deployment가 알아서 처리한다. 우리는 '선언형' 형태로 Deployment 리소스를 정의하기만 하면 된다.

[1] Deployment 생성

  • Deployment yaml파일은 레이블 셀렉터, 레플리카 수, 파드 템플릿으로 구성된다. 이때 업데이트 방식도 정의할 수 있다.
  • 디플로이먼트는 파드 템플릿의 각 버전마다 하나씩 여러 개의 레플리카셋을 만든다.
  • 파드 템플릿의 해시 값을 사용하면 디플로이먼트에서 지정된 버전의 파드 템플릿에 관해 항상 동일한 레플리카셋을 사용할 수 있다. 업데이트를 수행하더라도 ReplicaSet은 여전히 남아있다. 따라서 롤백시 RS를 재활용할 수 있다. RS에 revision 번호(버전)를 지정해 특정 버전으로 쉽게 롤백할 수 있다.

[2] Deployment 업데이트

  • 디플로이먼트 리소스에 정의된 파드 템플릿을 수정하기만 하면 쿠버네티스가 실제 시스템 상태를 리소스에 정의된 상태로 만드는 데 필요한 모든 단계를 수행한다. ex) rc를 추가로 생성하고 업데이트 등
  • 기본적으로 RollingUpdate 전략을 사용한다. 이 방식은 이전 버전과 새 버전을 동시에 실행할 수 있는 경우에만 사용해야 한다.
  • 대안으로 존재하는 Recreate 전략은 한 번에 기존 모든 파드를 삭제한 뒤 새로운 파드를 만드는 전략이다.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia # 이전에는 RC가 특정 버전의 파드를 관리했기 떄문에 kubia-v1으로 했으나, Deployment 자체가 여러 버전을 실행할 수 있기 때문에 버전을 참조하진 않는다.
spec:
  replicas: 3
  template: # pod template
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v2
        name: nodejs

[3] 롤링 업데이트 속도 제어

  • 롤링 업데이트에서 두 가지 추가 속성을 통해 새 파드를 만들고 기존 파드를 삭제하는 과정에서 속도를 제어할 수 있다. 'maxSurge', 'maxUnavailable' 두 가지가 있는데, 이 속성들을 통해 한 번에 몇개의 파드를 교체하지를 결정된다.
  • maxSurge : 의도하는 replica 수 보다 얼마나 많은 pod instance 를 허용하는지 결정한다.
  • maxUnavailable : update 중 의도하는 replica 수를 기준으로 사용할 수 없는 pod instance 수를 결정한다

의도하는 replica 수가 3이고, 이러한 모든 속성이 default(25%) 라면 maxSurge 는 4까지 허용되고, maxUnavailable 은 사용할 수 없는 파드를 허용하지 않는다

위 예제에서 maxUnavailable만 1로 변해보면 어떻게 동작할까? maxUnavailable=1로 인해서 2개까지만 가용한 상태면 되기 때문에 결과적으로는 롤링 업데이트가 더 빠르게 수행될수 있다.

[4] minReadySeconds 속성

  • minReadySeconds는 파드를 사용 가능한 것으로 취급하기 전에 새로 만든 파드를 준비할 시간을 지정하는 속성이다.
  • 적절하게 구성된 레디니스 프로브와 적절한 minReadySeconds 설정으로 쿠버네티스는 버그가 있는 버전을 배포하지 못하게 할 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  minReadySeconds: 10           # minReadySeconds를 10초로 설정
  selector:
    matchLabels:
      app: kubia
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0             # 디플로이먼트가 파드를 하나씩만 교체하도록 0으로 설정
    type: RollingUpdate
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v3
        name: nodejs
        readinessProbe:               
          periodSeconds: 1           # 매 초마다 레디니스 프로브 수행
          httpGet:
            path: /
            port: 8080
  • 사용 가능한 것으로 간주되려면 10초 이상 준비돼 있어야 하기 때문에(초기에 이 값을 매우 늘려, 트래픽을 수용 가능한지 체크하기도 한다.) 해당 파드가 사용 가능할 때까지 새 파드를 만들지 않는다. 여기서 maxUnavailable 속성이 0으로 설정되었기 때문에 원래 파드도 제거되지 않는다.
  • 만약 위 상황에서 minReadySeconds를 짧게 설정했더라면 레디니스 프로브의 첫 번째 호출이 성공한 후 즉시 새 파드가 사용 가능한것으로 간주해버릴 수도 있다.(트래픽, 오류 확인 없이) 그러면 잘못된 버전으로 롤아웃이 일어나기 때문에 이 값을 적절하게 잘 설정해야 한다.
  • 만약 위 상황에서 minReadySeconds를 짧게 설정했더라면 레디니스 프로브의 결과값이 지속해서 실패할 수 있다.
profile
성장하는 개발자가 되고싶어요

0개의 댓글