본문 바로가기

Kubenetes/Kubernetes Controller

Deployment - 애플리케이션 업데이트

다른 Pod나 외부 클라이언트에게 Service를 제공하는 Pod 인스턴스 세트가 있다고 가정하면 아래와 같은 구성으로 보여질 수 있다.

쿠버네티스에서 실행 중인 애플리케이션의 기본적인 구성

 

위의 Pod 내의 애플리케이션을 새로운 버전으로 업데이트 하기 위해서는 다음과 같은 방법이 필요

ㅇ 기존의 모든 Pod를 먼저 삭제한 다음 새로운 포드를 시작

ㅇ 새로운 것을 시작하고, 일단 끝나면 오래된 것을 지움. 모든 포드를 추가한 다음 한번에 모든 기존 포드를 삭제하거나 순차적으로 추가/제거 해야 함.

 

위의 작업들을 쿠버네티스가 자동으로 업데이트 하는 방법이 디플로이먼트임.

 

[오래된 포드를 삭제하고 새로운 포드로 교체]

 

잠깐의 다운 타임을 허용할 수 있다면 포드의 세트를 업데이트하는 가장 간단한 방법

레플리케이션컨트롤러의 Pod 템플릿을 변경해 업데이트 및 이전 Pod 삭제

 

[한 번에 기존 버전에서 새로운 버전으로 전환]

 

포드는 대개 서비스와 연결되어 있다. 새 버전을 실행하는 포드를 가져오는 동안 초기 버전의 포드만 서비스와 연결 후 새 포드가 모두 올라오면 아래 그림과 같이 서비스의 라벨 셀렉터를 변경해 서비스를 새 포드로 전환 할 수 있다.

이를 BlueGreen Deployment 라고 함.

이전 포드에서 새로운 포드로 서비스 전환

 

[롤링 업데이트]

 

새 포드를 모두 가져오고 한번에 이전 포드를 삭제하는 대신 포드를 단계적으로 대체하는 롤링 업데이트 수행이 가능

두 개의 레플리케이션컨트롤러를 사용한 포드의 롤링 업데이트

 

ㅁ 레플리케이션컨트롤러를 통한 자동 롤링 업데이트

 

레플리케이션컨트롤러를 사용해 수동으로 롤링 업데이트를 수행하는 대신 kubectl을 통해 똑같은 작업을 수행할 수 있다.

하지만 지금은 더 이상 사용하지 않는 방식이다.

 

ㅁ 선언적으로 애플리케이션을 업데이트하기 위한 디플로이먼트 사용하기

디플로이먼트를 만들면 레플리카셋 리소스가 아래에 만들어짐. 

디플로이먼트를 사용할 때 실제 Pod는 디플로이먼트가 아니라 디플로이먼트의 레플리카셋에 의해 생성되고 관리된다.

디플로이먼트의 포드를 감시하는 레플리카셋은 디플로이먼트를 지원한다.

애플리케이션을 업데이트할 때 추가 레플리케이션컨트롤러가 필요하고 이전 레플리케이션컨트롤러와 잘 조화되게끔 컨트롤러를 조정해야 한다. 이를 위해 전체적으로 통제할 무언가가 필요하며 이 디플로이먼트 리소스가 그 역할을 담당한다.

 

ㅁ 디플로이먼트 생성

 

디플로이먼트는 라벨 셀렉터, 원하는 복제본 수, 및 포드 템플릿으로 구성

 

[디플로이먼트 메니페스트 생성]

 

kubia-deployment-v1.yaml

apiVersion: apps/v1beta1            # 디플로이먼트는 apps API 그룹의 v1beta1 버전으로 지정
kind: Deployment                    # kind를 ReplicationController에서 Deplyment로 변경
metadata
   name: kubia                      # 디플로이먼트의 이름에서 버전을 포함시킬 필요는 없다.
spec:
   replicas: 3
   template:
     metadata:
       name: kubia
       labels:
         app: kubia
     spec:
       containers:
       - image: luksa/kubia:v1
         name: node.js

 

