본문 바로가기

[NCP] Helm 사용하여 Kubernetes 기반으로 서비스 배포하기

넥스터즈에서 배포를 준비하는 글에서 Kubernetes를 사용하여 배포하는 것을 최종 목표로 잡았었다.

네이버 클라우드 플랫폼(NCP) 에서 제공하는 Kubernetes 서비스와 Container Registry 를 사용하여 배포한 과정을 기록한다.

아직 초보라 많은 설정을 써보진 못해서 차차 개선해나가기로 한다.

 

목차

0. 배포해볼 구조 및 용어 정리

1. 설치

2. docker image 레지스트리에 저장

3. helm chart 생성 및 배포

4. 이미지 재배포

5. 정리


 

0. 배포해볼 구조

먼저 서비스를 어떻게 배포하는가를 짚고 넘어간다.

기본 구조

정말 단순하게 End User가 Load Balancer* 외부 IP를 통해 접속하면 부하 분산에 의해 적절한 Pod로 접근하고, nginx가 프록시하는 구조이다.

* 지금은 Pod 하나지만 auto scaling 설정 이후 Pod가 늘어날 때를 대비했다.

 

PM2 추가 이유

컨테이너 환경에서는 default로 pm2 역할을 컨테이너가 하지만 다음 세가지가 아쉽다.
1. Scale-up/down을 node에 비해 느리다. node 아키텍쳐는 빠른 I/O와 재시작이 장점인데 활용할 수 없다.
2. pm2로 인스턴스 재기동 조건을 제어할 수 있다.
3. 로그 수집을 추가하지 않는 이상 tracing이 어렵다.

 

이 구조에 맞춰 사전에 미리 docker 환경을 구성하였고 해당 이미지를 빌드하여 사용할 계획이다.

Docker 설정에 관한 정리

 

다만 이전 글에서 하나 수정해야 할 것은 nginx 설정 중 variable.conf이다.

docker-compose로 컨테이너를 생성할 때에는 같은 docker network를 공유하고 IP명은 곧 컨테이너명이었기 때문에 컨테이너명을 넣었지만 Pod 내의 컨테이너들은 같은 IP를 공유하기 때문에 localhost로 명시해야 한다.

 

용어 정리

쿠버네티스 용어도 간단하게 요약정리한다.

 

Cluster

쿠버네티스의 여러 리소스를 관리하기 위한 집합체

 

Node

Cluster 중 가장 큰 단위로 Docker 컨테이너들이 위치한 곳

노드 중 Master 노드는 클러스터 전체를 관리하는 노드이다.

 

출처 : https://coding-start.tistory.com/308

 

Pod

Docker 컨테이너들의 집합, 스토리지 및 네트워크를 공유 (참고)

 

Service

Pod는 이미지를 재빌드 후 생성하거나 등등 다양한 이유로 제거될 수 있다. 따라서 IP또한 고정이 아닌데 Service가 Pods들을 앞에서 매핑해 줄 수 있다. 

쿠버네티스는 파드에게 고유한 IP 주소와 파드 집합에 대한 단일 DNS 명을 부여하고, 그것들 간에 로드-밸런스를 수행할 수 있다.

type으로는 CluserIP, NodePort, LoadBalancer, ExternalName이 있다.

 

[참고]

쿠버네티스 서비스(kubernetes services) (1)

 

Deployment

k8s에서 보통 Pod를 직접 생성하기보다는 Deployment를 정의하여 Pod 명세와 ReplicaSet에 대한 선언적 업데이트를 한다.

 

ConfigMap

컨테이너에서 쓰이는 데이터를 저장할 때 사용한다. (기밀 데이터는 Secret으로 생성한다.)

볼륨 마운트 시 사용할 데이터, Pod 구성 시 사용할 환경 변수 등을 컨피그맵으로 생성한다.

 

 

1. 설치

먼저 NCP에 kubernetes 서비스를 생성하고, container registry 서비스를 이용신청해야 한다.

생성 시 참고할 글들을 소개한다. 또한 docker와 docker-compose가 설치되어 있어야 한다.

 

[참고]

[NCP] NAVER CLOUD에서 KUBERNETES를 사용해보자

[NCP] NAVER CLOUD KUBERNETES – CONTAINER REGISTRY로 컨테이너 이미지를 관리하자

 

