블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

쿠버네티스 패키지 매니저 HELM

#2-2. Chart 버전과 릴리즈

조대협 (http://bcho.tistory.com)

업그레이드와 롤백

Chart로 의해서 설치된 리소스들을 쿠버네티스에서 릴리즈라고 한다.

예를 들어 같은 차트로 MySQL을 쿠버네티스 클러스터 내에 여러번 설치 할 수 있다.  각각 설치된 MySQL들을 릴리즈라고 하고, 릴리즈에 설정이 변경된 경우에, 차트를 수정해서 변경을 반영할 수 있다. 변경이 반영될때 마다 새로운 버전이 생성된다.


처음 helm install로 설치를 할때 --name 옵션으로 저장한 설치 이름이 릴리즈 명이 되고, 이 릴리즈를 업데이트 하고 싶으면 helm upgrade {Helm 릴리즈명} {차트 디렉토리} 를 실행하면, 해당 릴리즈를 업데이트하고, 새로운 버전을 생성한다.

앞의 예제의 values.yaml 에서 replicaCount: 3 를 변경한 후, upgrade를 해보자

%helm upgrade helloworld ./helloworld/

명령을 실행하면 다음과 같이 기존 배포가 업데이트 된다.


Release "helloworld" has been upgraded. Happy Helming!

LAST DEPLOYED: Sun Jun  9 20:58:41 2019

NAMESPACE: default

STATUS: DEPLOYED


RESOURCES:

==> v1/Service

NAME            AGE

helloworld-svc  2d


==> v1beta2/Deployment

helloworld-deployment  2d


==> v1/Pod(related)


NAME                                    READY STATUS RESTARTS AGE

helloworld-deployment-696fc568f9-2dkpm  0/1 ContainerCreating 0 0s

helloworld-deployment-696fc568f9-fqqg8  1/1 Running 0 2d

helloworld-deployment-696fc568f9-r8qct  1/1 Running 0 2d


그리고 위와 같이 Deployment pod가 3개로 늘어난것을 확인할 수 있다.

업그레이드 한후 버전을 확인하려면  helm history {릴리즈 이름} 을 사용하면 되는데,

% helm history helloworld

를 실행하면 아래와 같이 2번 버전이 새로 생긴것을 확인할 수 있다.


REVISION UPDATED                  STATUS     CHART            DESCRIPTION     

1        Fri Jun  7 23:24:34 2019 SUPERSEDED helloworld-0.1.0 Install complete

2        Sun Jun  9 20:58:41 2019 DEPLOYED   helloworld-0.1.0 Upgrade complete


만약 예전 버전으로 돌리고 싶으면 rollback 명령을 사용하면 되는데, helm rollback {릴리즈 이름} {릴리즈 버전} 으로 실행하면 된다. helm rollback helloworld 1 는 helloworld 릴리즈를 1 버전으로 롤백 하는 명령어 이다.  명령어를 실행해보면 다음과 같이 롤백이 완료되는 것을 확인할 수 있고,

% helm rollback helloworld 1

Rollback was a success! Happy Helming!


helm history로 해당 릴리즈의 버전을 확인해보면, 3번 버전에서 1번으로 롤백을 한것을 확인할 수 있다.

%helm history helloworld

REVISION UPDATED                  STATUS     CHART            DESCRIPTION     

1        Fri Jun  7 18:24:34 2019 SUPERSEDED helloworld-0.1.0 Install complete

2        Sun Jun  9 20:58:41 2019 SUPERSEDED helloworld-0.1.0 Upgrade complete

3        Sun Jun  9 21:43:48 2019 DEPLOYED   helloworld-0.1.0 Rollback to 1


릴리즈

앞에서도 설명했듯이 차트 하나로 같은 클러스터에 같은 애플리케이션을 여러개를 설치할 수 있다. MySQL이나 Redis 메모리 서버들은 애플리케이션이 아니기 때문에  같은 이미지로 여러개의 릴리즈를 설치할 수 있다.

그런데 앞의 스크립트로 helloworld 차트를 한번 더 설치하면 에러가 날것이다. 이유는 차트에 정의된 Service와 Deployment 리소스의 이름이 동일하기 때문이다.

templates/helloworld.yaml 파일에서 Deployment 이름 정의 부분을 보면, 이름을 {{.Value.name}}을 사용하도록 하였다.


apiVersion: apps/v1beta2

kind: Deployment

metadata:

 name: {{ .Values.name }}-deployment

:


그래서 values.yaml에서 name을 변경하지 않는 이상, Deployment는 같은 이름을 가지게 된다.

이 문제를 해결하기 위해서 리소스들의 이름을 릴리즈 이름을 사용하도록 하면 된다. 릴리즈 이름은 {{ .Release.Name}} 을 사용하면, 릴리즈 이름을 리소스 이름으로 사용할 수 있다. helloworld.yaml을 아래와 같이 수정하면 된다.


apiVersion: apps/v1beta2

kind: Deployment

metadata:

 name: {{ .Release.Name }}

spec:


그런데, 이렇게 설치가 된 리소스들이 어떤 차트에 의해서 설치된 것인지 구별이 잘 안될 수 있기 때문에, 좀더 좋은 방법은 리소스 이름을 “차트 이름-릴리즈 이름" 형태로 하는 것이 좋다. 차트 이름은 {{ .Chart.Name }} 을 사용하면 된다. 아래는 “차트 이름-릴리즈 이름" 형태로 정의한 예제이다.


apiVersion: apps/v1beta2

kind: Deployment

metadata:

 name: {{ .Chart.Name }}-{{ .Release.Name }}


helm template 명령을 이용해서 테스트를 해보자. 같은 예제를  helloworld2 디렉토리에 새롭게 만들었다. (그래서 아래 명령을 보면 ./helloworld2 디렉토리를 차트 디렉토리로 실행하였다.) 그리고 릴리즈 이름을 --name을 이용해서 myrelease로 지정하였다.


% helm template --name myrelease ./helloworld2

---

# Source: helloworld2/templates/helloworld.yaml

apiVersion: apps/v1beta2

kind: Deployment

metadata:

 name: helloworld2-myrelease

spec:

 replicas: 3

:


metadata:

 name: helloworld-deployment

spec:

 replicas: 10

 minReadySeconds: 5

삭제

그리고 설치된 차트는 간단하게 helm delete 명령으로 삭제가 가능하다.

%helm delete helloworld

release "helloworld" deleted



본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요


쿠버네티스 #10


배포 (Deployment)


조대협



롤링 업데이트

애플리케이션을 배포 하는 방법에 대해서 알아보자.

일반적으로 애플리케이션을 배포하는 방법은 블루/그린, 카날리 배포, 롤링 업데이트도 여러가지 방법이 있다.

그중에서 몇가지 패턴에 대해서 알아보도록 하자


롤링 업데이트는 가장 많이 사용되는 배포 방식 중의 하나이다.

새 버전을 배포하면서, 새 버전 인스턴스를 하나씩 늘려나가고, 기존 버전을 하나씩 줄여나가는 방식이다. 이 경우 기존 버전과 새버전이 동시에 존재할 수 있는 단점은 있지만, 시스템을 무 장애로 업데이트할 수 있다는 장점이 있다.


롤링업데이트를 쿠버네티스의 Replication Controller (RC)를 이용하는 방법을 보면 다음과 같다.

아래와 같이 RC가 v1 버전의 Pod들을 관리하고 있다고 보자. 아래와 같이 3개의 Pod가 서비스 되고 있다고 볼때,



v2를 배포하기 위해서, v2 Pod를 컨트롤한 RC를 만들고 replica의 수를 1로해서 v2 Pod를 하나 생성한다.. 그리고 RC v1에서, replica의 수를 3 → 2로 줄여서 v1 Pod의 수를 2개로 조정한다.



같은 방식으로 v1 Pod의 수를 1로 조절하고, v2 Pod의 수를 2로 늘린다.



마지막으로, Pod v1을 0으로 줄이고, RC v1을 삭제한다. 그리고 Pod v2을 하나 더 늘린다.




앞에서 봤듯이, 롤링 업데이트를 하려면 RC를 두개를 만들어야 하고, RC의 replica 수를 단계적으로 조절해줘야 한다. 또한 배포가 잘못되었을때 이를 롤백하려면 이 순서를 꺼꾸로 다시 해야 한다.

Deployment

여러가지 배포 방식을 RC를 이용해서 구현할 수 있지만, 운영이 복잡해지는 단점이 있다. 그래서 쿠버네티스에서는 일반적으로 RC를 이용해서 배포하지 않고 Deployment라는 개념을 사용한다.

앞에서 봤듯이 롤링 업데이트등을 할때, RC를 두개를 만들어야 하고, 하나씩 Pod의 수를 수동으로 조정해야 하기 때문에 이를 자동화해서 추상화한 개념이 Deployment 이다.


Deployment는 기본적으로 RC를 생성하고, 이를 관리하는 역할을 한다.


v1 버전을 배포했다가 v2를 배포하는 시나리오를 구현해보자

먼저 node.js로 v1과 v2 애플리케이션을 구현해보자


아래는 version 1 애플리케이션인 server.js 이다. 응답으로 “Hello World! I’m Server version 1” 을 리턴한다.


var os = require('os');


var http = require('http');

var handleRequest = function(request, response) {

 response.writeHead(200);

 response.end("Hello World! I'm Server version 1 .  "+os.hostname() +" \n");


 //log

 console.log("["+

Date(Date.now()).toLocaleString()+

"] "+os.hostname());

}

var www = http.createServer(handleRequest);

www.listen(8080);


Version 2 애플리케이션도 내용은 갔다. 응답 문자열을 아래와 같이 version 1에서 version 2로만 변경하였다.

 response.end("Hello World! I'm Server version 2. "+os.hostname() +" \n");


이 두 server.js를 도커 이미지로 만든 다음에,

gcr.io/terrycho-sandbox/deployment:v1 , gcr.io/terrycho-sandbox/deployment:v2 라는 이름으로 컨테이너 레지스트리에 등록한다.


다음 Pod를 컨트롤할 RC를 정의해야 하는데, Deployment를 사용하면 RC를 별도로 정의하지 않고, Deployment가 자동으로 RC를 생성하도록 한다.

아래는 hello-deployment.yaml 로 Deployment를 정의한 내용이다.  RC 정의와 크게 다르지 안고, selector 부분을 matchLabels를 사용하였다.


apiVersion: apps/v1beta2

kind: Deployment

metadata:

 name: hello-deployment

spec:

 replicas: 3

 minReadySeconds: 5

 selector:

   matchLabels:

     app: hello-deployment

 template:

   metadata:

     name: hello-deployment-pod

     labels:

       app: hello-deployment

   spec:

     containers:

     - name: hello-deployment

       image: gcr.io/terrycho-sandbox/deployment:v1

       imagePullPolicy: Always

       ports:

       - containerPort: 8080



롤링 업데이트시 Pod 배포가 빠르게 되기 때문에, 테스트 용도로 Pod 배포를 인위적으로 느리게 해서 배포 과정을 살펴보기 편하게 하도록 하겠다.

minReadySeconds를 5로 줬는데, Pod가 배포되고 서비스를 시작하는데 5초 정도 딜레이를 준다. 5초 단위로, Pod 가 배포 되는 과정을 살펴볼 수 있다.


다음 이 Pod들 앞에 Service를 배포해보자

아래는 hello-deployment-service.yaml 이다.


apiVersion: v1

kind: Service

metadata:

 name: hello-deployment-svc

spec:

 selector:

   app: hello-deployment

 ports:

   - name: http

     port: 80

     protocol: TCP

     targetPort: 8080

 type: LoadBalancer


배포

YAML 파일 작성이 끝났으면, Deployment와 Service를 배포해보자.

배포가 끝난후에, kubectl get pod 로 확인해보면 아래와 같이 pod 가 3개가 올라온것을 확인할 수 있다.



Service의 IP를 확인한후 curl 명령을 이용해서 요청을 보내보면 아래와 같이 version 1 서버로 요청이 가는 것을 확인할 수 있다.



업데이트

그러면 v2 이미지를 배포해보자. 여러가지 방법이 있는데, kubectl set image deployment라는 명령을 이용하면 이미지를 새 이미지로 변경할수 있다. 다음 명령어를 실행해보자


%kubectl set image deployment hello-deployment hello-deployment=gcr.io/terrycho-sandbox/deployment:v2


명령어를 실행하면 v1 → v2로 pod를 하나씩 롤링 업데이트를 한다. 위의 명령을 실행해놓고 kubectl get pod 명령을 실행해보면 아래 그림과 같이 pod를 하나씩 지워가면서 새로운 pod를 생성하는 것을 확인할 수 있다.




배포가 끝난후에, kubectl describe deploy hello-deployment 명령을 실행해서  deployment 내용을 살펴보자 아래 내용을 보면 Replica Set replica set hello-deployment-68bd497896의 replica수를 3-->0 개로 줄이고, 새 버전의 RS인 replica set hello-deployment-5756bb6c8f의 replica 수를 1-->3으로 올리는 것을 확인할 수 있다.



잘 보면 Replication Controller가 아니라 Replication Set (RS)을 사용하는 것을 볼 수 있는데, Deployment는 RC대신 RS를 사용한다.

그리고 하나 주목할만한점은 Pod의 이름은 [deployment 이름]-[RS의 해쉬 #]-[Pod의 해쉬#] 를 사용한다.


배포가 끝난 후에 확인해보면 위처럼 Pod의 이름이 hello-deployment-5756bb6c8f-* 으로, 새로 배포된 RS 의 이름과 동일한것을 볼 수 있다.


set image 명령은 기존 배포된 deployment의 이미지를 변경하도록 하지만,

Deployment의 이미지 수정과 같이 쿠버네티스의 객체 (Object)의 정보를 수정하는 방법은 여러가지 방법이 있다.


객체의 설정 업데이트

그러면 간단하게, 쿠버네티스 객체 정보를 수정하는 방법을 살펴보자

kubectl edit

edit 명령은 리소스의 설정 정보를 kubectl 이 설치되어 있는 머신의 에디터를 이용해서 에디트할 수 있다.

예를 들어 hello-deployment 라는 이름의 deployment 리소스의 설정을 에디트 하고 싶으면,

%kubectl edit deploy hello-deployment

명령을 실행하면, (맥북 기준) vi 에디터가 실행되고, hello-deployment  설정 정보를 vi 에디터로 편집할 수 있게해준다. 에디터에서 설정을 변경한 후 저장하면, 그 객체의 설정값이 업데이트 된다.


아래는 kubectl edit deploy hello-deployment 를 이용하여 컨테이너 이미지의 태그를 v2로 변경한 예이다.


설정을 변경하는데 유용하게 사용할 수 있지만, 특정 리소스의 설정 정보를 에디터에서 보여주기 때문에, 상세한 설정 (yaml)을 보는데 유용하게 이용할 수 있다.

kubectl replace

설정 파일 수정하거나, 설정 파일을 새로 만들어서 그 파일로 설정을 업데이트하고 싶을때는  replace 명령을 사용한다.

%kubectl replace -f [YAML 파일명]

으로 이용한다.

kubectl patch

patch 명령은 파일 업데이트 없이 기존 리소스의 설정 정보 중 여러개의 필드를 수정하고자 하는데 이용한다.

%kubectl patch [리소스 종류] [리소스명] --patch ‘[YAML이나 JSON 포맷으로 변경하고자 하는 설정]’ 을 넣어주면 된다.


예를 들어

%kubectl patch deployment hello-deployment --patch 'spec:\n template:\n  spec:\n containers:\n - name: hello-deployment\n image: gcr.io/terrycho-sandbox/deployment:v2’

명령은 deployment 중에 hello-deployment 리소스에 대해서 image 명을  image: gcr.io/terrycho-sandbox/deployment:v2 로 변경한 예이다.


특히 [YAML] 설정은 한줄에 써야 하는 만큼 띄어쓰기에 조심하는 것이 좋다.


patch나 edit의 경우 쉽게 설정을 업데이트할 수 있는 장점은 있지만, 업데이트에 대한 히스토리를 추적하기 어려운 만큼 가급적이면, 새로운 파일을 생성하고, 파일을 replace를 통해서 적용하는 것이 파일 단위로 변경 내용을 추적할 수 있기 때문에 이 방법을 권장한다.

롤백

Deployment은 롤링 업데이트이외에, 롤백도 손쉽게 지원한다.

먼저 배포된 버전을 체크해보려면 kubectl rollout history deployment/[Deployment 이름]을 실행하면 기존에 배포된 버전을 확인할 수 있다. 디폴트로는 2개의 버전을 유지하게 되어 있다.



1버전으로 롤백을 하려면 kubectl rollout undo deployment [ deployment 명 ] --to-revision=[롤백할 버전명] 을 하면, 그 버전으로 롤백이 된다.

명령을 실행하면 아래와 같이 이전 버전으로 롤백이 되는 것을 확인할 수 있다.



롤백등을 위해서 Deployment를  RS를 여러 버전을 유지하고 있다.

유지하는 버전의 수는  Deployment에서 설정이 가능하다.


버전 (태그)

배포 이야기가 나왔기 때문에, 버전/태그에 대해서 언급하도록 하겠다.

쿠버네티스에서 사용되는 컨테이너 이미지 명은 gcr.io/terrycho-sandbox/deployment:v2 와 같이 [컨테이너 이미지명]:[태그] 의 조합으로 구성되는데, 태그는 일반적으로 버전을 사용한다.

주의할점은 컨테이너를 새로 빌드할때 마다 버전을 올리도록 해야, 나중에 구분이 가능하기 때문에 컨테이너를 빌드할때 마다 다른 태그를 사용하는 것을 습관화할 필요가 있다.

새롭게 빌드한 컨테이너 이미지를 같은 태그를 사용하는 것은 향후에 어떤 내용이 변경이 되었는지를 추적하기 어렵기 때문에 좋은 방법은 아니다.


“latest” 태그

쿠버네티스에서 사용되는 도커 컨테이너 이미지 중에 latest 라는 특별한 의미를 가지는 태그가 있는데, docker pull gcr.io/terrycho-sandbox/deployment 과 같은 명령으로 컨테이너 이미지에 태그명을 정의하지 않으면 디폴트로 latest라고 태그된 이미지를 가지고 오도록 되어 있다.


보통 최신 이미지에 이 latest 태그를 추가한다. (하나의 컨테이너는 두개 이상의 이미지를 가질 수 있다.)

이렇게 하면 latest 태그를 이용하여 항상 최신 이미지를 읽어올 수 있는 장점이 있을 수 있으나, 불러온 컨테이너 이미지의 버전을 정확히 알기가 어렵기 때문에 권장하는 방법이 아니다.


쿠버네티스에서 컨테이너 이미지를 가지고 올때는 가급적이면 latest 태그를 사용하는 것 보다는 명시적으로 배포하고자 하는 버전을 태그로 정의하는 것을 권장한다.





본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요