[디플로이먼트 리소스 생성]

 

이 디플로이먼트를 만들기 전에 아직 실행 중인 레플리케이션컨트롤러와 포드는 삭제해야 한다. 그러나 현재는 kubia 서비스를 유지해야 한다. 다음과 같이 --all 스위치를 사용해 모든 레플리케이션컨트롤러를 삭제한다.

$ kubectl delete rc --all

$ kubectl create -f kubia-deployment-v1.yaml --record
deplyment "kubia" created

 

ㅁ 디플로이먼트 롤아웃 상태 출력

 

kubectl get deployment와 kubectl describe deployment 명령을 사용해 디플로이먼트의 세부 사항을 볼수 있다. 그러나 디플로이먼트를 위해서 만들어진 아래의 추가 명령도 사용이 가능하다.

 

$ kubectl rollout status deplyment kubia
deploymeht kubia successfully rolled out

 

세개의 복제본이 실행중인지 확인

 

$ kubectl get po
NAME                    READY   STATUS     RESTARTS    AGE
kubia-1506449474-otndk  1/1     Running    0           14s
kubia-1506449474-vmdk7  1/1     Running    0           14s
kubia-1506449474-xid7dc 1/1     Running    0           14s

 

ㅁ 디플로이먼트가 레플리카셋을 생성한 이후에 레플리카셋이 포드를 생성하는 방법

 

- 디플로이먼트에서 만든 세개의 포드에 이름 중간에 숫자 값이 추가로 포함됐다.

   이 숫자는 디플로이먼트 및 이 포드를 관리하는 레플리카셋의 포드 템플릿의 해시 값을 뜻함.

- 디플로이먼트는 포드를 직접 관리하지 않고 레플리카셋을 생성하고 레플리카셋이 관리하도록 위임한다.

 

$ kubectl get replicasets
NAME               DESIRED  CURENT   AGE
kubia-1506449474.  3        3        10s

 

- 레플리카셋의 이름도 해당 포드 템플릿의 해시 값을 포함

- 포드 템플릿의 각 버전마다 레플리카셋이 생성되어 디플로이먼트에서 항상 포드 템플릿의 주어진 버전에 동일한 레플리카셋을 사용할 수 있게 된다.

 

[서비스를 통한 포드 접근]

 

현재 실행중인 레플리카셋에 의해 생성된 세개의 복제본에 접근하기 위해 이전에 생성했던 서비스를 사용할 수 있다. 왜냐하면 서비스 라벨 셀렉터와 새로운 포드의 라벨을 일치시켰기 때문이다.

 

ㅁ 디플로이먼트 업데이트

 

[디플로이먼트 전략]

 

- 기본 전략은 RollingUpdate라고 부르는 롤링 업데이트 전략을 수행하는 것

  ㅇ 오래된 포드를 하나씩 제거하는 동시에 새로운 포드를 추가해 전체 업데이트 프로세스에 걸쳐 애프리케이션을 사용할 수 있도록 함

  ㅇ 요청을 처리할 수 있는 용량이 Drop 되지 않도록 보장

  ㅇ 원하는 복제본 개수가 포드의 수보다 크거나 작은 상한 및 하한을 구성할 수 있다.

  ㅇ 이 전략은 애플리케이션이 이전 버전과 새 버전을 동시에 처리할 수 있는 경우에만 사용해야 함.

 

- 대안으로 Recreate 전략이 있다.

  ㅇ Recreate 전략을 사용하면 새 포드를 만들기 전에 모든 이전 포드를 삭제할 수 있다. 

  ㅇ 애플리케이션이 여러 버전을 동시에 실행할 수 없으며

  ㅇ 새 버전을 시작하기 전에 이전 버전을 완전히 중지해야 하는 경우 이 전략을 사용

  ㅇ 이 전략에는 애플리케이션을 완전히 사용할 수 없게 되는 짧은 시간이 포함됨

 

[롤링 업데이트 속도 느리게 하기]

 

minReadySeconds 속성을 설정해 속도 조절

 

