본문 바로가기

서버운영 (TA, ADMIN)/인프라

[컨테이너] 핵심만 콕! 쿠버네티스(1) - helm 패키지 매니저

헬름 개념 설명 "What is Helm?" - https://www.youtube.com/watch?v=fy8SHvNZGeE 

원문 출처 "핵심만 콕! 쿠버네티스" 8장 - https://book.naver.com/bookdb/book_detail.nhn?bid=16682923 

 

쿠버네티스 위에서 동작하는 애플리케이션은 Deployment, Service, ConfigMap과 같은 다양한 리소스의 조합으로 구성된다. 애플리케이션 배포시 이런 리소스들을 개별적으로 생성하는 것이 아니라 하나의 패키지로 묶어서 배포한다. 패키지로 묶어서 관리하면 여러 리소스들을 동시에 추가 및 업그레이드하기가 편리해진다. 쿠버네티스의 패키지 매니저인 helm에 대해서 살펴본다.

1. helm이란?

helm은 쿠버네티스 패키지 매니저이다. 쉽게 표현하자면, apt, yum, pip 툴과 비슷하게 플랫폼의 패키지를 관리한다. helm을 이용하여 원하는 소프트웨어(패키지)를 쿠버네티스에 손쉽게 설치할 수 있다. helm 패키지 또한 YAML 형식으로 구성되어 있으며, 이것을 chart라고 한다.

 

helm chart의 구조는 크게 values.yaml과 templates/ 디렉토리로 구성된다.

  - values.yaml: 사용자가 원하는 값들을 설정하는 파일이다.

  - templates/: 설치할 리소스 파일들이 존재하는 디렉토리이다. 해당 디렉토리 안에는 Deployment, Service 등과 같은 쿠버네티스 리소스가 YAML 파일 형태로 들어가 있다. 각 파일들의 설정값은 비워져 있고(placeholder) values.yaml의 설정값들로 채워진다.

 

패키지가 설치될 시점에 values.yaml 파일의 설정값들을 이용하여 templates 디렉토리에 들어있는 YAML 파일의 구멍난 부분을 채운다. values.yaml 파일에는 자주 바뀌거나 사용자마다 달라지는 설정값들을 입력하는 용도로 사용하고 templates 디렉토리는 패키지의 뼈대를 이룬다.

helm을 잘 활용하면 다른 사람이 만든 애플리케이션도 손쉽게 나의 쿠버네티스 클러스터로 가져올 수 있게 된다. 도커가 단순히 프로세스 레벨에서 외부의 것을 가져다 쓸 수 있게 해준것이라면, 쿠버네티스에서는 helm을 이용하여 프로세스(Pod)와 네트워크(Service), 저장소(PersistentVolume) 등 애플리케이션에서 필요한 모든 자원들을 외부에서 가져올 수 있게 한다.

1.1. helm 설치

helm을 설치하는 방법은 무척 간단하다. 다음 명령을 수행하면 helm이 설치된다.

curl https //raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
bash -s -- --version v3.2.2

이제, 직접 helm chart를 만들어본다.

1.2. chart 생성

$ helm create <CHART_NAME>

chart는 리소스들을 편리하게 배포하거나 다른 사람들과 쉽게 공유할 수 있게 패키징한 설치파일 묶음이다. 이 설치파일 묶음을 직접 만들어본다. mychart라는 이름을 가진 chart를 생성하고, 그 속에 어떤 파일들이 있는지 확인해 본다.

$ helm create mychart
Creating mychart
$ ls mychart
Chart.yaml   charts   templates   values.yaml

  - Chart.yaml: chart 이름, 버전 정보 등 chart의 전반적인 정보를 담고 있다.

  - charts: chart 속에 또 다른 여러 chart들을 넣을 수 있다. 기본적으로는 비어있다.

  - templates/: chart의 뼈대가 되는 쿠버네티스 리소스가 들어있는 폴더이다.

  - values.yaml: 사용자가 정의하는 설정값을 가진 YAML 파일이다.

 

templates 폴더 아래의 service.yaml을 살펴보면 placeholder({{ key }})가 있는 것을 확인해볼 수 있다. 

apiVersion: v1
kind: Service
metadata:
    name: {{ include "mychart.fullname" . }}
    labels:
      {{- include "mychart.labels" . | nindent 4 }}
spec:
    type: {{ .Values.service.type }}                 # 서비스 타입 지정
    ports:
      - port: {{ .Values.service.port }}             # 서비스 포트 지정
        targetPort: http
        protocol: TCP
        name: http
    selector:
      {{- include "mychart.selectorLabels" . | nindent 4 }}