‼️ 앞으로 설명할 글에서 --kubeconfig=$KUBE_CONFIG 는 kubectl과 helm 명령어의 alias로 등록했다고 가정하고 진행한다.

 

2. docker image 레지스트리에 저장

이제 NCP의 Container Registry에 이미지를 푸쉬한다.

docker-compose로 이미지를 생성한다. 필자는 따로 컨테이너로 먼저 띄워서 정상적으로 실행되는지 확인하기 위해 빌드와 생성을 동시에 할 수 있는 up 커맨드를 사용했다.

docker-compose up -d

 

remote registry에 접속하기 위해 docker login  한다.

 

docker login <REGISTRY_ADDRESS>

 

이미지를 푸쉬하기 전 <REGISTRY_ADDRESS>/<IMAGE_NAME> 으로 이미지를 태깅한다. 

docker image tag <IMAGE_NAME> <REGISTRY_ADDRESS>/<IMAGE_NAME>

 

이제 이미지를 레지스트리에 푸쉬한다.

docker push <REGISTRY_ADDRESS>/<IMAGE_NAME> # tag를 안붙이면 기본 latest

 

3. helm chart 생성 및 배포

 

이제 배포할 이미지까지 준비가 되었으니 k8s 배포를 준비한다.

 

helm이란

package managing tool로, k8s 배포 시 필요한 설정들을 한방에 설정 및 배포할 수 있게 해주는 유용한 툴이다.

다만 처음 써보면 yaml 파일들 속에서 길을 잃을 수 있는데 로컬환경에서 minikube로 일일히 배포연습을 해보면서 helm chart를 구성했었다. helm chart는 Go Template을 사용하여 설정한다.

 

다음 명령어로 기본 helm chart를 생성한다.

helm create <CHART_NAME>

 

필자는 지금 수정한 상태이지만 생성하고 나면 기본 구성은 templates와 Chart.yaml, values.yaml 등이 포함된 폴더가 생성된다.

*dev.values.yaml 파일은 필자가 추가한 것이다.

 

 

이 중 다음 두가지 파일이 중요한데 각 파일을 요약하자면 이렇다.

  • /templates : k8s 배포 시 사용되는 yaml 파일들.
    /templates 내부에  {{ .Values.**.* }} 라는 값들에 values.yaml 파일 내용이 들어간다.
  • values.yaml : /templates 에 삽입될 데이터

 

dev.values.yaml

dev.values.yaml은 dev환경과 production 환경을 구분하기 위해 values.yaml 파일을 각 환경별로 생성한 파일이다.

 

 

templates

templates 폴더는 배포에 필요한 yaml 파일이 저장되어 있다. 각 yaml 파일은 template화되어 지정한 변수에 따라서 release를 생성할 수 있도록 재사용성을 제공한다.

templates 폴더에도 주로 수정한 파일은 deployment와 service이다.

 

templates/service.yaml

필자는 service.yaml 에서 Service 종류를 LoadBalancer로 잡았다. 이렇게 잡으면 NCP 클러스터에서 LoadBalancer 인스턴스를 자동으로 생성해주고 접근가능한 IP 주소를 할당한다.

 

templates/deployment.yaml

필자는 위에서 nginx와 app 이미지를 빌드했다. 따라서 두 이미지의 컨테이너를 Pod에 생성하기 위해 아래처럼 yaml을 수정했다.

 

 

 

 

 

imagePullSecret

또한 NCP의 Container Registry는 Private Registry이므로 이미지를 pull하기 위해서 imagePullSecret 을 추가해주어야 한다.

kubectl create secret docker-registry ${SECRET_NAME} --docker-server=${REGISTRY_ADDRESS} --docker-username=${API_KEY} --docker-password=${API_SECRET} --docker-email=${NCP_LOGIN_EMAIL}

* API_KEY와 API_SECRET은 NCP > 마이페이지 > 계정 관리 > 인증키 관리 에서 확인한 값

 

 

install

kubectl get pods 를 해보면 아직 배포한 Pod가 없기 때문에 아무것도 뜨지 않는데 처음 생성 시 helm install 명령어로 k8s에 Pod를 생성한다.

 

helm install ${NAME} ./${CHART_DIRECTORY}
생성 전, k8s menifest 데이터를 미리 확인하고 싶다면 --debug --dry-run 옵션을 추가하여 실행한다.

 