$ kubectl patch deployment kubia -a {"spec": {"minReadySeconds": 10}}'
"kubia" patched

 

[롤링 업데이트 트리거]

 

실제 롤아웃을 트리거하기 위해 단일 포드 컨테이너에서 사용하고 있는 이미지를 luksa/kubia:v1에서 luksa/kubia:v2로 변경

이를 위해 디플로이먼트 객체의 전체 YAML을 편집하거나 patch 명령을 사용해 이미지를 변경하는 대신에 kubectl set image 명령을 사용하면 컨테이너를 포함하고 있는 모든 리소스의 이미지를 변경할 수 있다. (레플리케이션컨트롤러, 레플리카셋, 디플로이먼트 등)

 

$ kubectl set image deployment kubia nodejs=luksa/kubia:v2

deployment "kubia" image updated

 

이 명령을 실행하면 kubia 디플로이먼트의 포드 템플릿이 업데이트돼 nodejs 컨테이너에서 사용하고 있는 이미지가 v1에서 luksa/kubia:v2로 변경된다.

새 이미지를 가리키도록 디플로이먼트의 포드 템플릿 업데이트하기

 

ㅁ 디플로이먼트 수행 결과

롤링 업데이트 시작과 종료 시점의 디플로이먼트

 

레플리카셋의 리스트를 보면 새로 만들어진 레플리카셋 옆에 이전 레플리카셋을 여전히 볼 수 있다.

$ kubectl get rs
NAME              DESIRED   CURRENT   AGE
kubia-1506449474  0         0         24m
kubia-1581357123  3         3         23s

위와 같이 디플로이먼트로 구성할 때는 레플리카셋은 전혀 신경 쓸 필요가 없다.

 

ㅁ 디플로이먼트와 그 밖의 리소스를 수정하는 방법

방법 설명
kubectl edit 기본 편집기에서 객체의 매니페스트 파일을 연다. 변경 한 후, 파일을 저장하고 편집기를 종료하면 오브젝트가 갱신된다.
예: kubectl edit deployment kubia
kubectl patch 객체의 개별 속성을 수정한다.
예: kubectl patch deployment kubia -p '{"spec":
{"template":{"spec":{"containers":[{"name":"nodejs","image":"luksa/kubia:v2"}]}}}}'
kubectl apply 전체 YAML 또는 JSON 파일의 속성 값을 적용해 객체를 수정한다. YAML/JSON에 지정된 객체가 아직 존재하지 않으면 생성된다. 이 파일에는 리소스 전체 정의가 포함돼야 한다.
(kubectl 패치의 경우처럼 업데이트하려는 필드만 포함할 수 없다.).
예: kubectl apply -f kubia-deployment-v2.yaml
kubectl replace 객체를 YAML/JSON 파일의 새 객체로 바꾼다. 적용 명령과 달리 명령은 객체가 존재해야 한다. 그렇지 않으면 오류를 출력한다.
예: kubectl replace -f kubia-depolyment-v2.yaml
kubectl set image 포드, 레플리케이션컨트롤러의 템플릿, 디플로이먼트, 데몬셋, 잡 또는 레플리카셋에 정의도니 컨테이너 이미지를 변경한다.
예: kubectl image deployment kubia nodejs = luksa/kubia:v2

 

ㅁ 디플로이먼트 롤백

 

[애플리케이션 버전 3 생성]

 

버전 3에서 애플리케이션이 처음의 네개의 요청만 제대로 처리하도록 하는 버그를 소개. 5번째 요청 이후의 모든 요청은 내부 서버 오류(HTTP 상태 코드 500)를 반환하는 새 코드 작성

애플리케이션 버전 3(손상된 버전) v3/app.js

const http = require('http');
const os = require('os');

var requestCount = 0;

console.log("Kubia server starting...");

var handler = function(request, response) {
   console.log("Received request from " +request.connection.remoteAddress);
   if (++requestCount >=5) {
     response.writeHead(500);
     response.end("Some internal error has occured! This is pod " +
       os.hostname() + "\n");
     return;
   }
   response.writeHead(200);
   response.end("This is v3 running in pod " + os.hostname() + "\n");
};

