Helm이란?
Helm은 Kubernetes 애플리케이션을 관리하기 위한 패키지 매니저이다. Chart라는 패키지를 통해 애플리케이션 배포, 관리, 업그레이드를 효율적으로 처리할 수 있다.
- Helm의 필요성
- Kubernetes 리소스의 수동 관리 복잡도를 줄이고, 여러 리소스를 하나의 Chart로 관리가 가능해진다.
- Helm의 구성 요소
- Chart: Kubernetes 애플리케이션을 정의하는 템플릿 파일 모음. 기동되기 위해 필요한 모든 리소스들이 포함되어 있다. (Deployment, Service 등..)
- Release: Helm Chart를 이용해 Kubernetes 클러스터에 배포된 인스턴스.
- Repository: Helm Chart를 저장하고 공유할 수 있는 저장소.
Helm Chart 구조
- 디렉토리 구조
mychart/ ├── Chart.yaml ├── values.yaml ├── charts/ ├── templates/ └── .helmignore
파일 형식
- Chart.yaml
Helm Chart의 메타 데이터와 설정을 정의하는 파일이다.
따라서 이름, 버전 정보, dependency 등과 같은 정보가 포함된다.
# Chart.yaml
apiVersion: The chart API version (required)
name: The name of the chart (required)
version: A SemVer 2 version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
description: A single-sentence description of this project (optional)
type: The type of the chart (optional)
keywords:
- A list of keywords about this project (optional)
home: The URL of this projects home page (optional)
sources:
- A list of URLs to source code for this project (optional)
dependencies: # A list of the chart requirements (optional)
- name: The name of the chart (nginx)
version: The version of the chart ("1.2.3")
repository: (optional) The repository URL ("https://example.com/charts") or alias ("@repo-name")
condition: (optional) A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
tags: # (optional)
- Tags can be used to group charts for enabling/disabling together
import-values: # (optional)
- ImportValues holds the mapping of source values to parent key to be imported. Each item can be a string or pair of child/parent sublist items.
alias: (optional) Alias to be used for the chart. Useful when you have to add the same chart multiple times
maintainers: # (optional)
- name: The maintainers name (required for each maintainer)
email: The maintainers email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). Needn't be SemVer. Quotes recommended.
deprecated: Whether this chart is deprecated (optional, boolean)
annotations:
example: A list of annotations keyed by name (optional).
이후 repository를 추가하고자 하면, 아래와 같이 추가 하면 된다.
helm repo add fantastic-charts https://charts.helm.sh/incubator
- template 폴더
Kubernetes 리소스 템플릿 파일들을 포함하는 디렉토리이다. Helm은 Chart를 배포할 때 이 파일들을 사용해 설정을 기반으로 실제 Kubernetes 리소스 파일을 생성한다.
여기서는 변수를 동적으로 설정한다. 말 그대로 해당 파일이 템플릿이 되고, values.yaml 파일을 통해 커스터마이징이 가능하다.
# template/ReplicationController.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
imagePullPolicy: {{ .Values.pullPolicy }}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{ default "minio" .Values.storage }}
- values.yaml
변수에 대한 값을 입력하는 파일이다. 공식 레파지토리/오픈소스에서 다운받은 helm파일에서 아래 값을 조정하면 내 환경에 맞는 설정으로 운영할 수 있다.
# values.yaml
imageRegistry: myregistry.io
dockerTag: "1.0.0"
pullPolicy: IfNotPresent
storage: "minio"
- charts/
helm charts에는 다른 여러 charts에 종속될 수 있다. 따라서 charts/ 하위 폴더로 이러한 의존성을 관리할 수 있다.
dependencies:
- name: apache
version: 1.2.3
repository: https://example.com/charts
- name: mysql
version: 3.2.1
repository: https://another.example.com/charts
아래 명령어를 수행하면 지정된 차트를 charts 하위 폴더로 다운한다.
helm dependency update
- _helpers.tpl
values와 유사하게 변수를 저장하는 파일이지만, 여러 telmplate하위 항목의 _helpers.tpl을 가져올 수 있어 공통된 템플릿 코드를 정의하기에 적합하다. 또한, 복잡한 로직(문자열 조작, 조건부 논리) 를 처리할 수 있어 helm의 재사용성을 높여준다.
{{/*
Generate the full name of the release.
*/}}
{{- define "hellospring.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Generate the name of the application.
*/}}
{{- define "hellospring.name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
Helm 과 Kustomize
앞서 살펴보았던 kustomzie와 마찬가지로, 모두 어플리케이션을 선언적으로 관리하는 도구이다. 또한 두가지 모두 patchs 와 values를 통해서 커스터마이징이 가능하다.
그렇다면 어떤 상황에서 helm을 선택할까?
- 패키지 관리 및 재사용성: Chart를 통해서 재사용 가능한 구성으로 다양한 환경에 쉽게 배포할 수 있다.
- 복잡한 애플리케이션 구성 지원: Helm Chart는 템플릿화를 통해 복잡한 애플리케이션 구성을 보다 쉽게 관리할 수 있도록 도와줍니다. 여러 리소스와 의존성을 가진 애플리케이션을 한 번에 구성하여 배포할 수 있습니다.
- 커뮤니티 지원: 공식 차트 저장소뿐만 아니라 다양한 오픈소스 커뮤니티에서 유지보수하는 차트들이 많아 쉽게 활용할 수 있다. 어렵게 설치 과정을 거쳐 리소스를 생성하지 않고도 이미 제공되는 charts를 통해서 argocd와 같은 툴을 간단하게 설치할 수 있다. (가장 큼)
- GitOps와의 호환성: Argo CD는 helm을 지원하여 용이하게 배포를 자동화할 수 있다. 참고로 ArgoCD는 kustomize도 지원한다.
Kustomize는 쿠버네티스 오브젝트의 선언적 관리를 수행할 수 있게 도와준다.
- configmap, secret과 같은 오브젝트를 선언적으로 생성
- patch를 통해 환경별 커스터마이징이 가능하다.
실습
💡helm을 통해서 helm charts를 생성해보고, argocd를 쉽게 패키지를 설치하고, values.yaml을 통해서 커스터마이징 해본다.
ArgoCD 설치
- argocd cli 명령어 설치
curl -sSL https://github.com/argoproj/argo-cd/releases/download/v2.12.6/argocd-linux-amd64 -o argocd
chmod +x argocd
sudo mv argocd /usr/local/bin/
이후 아래와 같이 정상 설치가 된 것을 볼 수 있다.
- helm 설치
curl -sSL https://get.helm.sh/helm-v3.16.2-linux-amd64.tar.gz | tar -xz
sudo mv linux-amd64/helm /usr/local/bin/helm
- helm repo 추가
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm search repo argocd
아래와 같이 다운 받을 수 있는 argocd 관련 chart가 보여진다.
- namespace 추가
kubectl create namespace argocd
- values.yaml 생성
# argocd/values.yaml
installCRDs: false
controller:
replicas: 1
repoServer:
replicas: 2
server:
replicas: 2
service:
type: NodePort
nodePortHttp: 30800
config:
accounts:
admin: "login"
redis:
enabled: true
redis-ha:
enabled: true
- helm 설치 검증
helm -n argocd template argocd argo/argo-cd -f values.yaml
해당 명령어를 치면 install 하면 설치되게 될 argocd의 manifest가 나오게 된다.
- 설치
helm install argocd argo/argo-cd -n argocd -f values.yaml
시간이 생각보다 오래걸린다. 기다린 후 설치가 완료된 것으로 확인하였다.
여기서는 포트프워딩을 진행하여 확인하라고 안내하지만, 이미 values.yaml을 통해서 원하는 값으로 overlay하여 nodeport:33080 포트로 지정하였기 때문에 {node ip}:33080 으로 접속한다.
아래와 같이 argocd 화면이 보인다.
- argocd 비밀번호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
- 설치 확인 & 접속 확인
Application Helm Chart로 생성해보기
- helm chart 생성
helm create hellospring
- 파일 구조
hellospring-helm/
├── Chart.yaml
├── values.yaml
├── charts/
└── templates/
├── deployment.yaml
├── service.yaml
├── ingress.yaml
└── _helpers.tpl
- Chart.yaml
apiVersion: v2
name: hellospring
description: A Helm chart for deploying a Spring Boot application
type: application
version: 0.1.0
appVersion: "1.0" # 애플리케이션의 버전
keywords:
- spring
- boot
- java
sources:
- https://github.com/suhyeonXYZ/hellospring
dependencies:
- name: ingress-nginx
version: ">=3.6.0"
repository: "https://kubernetes.github.io/ingress-nginx"
- values.yaml
replicaCount: 1
image:
repository: suhyeonsong/hellospring
pullPolicy: Always
tag: latest
service:
type: ClusterIP
port: 3000 # 컨테이너 포트를 3000으로 설정
ingress:
enabled: true
path: /hello
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # URL 재작성 설정
- /templates/_helpers.tpl
{{/*
Generate the full name of the release.
*/}}
{{- define "hellospring.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Generate the name of the application.
*/}}
{{- define "hellospring.name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
- /template/Deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "hellospring.fullname" . }}
labels:
app: backend
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "hellospring.name" . }}
template:
metadata:
labels:
app: backend
spec:
containers:
- name: {{ include "hellospring.name" . }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- name: http
containerPort: 3000 # 포트 3000으로 설정
resources:
{}
- /template/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "hellospring.fullname" . }}
labels:
app: backend
spec:
type: {{ .Values.service.type }}
ports:
- port: 3000
targetPort: 3000
selector:
app: backend
- /template/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "hellospring.fullname" . }}
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: {{ .Values.ingress.path }}
pathType: Prefix
backend:
service:
name: {{ include "hellospring.fullname" . }}
port:
number: {{ .Values.service.port }}
- 종속성 업데이트
ingress가 종속성으로 있기 때문에, 아래 명령어로 charts/ 하위 디렉토리에 종속성을 다운한다.
helm dependency update .
아래와 같이 nginx tgz 가 생긴 것을 볼 수 있다.
- 문법 확인
helm lint .
- 배포 시 생성되는 오브젝트 설정 확인
helm template .
- Chart 패키징
helm package hellospring/
hellospring-0.1.0.tgz 로 패키징 된다.
- index.yaml 생성(이게 없으면 chart로 인식하지 못한다.)
index.yaml은 아래 charts 정보가 있기 때문에 자동으로 생성된다.
helm repo index . --url {{github pages 주소}}
아래와 같이 파일 정보를 기반한 index가 생성된다.
- git charts관리를 위한 repository 생성
$ git checkout -b release
$ git push --set-upstream origin release
$ git add .
$ git commit -m "helm for hellospring"
$ git push
위의 과정을 모두 진행하면, 최종 파일 구조는 아래와 같다.
➜ hellospring-helm git:(release) tree
.
├── README.md
├── hellospring-0.1.0.tgz
├── hellospring-helm
│ ├── Chart.lock
│ ├── Chart.yaml
│ ├── charts
│ │ └── ingress-nginx-4.11.3.tgz
│ ├── templates
│ │ ├── Deployment.yaml
│ │ ├── _helpers.tpl
│ │ ├── ingress.yaml
│ │ └── service.yaml
│ └── values.yaml
└── index.yaml
생성된 Chart로 hellospring 프로젝트 설치
- helm repo를 호스팅하려면 git repository를 Pages로 호스팅한다.
아래와 같이, repository의 setting-pages에서 Branch - release 선택 후 save 버튼을 누르면, 상단 호스팅되는 페이지가 보인다.
현재는 그냥 readme 만 보이는 페이지이다.
- Chart Repository 추가
helm repo add hellospring https://github.com/suhyeonXYZ/hellospring-helm
helm repo update
정상적으로 helm repo가 등록된 것을 알 수 있다.
- Chart 배포
helm install hellospring hellospring/hellospring
정상적으로 설치되었다.
정상적으로 설치가 된 것을 볼 수 있다.
배포 업데이트
# Helm Chart 업그레이드
helm upgrade <release-name> ./hellospring
TroubleShooting
- helm 삭제
helm uninstall [RELEASE_NAME] -n [NAMESPACE
- Deployment.apps "hellospring-hellospring" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"backend"}:
selector
does not match templatelabels
무조건 변수사용해야하는 것 같음
'사이드 프로젝트' 카테고리의 다른 글
[CI/CD 프로젝트] API gateway의 도입 배경과 역할 (0) | 2024.11.20 |
---|---|
[CI/CD 프로젝트] Ingress 를 통한 외부 트래픽 관리 (0) | 2024.11.20 |
[CI/CD 프로젝트] Kustomize 사용하여 다양한 환경에서 쉽게 배포하기 (0) | 2024.11.19 |
[CI/CD 프로젝트] K8S - Calico 내부 동작 이해 (0) | 2024.11.19 |
[CI/CD 프로젝트] K8S - kubeadm으로 Kubernetes Cluster 구축하기 (0) | 2024.11.19 |