CI/CD Study 2주차 Helm
가시다님이 운영하시는 CI/CD Study 2주차 내용을 정리한 게시글 입니다.
1. Helm
✅ Helm 이란?
Helm은 Kustomize와 유사하지만 Template 기반 Package Manager 입니다.
Kustomize와 다르게 Chart, Release, Repository 개념으로 구성 됩니다.
- Chart
- k8s Application을 구성하는데 필요한 모든 리소스를 정의한 내용과 Template, 설정값(values.yaml), Metadata를 포함한 Package 형식이며 재사용 및 공유가 가능합니다.
- Release
- Chart를 이용하여 k8s Cluster에 설치된 실제 Instance를 의미합니다. 동일한 Chart를 여러번 설치하는 경우, 고유한 이름을 가진 별도의 Release가 생성되어 독립적으로 관리됩니다.
Repository
- Chart를 저장하고 공유하는 공간입니다. Container Repository와 비슷한 개념으로, Container 대신 Chart를 저장하고 공유합니다.
Helm은 Chart라는 Template와 Values.yaml이라는 설정 파일을 분리하여 적동합니다.
Chart에는 Deployment, Service와 같은 k8s Resource yaml파일이 템플릿 형태로 구성되어있습니다.
values.yaml파일에 각 환경(개발,검증,운영)과 같은 환경별로 변수 값을 정의하고 helm install, helm upgrade 명령어를 수행하게 되면 values.yaml파일의 값이 Chart에 주입되어 k8s manifest 파일로 생성이 되고 생성된 결과물을 k8s API Server로 보내 Application을 배포하거나 업데이트 합니다.
k8s 에서 Application을 운영하는 경우 ConfigMap이 변경될 때 자동으로 Rolling Update가 진행되지 않는데 Helm은 ConfigMap이 변경되도 Rolling Update가 진행되는 기능을 제공합니다.
Helm Project 생성하기
간단하게 Helm Project를 생성하면서 Helm Chart에 대한 구조를 이해해보겠습니다.
기본적으로, Helm은 관련된 Manifest 파일들을 Bundle로 묶어 하나의 Chart로 Packaging을 수행합니다.
kind를 이용하여 실습 환경을 구성해보겠습니다.
kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
- containerPort: 30001
hostPort: 30001
EOF
## 헬름 차트 디렉터리 레이아웃 생성
mkdir pacman
mkdir pacman/templates
cd pacman
## 루트 디렉터리에 차트 정의 파일 작성 : 버전, 이름 등 정보
cat << EOF > Chart.yaml
apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0 # 차트 버전, 차트 정의가 바뀌면 업데이트한다
appVersion: "1.0.0" # 애플리케이션 버전
EOF
## deployment.yaml 파일에서 템플릿화 : dp 이름, app 버전, replicas 수, 이미지/태그, 이미지 풀 정책, 보안 컨텍스트, 포트
cat << EOF > templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name}} # Chart.yaml 파일에 설정된 이름을 가져와 설정
labels:
app.kubernetes.io/name: {{ .Chart.Name}}
{{- if .Chart.AppVersion }} # Chart.yaml 파일에 appVersion 여부에 따라 버전을 설정
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} # appVersion 값을 가져와 지정하고 따움표 처리
{{- end }}
spec:
replicas: {{ .Values.replicaCount }} # replicaCount 속성을 넣을 자리 placeholder
selector:
matchLabels:
app.kubernetes.io/name: {{ .Chart.Name}}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name}}
spec:
containers:
- image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion}}" # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{- toYaml .Values.securityContext | nindent 14 }} # securityContext의 값을 YAML 객체로 지정하며 14칸 들여쓰기
name: {{ .Chart.Name}}
ports:
- containerPort: {{ .Values.image.containerPort }}
name: http
protocol: TCP
EOF
## service.yaml 파일에서 템플릿화 : service 이름, 컨테이너 포트
cat << EOF > templates/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
name: {{ .Chart.Name }}
spec:
ports:
- name: http
port: {{ .Values.image.containerPort }}
targetPort: {{ .Values.image.containerPort }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}
EOF
## 차트 기본값 default vales 이 담긴 파일 작성 : 애플리케이션 배포 시점에 다른 값으로 대체될 수 있는, 기본 설정을 담아두는 곳
cat << EOF > values.yaml
image: # image 절 정의
repository: quay.io/gitops-cookbook/pacman-kikd
tag: "1.0.0"
pullPolicy: Always
containerPort: 8080
replicaCount: 1
securityContext: {} # securityContext 속성의 값을 비운다
EOF
## SecuriyContext 값을 채우기 위해 toYaml 함수를 사용했기 때문에 Security 값을 사용시에는 다음과 같이 정의가 됩니다.
# securityContext:
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
## 디렉터리 레이아웃 확인
tree
# ├── Chart.yaml # 차트를 설명하며, 차트 관련 메타데이터를 포함
# ├── templates # 차트 설치에 사용되는 모든 템플릿 파일
# ├── deployment.yaml # 애플리케이션 배포에 사용되는 헬름 템플릿 파일들
# └── service.yaml
# └── values.yaml # 차트 기본값
생성된 Helm Chart를 Local에서 Yaml로 rendering 해보겠습니다.
# template 명령어를 이용하여 readering
helm template .
우선 순위는 cli에서 명시한 내용이 더 높기 때문에 다음과 같이 명시하게 되면 기본값을 재정의 할 수 있습니다.
# --set 파라미터를 사용하여 기본값을 재정의 한 yaml파일 확인
helm template --set replicaCount=3 .
저희가 생성한 Helm Chart 파일들을 이용해서 설치 ~ 삭제 실습을 해보겠습니다.
helm install pacman .
# NAME: pacman
# LAST DEPLOYED: Sat Oct 25 21:15:22 2025
# NAMESPACE: default
# STATUS: deployed
# REVISION: 1
# TEST SUITE: None
helm history pacman
# REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
# 1 Sat Oct 25 21:15:22 2025 deployed pacman-0.1.0 1.0.0 Install complete
# Helm 자체가 배포 릴리스 메타데이터를 저장하기 위해 자동으로 Sercet 리소스 생성 : Helm이 차트의 상태를 복구하거나 rollback 할 때 이 데이터를 이용
kubectl get secret
# NAME TYPE DATA AGE
# sh.helm.release.v1.pacman.v1 helm.sh/release.v1 1 56s
helm upgrade pacman --reuse-values --set replicaCount=2 .
# Release "pacman" has been upgraded. Happy Helming!
# NAME: pacman
# LAST DEPLOYED: Sat Oct 25 21:18:34 2025
# NAMESPACE: default
# STATUS: deployed
# REVISION: 2
# TEST SUITE: None
helm uninstall pacman
# release "pacman" uninstalled
Helm Chart 사용 시 재사용 항목 사용 하기
일반적으로 Deployment, Service 객체 배포 시 필드를 업데이트 하려고하면, Deployment의 Lables와 Selector, Service의 Selector를 수정해야하는데, Helm을 사용하게 되면 Code Block으로 재사용할 수 있습니다.
재사용을 하기위해서는 _heplers.tpl파일에 정의를 해서 재사용을 합니다.
## _helpers.tpl 파일 작성
cat << EOF > templates/_helpers.tpl
{{- define "pacman.selectorLabels" -}} # stetement 이름을 정의
app.kubernetes.io/name: {{ .Chart.Name}} # 해당 stetement 가 하는 일을 정의
{{- end }}
EOF
## deployment.yaml 수정
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "pacman.selectorLabels" . | nindent 6 }} # pacman.selectorLabels를 호출한 결과를 6만큼 들여쓰기하여 주입
template:
metadata:
labels:
{{- include "pacman.selectorLabels" . | nindent 8 }} # pacman.selectorLabels를 호출한 결과를 8만큼 들여쓰기하여 주입
## service.yaml 수정
selector:
{{- include "pacman.selectorLabels" . | nindent 6 }}
# 변경된 차트를 로컬에서 YAML 렌더링 : _helpers.tpl 설정된 값으로 갱신 확인
helm template .
# _helpers.tpl 파일 수정 : 새 속성 추가
cat << EOF > templates/_helpers.tpl
{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name}}
app.kubernetes.io/version: {{ .Chart.AppVersion}}
{{- end }}
EOF
# 변경된 차트를 로컬에서 YAML 렌더링 : _helpers.tpl 설정된 값으로 갱신 확인
helm template .
Helm을 이용한 Application Upgrade
helm upgrade 명령어를 시용하여 배포되어 실행하고 있는 instance를 upgrade 해보겠습니다.
# values.yaml 에 이미지 태그 업데이트
cat << EOF > values.yaml
image:
repository: quay.io/gitops-cookbook/pacman-kikd
tag: "1.1.0"
pullPolicy: Always
containerPort: 8080
replicaCount: 1
securityContext: {}
EOF
# Chart.yaml 파일에 appVersion 필드 갱신
cat << EOF > Chart.yaml
apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0
appVersion: "1.1.0"
EOF
helm upgrade pacman .
# Release "pacman" has been upgraded. Happy Helming!
# NAME: pacman
# LAST DEPLOYED: Sat Oct 25 21:44:23 2025
# NAMESPACE: default
# STATUS: deployed
# REVISION: 2
# TEST SUITE: None
helm history pacman
# REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
# 1 Sat Oct 25 21:43:13 2025 superseded pacman-0.1.0 1.0.0 Install complete
# 2 Sat Oct 25 21:44:23 2025 deployed pacman-0.1.0 1.1.0 Upgrade complete
이전 버전으로 롤백도 해보겠습니다.
# 이전 버전으로 롤백
helm rollback pacman 1
# Rollback was a success! Happy Helming!
helm history pacman
# REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
# 1 Sat Oct 25 21:43:13 2025 superseded pacman-0.1.0 1.0.0 Install complete
# 2 Sat Oct 25 21:44:23 2025 superseded pacman-0.1.0 1.1.0 Upgrade complete
# 3 Sat Oct 25 21:50:43 2025 deployed pacman-0.1.0 1.0.0 Rollback to 1
values yaml 파일을 override를 해보겠습니다.
cat << EOF > newvalues.yaml
image:
tag: "1.2.0"
EOF
# template 명령 실행 시 새 values 파일 함께 전달 : 결과적으로 values.yaml 기본값을 사용하지만, image.tag 값은 override 함
helm template pacman -f newvalues.yaml .
# spec:
# containers:
# - image: "quay.io/gitops-cookbook/pacman-kikd:1.2.0" # 이미지 지정 placeholder, 이미지 태그가 있으면 넣고, 없으면 Chart.yaml에 값을 설정
# i
Helm Chart Packaging 및 Deploy
Helm Chart를 Packaging을 할 때 Helm Package 명령렁어를 사용하여 Public Repository에 배포해보겠습니다.
helm package .
# Successfully packaged chart and saved it to: /home/duswn916/pacman/pacman-0.1.0.tgz
# 차트 저장소는 차트 및 .tgz 차트에 대한 메타데이터 정보를 담은 index.html 파일이 있는 HTTP 서버입니다.
## index.html 파일 생성
helm repo index .
cat index.yaml
# apiVersion: v1
# entries:
# pacman:
# - apiVersion: v2
# appVersion: 1.1.0
# created: "2025-10-25T22:15:11.964990983+09:00"
# description: A Helm chart for Pacman
# digest: e07bb70b1b7a2637882a0e4ced990568daeda6fffdd7ab212942cf391c4c05b7
# name: pacman
# type: application
# urls:
# - pacman-0.1.0.tgz
# version: 0.1.0
# generated: "2025-10-25T22:15:11.963870047+09:00"
Helm Chart를 Repository에 배포
repo add 명령어를 사용하여 remote Repository를 추가하고 install 명령어를 사용하여 배포해보겠습니다.
# repository 추가
helm repo add bitnami https://charts.bitnami.com/bitnami
# 배포
helm install my-db \
--set postgresql.postgresqlUsername=my-default,postgresql.postgresqlPassword=postgres,postgresql.postgresqlDatabase=mydb,postgresql.persistence.enabled=false \
bitnami/postgresql
# 배포 확인
helm list
# NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
# my-db default 1 2025-10-25 22:31:24.32356331 +0900 KST deployed postgresql-18.1.1 18.0.0
# pacman default 3 2025-10-25 21:50:43.790544871 +0900 KST deployed pacman-0.1.0 1.0.0
# 실습 후 삭제
helm uninstall my-db
다른 차트를 의존성으로 사용하는 Chart 배포 해보기
PostgreSQL 데이터베이스에 저장된 노래 목록을 반환하는 Java 서비스를 Helm Chart를 사용해서 배포해보겠습니다.
cd ..
mkdir -p music/templates
cd music
cat << EOF > templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name}}
labels:
app.kubernetes.io/name: {{ .Chart.Name}}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ .Chart.Name}}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name}}
spec:
containers:
- image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion}}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
name: {{ .Chart.Name}}
ports:
- containerPort: {{ .Values.image.containerPort }}
name: http
protocol: TCP
env:
- name: QUARKUS_DATASOURCE_JDBC_URL
value: {{ .Values.postgresql.server | default (printf "%s-postgresql" ( .Release.Name )) | quote }}
- name: QUARKUS_DATASOURCE_USERNAME
value: {{ .Values.postgresql.postgresqlUsername | default (printf "postgres" ) | quote }}
- name: QUARKUS_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.postgresql.secretName | default (printf "%s-postgresql" ( .Release.Name )) | quote }}
key: {{ .Values.postgresql.secretKey }}
EOF
cat << EOF > templates/service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
name: {{ .Chart.Name }}
spec:
ports:
- name: http
port: {{ .Values.image.containerPort }}
targetPort: {{ .Values.image.containerPort }}
selector:
app.kubernetes.io/name: {{ .Chart.Name }}
EOF
# Chart Metadata 등록
cat << EOF > Chart.yaml
apiVersion: v2
name: music
description: A Helm chart for Music service
type: application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
version: 18.0.17 # book 10.16.2
repository: "https://charts.bitnami.com/bitnami"
EOF
cat << EOF > values.yaml
image:
repository: quay.io/gitops-cookbook/music
tag: "1.0.0"
pullPolicy: Always
containerPort: 8080
replicaCount: 1
postgresql:
server: jdbc:postgresql://music-db-postgresql:5432/mydb
postgresqlUsername: my-default
postgresqlPassword: postgres
postgresqlDatabase: mydb
secretName: music-db-postgresql
secretKey: postgresql-password
EOF
# tree
├── Chart.yaml
├── templates
├── deployment.yaml
└── service.yaml
└── values.yaml
# 의존성으로 선언된 차트를 다운로드하여 차트 디렉터리에 저장
helm dependency update
tree
# ├── Chart.lock
# ├── Chart.yaml
# ├── charts
# └── postgresql-18.0.17.tgz
# ├── templates
# ├── deployment.yaml
# └── service.yaml
# └── values.yaml
# 차트 배포
helm install music-db .
# NAME: music-db
# LAST DEPLOYED: Sat Oct 25 23:07:23 2025
# NAMESPACE: default
# STATUS: deployed
# REVISION: 1
# TEST SUITE: None
# 실습정리
helm uninstall pacman
helm uninstall music-db
'DevOps > Study' 카테고리의 다른 글
| CI/CD Study 3주차 Jenkins, ArgoCD (0) | 2025.11.02 |
|---|---|
| CI/CD Study 2주차 Cloud Native CI/CD (1) | 2025.10.26 |
| CI/CD Study 1주차 Image Build (0) | 2025.10.19 |
| MinIO Study 3주차 PBAC, LDAP (0) | 2025.09.27 |
| MinIO Study 2주차 Performance & Warp (0) | 2025.09.20 |