var www = http.createServer(handler);
www.lsiten(8080);

 

[버전 3 배포 후 롤아웃 진행 상황 확인]

 

$ kubedtl set image deployment kubia nodejs=luksa/kubia:v3

deployment "kubia" iamge update

 

이후 아래와 같이 kubectl rollout. status 로 롤아웃 진행 상황을 확인 할 수 있다.

 

$ kubectl rollout status deployment kubia
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for rollout to finish: 1 old replicas are pending termination...
deployment "kubia" successfully rolled out

 

[롤아웃 되돌리기]

 

$ kubectl rollout undo deployment kubia
deployment "kubia" rolled back

 

이렇게 하면 디플로이먼트를 이전 버전으로 롤백할 수 있다.

 

[디플로이먼트의 롤아웃 히스토리 보여주기]

 

$ kubectl rollout history deployment kubia
deployment "kubia":
REVISION  CHANGE-CAUSE
2         kubectl set image deployment kubia nodejs=luksa/kubia:v2
3         kubectl set image deployment kubia nodejs=luksa/kubia:v3

 

[특정 디플로이먼트 리비전으로 롤백하기]

 

$ kubectl rollout undo deployment kubia --to-revision=1

 

디플로이먼트의 레플리카셋은 리비전 히스토리의 역할을 수행한다.

이전 레플리카셋이 레플리카셋 목록을 복잡하게 만드는 것은 이상적이지 않아 리비전 히스토리의 길이는 디플로이먼트 리소스의 revisionHistoryLimit 속성에의해 제한된다.

기본적으로는 2로 설정되어 일반적으로 현재 및 이전 버전만 기록에 표시된다.

 

ㅁ 롤아웃 속도 통제

 

[롤링 업데이트 전략의 maxSurge와 maxUnavaiable 속성 소개]

 

두 가지 속성은 배포의 롤링 업데이트 중에 한 번에 대체되는 포드의 수에 영향을 준다.

이 속성은 maxSurge 및 maxUavailable 이며 다음 예제와 같이 디플로이먼트 전략 속성의 rollingUpdate 하위 속성의 일부로 설정 가능

 

rollingUpdate 전략을 위한 파라미터 지정하기

spec:
  stratege:
    rollingUpdate:
      maxSurge: 1
      maxUavailable: 0
    type: RollingUpdate

 