이번에는 values.yaml 파일을 살펴본다. YAML 형식에 따라 설정값들이 적혀있다. 앞서 눈여겨 본 service.type과 service.port도 보인다. service.type과 service.port를 각각 로드밸런서와 8888로 수정한다.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent

imagePullSecrets: []
nameOverride: ""
fullnameOverried: ""

...

service:
  type: LoadBalancer
  port: 8888
...

values.yaml 수정이 완료되면 helm chart를 설치한다.

1.3. chart 설치

helm install <CHART_NAME> <CHART_PATH>

다른 패키지 매니저와는 다르게 모든 라이브러리 종속성이 컨테이너 안에서 해결되기 때문에 helm에서는 실제 사용할 프로세스만 생성된다.

$ helm install foo ./mychart
NAME: foo
LAST DEPLOYED: Mon Sep 27 13:22:06 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace default svc -w foo-mychart'
  export SERVICE_IP=$(kubectl get svc --namespace default foo-mychart --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
  echo http://$SERVICE_IP:8888

 

Service 리소스를 조회해 보면 values.yaml 파일에서 정의한 것과 같이 Service는 로드밸런서 타입에 8888 포트를 사용하는 것을 확인할 수 있다.

$ kubectl get svc
NAME          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
foo-mychart   LoadBalancer   10.108.49.163   <pending>     8888:30633/TCP   28s
kubernetes    ClusterIP      10.96.0.1       <none>        443/TCP          19m

 

앞에서 살펴본 templates/service.yaml 파일의 {{ .Values.service.type }}과 {{ .Values.service.port }} 부분이 values.yaml 파일과 합쳐져 최종 Service 리소스가 생성된다.

 

https://devocean.sk.com/blog/tags/index.do?searchData=Kubernetes 

 

데보션 (DEVOCEAN) 기술 블로그

데보션 (DEVOCEAN) 기술 블로그 , 개발자 커뮤니티이자 내/외부 소통과 성장 플랫폼

devocean.sk.com

1.4. chart 리스트 조회

설치된 helm chart를 조회하는 명령어이다. -n(--namespace) 옵션을 이용하여 네임스페이스별 다른 리스트를 조회할 수도 있다.

$ helm list

default와 kube-system 네임스페이스를 각각 조회해본다.

$ helm list
NAME	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART        	APP VERSION
foo 	default  	1       	2021-09-27 13:22:06.583053 +0900 KST	deployed	mychart-0.1.0	1.16.0
$ helm list -n kube-system
NAME	NAMESPACE	REVISION	UPDATED	STATUS	CHART	APP VERSION

네임스페이스에 따라 chart 리스트가 다르게 보인다.

1.5. chart 렌더링

$ helm template <CAHRT_PATH>

실제 설치까지 수행되는 것이 아니라 values.yaml 파일과 templates 안의 템플릿과 파일들의 합쳐진 YAML 정의서 결과를 확인하고 싶다면 template 명령을 사용할 수 있다. helm에서는 이것을 rendering한다고 표현한다. kubectl 명령툴의 --dry-run 옵션과 유사하다고 볼 수 있다.

$ helm template foo ./mychart > foo-output.yaml
$ cat foo-output.yaml
---
# Source: mychart/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: foo-mychart
  labels:
    helm.sh/chart: mychart-0.1.0
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: foo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: foo-mychart
  labels:
    helm.sh/chart: mychart-0.1.0
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: foo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: LoadBalancer
  ports:
    - port: 8888
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: foo
---
# Source: mychart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo-mychart
  labels:
    helm.sh/chart: mychart-0.1.0
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: foo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: mychart
      app.kubernetes.io/instance: foo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: mychart
        app.kubernetes.io/instance: foo
    spec:
      serviceAccountName: foo-mychart
      securityContext:
        {}
      containers:
        - name: mychart
          securityContext:
            {}
          image: "nginx:1.16.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}
---
# Source: mychart/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "foo-mychart-test-connection"
  labels:
    helm.sh/chart: mychart-0.1.0
    app.kubernetes.io/name: mychart
    app.kubernetes.io/instance: foo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['foo-mychart:8888']
  restartPolicy: Never

이를 통해, helm install 명령은 다음과 같다고 볼 수 있다. YAML 파일이 어떤 형태로 만들어져 설치가 되는지 디버깅하는 용도로 종종 사용한다.

helm install <NAME> <CHART_PATH> == helm template <NAME> <CHART_PATH> > \
        output.yaml && kubectl apply -f output.yaml

1.6. chart 업그레이드

$ helm upgrade <CHART_NAME> <CHART_PATH>

이미 설치한 chart에 대해 values.yaml 값을 수정하고 업데이트할 수 있다. Service 타입을 NodePort로 수정하고 다시 배포한다.

service:
  type: NodePort    # 기존 LoadBalancer
  port: 8888
$ helm upgrade foo ./mychart
Release "foo" has been upgraded. Happy Helming!
NAME: foo
LAST DEPLOYED: Mon Sep 27 13:43:36 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services foo-mychart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
$ kubectl get svc
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
foo-mychart   NodePort    10.108.49.163   <none>        8888:30633/TCP   23m
kubernetes    ClusterIP   10.96.0.1       <none>        443/TCP          42m
$ helm list
NAME	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART        	APP VERSION
foo 	default  	2       	2021-09-27 13:43:36.705462 +0900 KST	deployed	mychart-0.1.0	1.16.0

Service 타입이 기존 로드밸런서에서 NodePort로 변경된 것을 확인할 수 있다. chart를 조회하면, REVISION 숫자가 2로 올라갔다. 업데이트마다 REVISION 값이 올라간다.

1.7. chart 배포상태 확인

helm status <CHART_NAME>

배포된 chart의 상태를 확인하기 위해서 다음과 같은 명령을 사용한다.

$ helm status foo
NAME: foo
LAST DEPLOYED: Mon Sep 27 13:43:36 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services foo-mychart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

1.8. chart 삭제

helm delete <CHART_NAME>

생성한 helm chart를 더는 사용하지 않아서 삭제하고 싶다면 delete 명령을 사용한다.

$ helm delete foo
release "foo" uninstalled
$ helm list
NAME	NAMESPACE	REVISION	UPDATED	STATUS	CHART	APP VERSION

2. 원격 리파지토리(repository)

helm을 사용할 때의 가장 큰 장점은 외부에 잘 구축된 애프릴케이션을 손쉽게 가져올 수 있게 해준다는 점이다. helm만 잘 사용해도 쿠버네티스 생태계에서 지원하는 다양하고 강력한 애플리케이션들을 활용할 수 있다.

 

helm에는 chart 원격 저장소인 리파지토리가 있다. 리파지토리는 여러 chart를 한 곳에 묶어서 보관해놓은 저장소이다. 사용자가 온라인상에 제공되는 리파지토리를 추가해서 원격 저장소로부터 chart를 로컬 클러스터에 설치할 수도 있다.

2.1. 리파지토리 추가

$ helm repo add stable https://charts.helm.sh/stable
"stable" has been added to your repositories

2.2. 리파지토리 업데이트

추가한 리파지토리의 인덱스 정보를 최신으로 업데이트 하는것이 필요하다. helm은 리파지토리 정보를 기본적으로 캐싱해서, 신규 chart를 설치하기 위해서 업데이트를 수행한다.

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈

2.3. 리파지토리 조회

현재 등록된 리파지토리 리스트를 확인한다. 현재 stable 리파지토리만 등록했으므로, 1개만 보인다.

$ helm repo list
NAME  	URL
stable	https://charts.helm.sh/stable

2.4. 리파지토리내 chart 조회

stable 리파지토리에 저장된 chart 리스트를 확인한다.

$ helm search repo stable
NAME                                 	CHART VERSION	APP VERSION            	DESCRIPTION
stable/acs-engine-autoscaler         	2.2.2        	2.1.1                  	DEPRECATED Scales worker nodes within agent pools
stable/aerospike                     	0.3.5        	v4.5.0.5               	DEPRECATED A Helm chart for Aerospike in Kubern...
stable/airflow                       	7.13.3       	1.10.12                	DEPRECATED - please use: https://github.com/air...
stable/ambassador                    	5.3.2        	0.86.1                 	DEPRECATED A Helm chart for Datawire Ambassador
stable/anchore-engine                	1.7.0        	0.7.3                  	Anchore container analysis and policy evaluatio...
stable/apm-server                    	2.1.7        	7.0.0                  	DEPRECATED The server receives data from the El...
$ helm search repo stable/airflow
NAME          	CHART VERSION	APP VERSION	DESCRIPTION
stable/airflow	7.13.3       	1.10.12    	DEPRECATED - please use: https://github.com/air...

 

다음 주소에서 stable 리파지토리 외에 다양한 원격 저장소를 조회해볼 수 있다. ( https://hub.helm.sh/charts )

3. 외부 chart 설치 (WordPress)

3.1. chart install

stable 리파지토리에 있는 WordPress chart를 설치해본다. 로커 ㄹ디렉토리에 chart가 존재하지 않더라도 원격 리파지토리에 있는 chart를 바로 설치할 수 있다. 이때 몇가지 옵션을 지정할 수 있다.

  --version: chart의 버전을 지정한다. Chart.yaml 안에 version 정보를 참조한다.

  --set: 해당 옵션으로 values.yaml 값을 동적으로 설정할 수 있다.

  --namespace: chart가 설치될 네임스페이스를 지정한다.

$ helm install wp stable/wordpress \
        --version 9.0.3 \
        --set service.port=8080 \
        --namespace default
WARNING: This chart is deprecated
NAME: wp
LAST DEPLOYED: Mon Sep 27 14:16:43 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
This Helm chart is deprecated

Given the `stable` deprecation timeline (https://github.com/helm/charts#deprecation-timeline), the Bitnami maintained Helm chart is now located at bitnami/charts (https://github.com/bitnami/charts/).

The Bitnami repository is already included in the Hubs and we will continue providing the same cadence of updates, support, etc that we've been keeping here these years. Installation instructions are very similar, just adding the _bitnami_ repo and using it during the installation (`bitnami/<chart>` instead of `stable/<chart>`)

```bash
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm install my-release bitnami/<chart>           # Helm 3
$ helm install --name my-release bitnami/<chart>    # Helm 2
```

To update an exisiting _stable_ deployment with a chart hosted in the bitnami repository you can execute

```bash
$ helm repo add bitnami https://charts.bitnami.com/bitnami
$ helm upgrade my-release bitnami/<chart>
```

Issues and PRs related to the chart itself will be redirected to `bitnami/charts` GitHub repository. In the same way, we'll be happy to answer questions related to this migration process in this issue (https://github.com/helm/charts/issues/20969) created as a common place for discussion.

** Please be patient while the chart is being deployed **

To access your WordPress site from outside the cluster follow the steps below:

1. Get the WordPress URL by running these commands:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w wp-wordpress'

   export SERVICE_IP=$(kubectl get svc --namespace default wp-wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
   echo "WordPress URL: http://$SERVICE_IP:8080/"
   echo "WordPress Admin URL: http://$SERVICE_IP:8080/admin"

2. Open a browser and access WordPress using the obtained URL.

3. Login with the following credentials below to see your blog:

  echo Username: user
  echo Password: $(kubectl get secret --namespace default wp-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)
$ kubectl get pod
NAME                           READY   STATUS              RESTARTS   AGE
wp-mariadb-0                   0/1     ContainerCreating   0          57s
wp-wordpress-f6d6dc5f7-zfcd7   0/1     ContainerCreating   0          57s
$ kubectl get svc
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                        AGE
kubernetes     ClusterIP      10.96.0.1       <none>        443/TCP                        74m
wp-mariadb     ClusterIP      10.103.46.120   <none>        3306/TCP                       78s
wp-wordpress   LoadBalancer   10.105.215.66   <pending>     8080:30339/TCP,443:30092/TCP   78s

이렇듯 나의 클러스터 위에 워드프레스 관련된 소프트웨어 하나 없어도 리파지토리를 추가하고 helm install 명령 하나로 워드프레스 사이트를 순식간에 만들 수 있다.

3.2. chart fetch

리파지토리의 chart를 원격에서 바로 설치할 수도 있지만 로컬 디렉토리로 다운로드해서 설치할 수도 있다. 사용자가 세부적으로 설정값들을 수정한 후에 애플리케이션을 설치하고 싶을때는 fetch를 사용한다. 먼저 fetch 명령을 이용해서 chart를 다운로드한다. chart는 기본적으로 tar로 묶인 상태로 저장된다. --untar 옵션을 이용하여 폴더로 풀어진 상태를 저장할 수 있다.

$ helm fetch --untar stable/wordpress --version 9.0.3
$ ls wordpress/
$ helm install wp-fetch ./wordpress

helm 패키지 매니저는 쿠버네티스를 사용하는데 있어서 강력함을 더해주는 툴이다. 쿠버네티스의 기능을 풍성하게 만들어주고 복잡한 애플리케이션도 손쉽게 구축할 수 있게 도와준다. 다음은 이전에 설치한 helm 을 제거하는 명령이다.

$ helm delete wp
release "wp" uninstalled
$ kubectl delete pvc data-wp-mariadb-0
persistentvolumeclaim "data-wp-mariadb-0" deleted