정상적으로 생성되었다면 다시 Pod 리스트를 조회했을 때 다음처럼 보일 것이다.

 

서비스 인스턴스도 조회해보면 다음처럼 출력된다.

 

EXTERNAL-IP를 보면 자동으로 어떤 도메인이 할당되었음을 확인할 수 있는데 그 도메인은 NCP에서 자동으로 생성된 LB인스턴스이다.

 

EXTERNAL-IP로 접속해보면 정상적으로 뜸을 확인할 수 있다.

 

Global DNS 설정

그런데 EXTERNAL-IP로는 서비스를 출시하기가 곤란하다. 매우매우 랜덤값이기 때문에 보통 이를 그냥 쓰지않고 미리 구입한 도메인을 연결한다. NCP의 Global DNS를 사용해도 좋고, 구매한 도메인 사이트에서 관리할 수 있다면 호스팅 서비스에서 직접 관리할 수도 있다.

 

4. 이미지 재배포

한번 생성된 서비스를 재배포하려면 어떻게 해야 할까?

만약 helm uninstall ${NAME} 으로 이전에 배포된 서비스를 내리고 다시 install하면 Pod 뿐만 아니라 서비스 인스턴스또한 재생성되어 EXTERNAL-IP가 달라져버려 이전에 연결해둔 DNS  레코드 또한 다시 수정해야 한다.

 

새로 빌드한 이미지를 재배포하기 위해서는 upgrade 명령어를 사용한다.

helm upgrade ${NAME} ./${CHART_DIRECTORY} -f ${CHART_DIRECTORY}/dev.values.yaml --recreate-pods

* -f ${CHART_DIRECTORY}/dev.values.yaml  : 아까 위에서 dev, production 환경을 나눠서 배포한다고 한 부분으로, 사용할 values.yaml 파일을 직접 지정하는 옵션

* --recreate-pods 옵션 : 이 옵션을 추가해야 pod를 재생성할 수 있음

 

재배포 시 Pod를 조회해보면 하나는 Terminating되고 있고, 다른 하나가 생성되고 있음을 볼 수 있는데, 이로 미루어 보아 upgrade는 롤링 업데이트로 업데이트하지 않나 생각이 들었다. (참고)

 

 

이렇게 생성부터 재배포까지 알아보았고 도메인으로 접속해보면 정상적으로 배포되었음을 확인할 수 있다.

아래는 필자가 배포한 서비스 화면 예시이다.

(개발 중이라 도메인은 미공개)

 

5. 정리

이렇게 기본 배포를 끝냈다. 아직 해보지 못한 기능들이 많은데 다음 공부로는 hpa 설정을 해보려 한다.

 

hpa 설정

CPU 사용률 등 부하를 체크하여 Pod의 Replica수를 자동으로 Scaling하는 기능으로 HorizontalPodAutoscaler(HPA, 수평스케일)이라 부름

 

8/26 추가

오늘 회의시간에 hpa에서 minReplica와 maxReplica개수를 정하는 기준이 궁금해서 TL님께 질문드렸었다.

Replica 개수를 잡는 기준은 목표 RPS(Request Per Second, 동시 초당 접속자)RPS가 늘어남에 따른 CPU 사용률 추이로 결정지을 수 있다.

 

만약에 서비스에서 목표로 하는 A 서비스의 목표 RPS를 100이라고 가정한다.

그리고 서버 한 대에서 RPS를 증가시킴에 따라 CPU 사용률을 그래프로 표시해보면 한계치가 산출된다.

한계치에 도달했을 때의 rps가 5라면 한 서버당 5rps를 처리할 수 있다는 뜻이므로 최소한으로 필요한 Pod Replica는 100/2 = 20 개가 필요하다. 즉 minReplica는 20이다.

 

일반적으로 최소 필요치에서 a만큼 더해서  minReplica를 정하므로 20+a = 20~25이다.

 

maxReplica는 가용량에 따라 minReplica에서 x2, x3, x5배 해서 결정한다.

 

 

참고한 글

Helo Minikube ... 1

0. helm 설치하기

How to make a Helm chart in 10 minutes

[NCP] CONTAINER REGISTRY에서 이미지를 가져오기 & 로드밸런서 연결

프라이빗 레지스트리에서 이미지 받아오기

https://github.com/mincloud1501/Helm