속성 설명
maxSurge 배포에 구성된 원하는 복제본 수 위에 존재하도록 허용되는 포드 인스턴스 수를 결정한다.
기본값은 25%이므로 원하는 수보다 최대 25% 더 많은 포드 인스턴스가 있을 수 있다.
원하는 복제본 수가 4로 설정되면 업데이트 중에 동시에 실행되는 5개 이상의 포드 인스턴스가 없다.
백분율을 절대 숫자로 변환할 때 숫자는 반올림된다.
백분율 대신 값은 절대 값일 수도 있다. (예를 들어 하나 또는 두 개의 추가 포드를 허용할 수 있다.
maxUavailable 업데이트 중에 원하는 복제본 수에 비례하여 사용할 수 없는 포드 인스턴스 수를 결정
또한 기본 값은 25%로 설정되므로 사용 가능한 포드 인스턴스 수가 원하는 복제본 수의 75% 미만으로 떨어지지 않아야 한다.
여기에서 백분율을 절대 숫자로 변환할 때 숫자는 내림된다.
원하는 복제본 수가 4로 설정되고 백분율이 25%이면 하나의 포드만 사용할 수 없다. 
전체 롤아웃 중에 요청을 처리할 수 있는 포드 인스턴스가 항상 3개 이상 있어야 한다.
maxSurge와 마찬가지로 백분율 대신 절대값을 지정할 수도 있다.

 

3개의 복제본 및 기본 maxSurge 및 maxUnavailable을 사용한 디플로이먼트의 롤링 업데이트

 

[maxUnavilable 속성]

디플로이먼트의 extensions/v1beta1 버전은 다른 기본 값을 사용한다.

maxSurge 및 maxunavailable을 모두 25% 대신 1로 설정한다.

세개의 복제본의 경우 maxSurge는 이전과 동일하지만 maxUnavailable은 다르다( 0대신 1)

 

maxSurge=1, maxUnavailble=1과 함께 디플로이먼트의 로링 업데이트

 

[롤아웃 일시 중지하기]

 

v4 이미지를 새로 만들어 롤아웃을 한다

$ kubectl set image deployment kubia nodejs=luksa/kubia:v4

deployment "kubia" image updated

 

일부 배포가 되는것을 확인 후 최종 검증을 위해 일시적으로 롤아웃을 중단 한다.

 

$kubectl rollout pause deployment kubia

deployment "kubia" paused

 

[롤아웃 재개]

 

새로 배포된 이미지가 정상적인 것을 확인 했으면 다시 롤 아웃을 재개 한다.

$ kubectl rollout resume deployment kubia

 

[새로운 버전(v3)이 완전히 롤아웃된는 것을 방지하기 위한 레디니스 프로브(Readiness Probe) 정의]

 

레디니스 프로브를 통한 디플로이먼트: kubia-deployment-v3-with-readinesscheck.yaml

apiVersion: apps/v1beta1
kind: deployment
metadata:
   name: kubia
spec:
   replicas: 3
   minReadySeconds: 10        # minReadySeconds를 10에 맞춤
   strategy:
      rollingUpdate:
        maxSurge: 1
        maxUnavailable: 0     # maxUnavailable을 0으로 설정하면 디플로이먼트가 포드를 하나씩 대체한다.
      type: RolingUpdate
   template:
      metadata:
        name: kubia
        labels:
          app: kubia
      spec:
        containers:
        - image: luksa/kubia:v3
 name: nodejs
        readinessProbe:
          periodSeconds: 1   # 매초마다 실행될 readiness probe를 정의하고 있음
          httpGet:           # readiness probe는 컨테이너에 HTTP GET 요청을 수행할 것이다.
            path: /
            port: 8080

 

[kubectl apply를 통한 디플로이먼트 업데이트]

 

$ kubectl apply -f kubia-deployment-v3-with-readinesscheck.yaml

deployment "kubia" configured

 

apply 명령을 실행하면 업데이트 프로세스를 시작하고, 이어서 rollout status 명령을 다시 수행할 수 있게 된다.

 

$ kubectl rollout status deployment kubia

Waitting for rollout to finish: 1 out of 3 new replicas have been updated...

 

만약 정상적인 이미지가 아니라면 레디네스 프로브 때문에 배포 진행 도중 신규 이미지가 정상적으로 보이지 않는다.

 

 

[롤아웃 데드라인 설정]

 

기본적으로 롤아웃이 10분 안에 진행되지 않으면 실패한 것으로 간주됨

kubectl describe deploy 명령을 사용하면 다음 예제와 같이 ProgressDeadlineExceeded 조건이 표시

 

kubectl describe를 사용한 디플로이먼트 조건 확인

 

kubectl describe deploy kubia

Name:                 Kubia

...

Conditions:

 Type              Status          Reason

-----              --------       ---------

Available        True             MinimumReplicasAvailable

Progressing    False            ProgressDeadlineExceeded

 

디플로이먼트가 실패한 것으로 간주되는 시간은 디플로이먼트 사양의 progressDeadlineSeconds 속성을 통해 구성 가능

 

[잘못된 롤아웃 중지하기]

 

$ kubectl rollout undo deployment kubia

deployment "kubia" rolled back

'Kubenetes > Kubernetes Controller' 카테고리의 다른 글

StatefulSet  (0) 2021.02.13
잡 리소스 및 스케줄링  (0) 2021.02.11
레플리카셋(Replicaset)  (0) 2021.02.11
레플리케이션 컨트롤러 (Replication Controller)  (0) 2021.02.11