Helm Chart 개발 실습 (기본)
Helm Chart의 기본 구조를 이해했다면, 이제 간단한 웹 애플리케이션을 실제 Kubernetes 클러스터에 배포하면서 Chart를 작성하고 관리하는 방법을 살펴보겠습니다.
이 장에서는 다음 과정을 단계별로 실습합니다.
templates/디렉토리 구성- Deployment, Service, Ingress 템플릿 작성
values.yaml을 이용한 설정 관리- Chart 패키징
- Chart 설치 및 배포
- Helm Release 상태 확인
- Release 업그레이드와 롤백
예제에서는 NGINX 기반의 간단한 웹 애플리케이션을 사용합니다.
1.1 간단한 웹 애플리케이션 Helm Chart 만들기#
Helm Chart는 Kubernetes 리소스를 템플릿으로 정의하고, 환경별 설정을 values.yaml 등의 값으로 분리하여 재사용할 수 있도록 구성합니다.
실습을 위해 다음과 같은 Chart 구조를 사용합니다.
my-web-app/
├── Chart.yaml
├── values.yaml
├── charts/
└── templates/
├── deployment.yaml
├── service.yaml
├── ingress.yaml
└── _helpers.tpl실제 Chart를 처음부터 만들 때는 helm create 명령어를 이용해 기본 구조를 생성할 수도 있습니다.
helm create my-web-appHelm 공식 권장 사항에서도 helm create를 이용하면 기본적인 템플릿과 헬퍼 구조를 빠르게 구성할 수 있습니다.
1.1.1 templates/ 디렉토리 구조 설계#
templates/ 디렉토리는 Kubernetes 리소스를 생성하기 위한 Helm 템플릿을 저장하는 곳입니다.
각 리소스는 일반적으로 별도의 YAML 파일로 관리합니다. Helm 공식 Best Practices에서도 리소스별로 템플릿 파일을 분리하고, YAML을 생성하는 파일에는 .yaml, 재사용 가능한 템플릿 정의에는 .tpl 확장자를 사용하는 방식을 권장합니다.
templates/
├── deployment.yaml # Deployment 정의
├── service.yaml # Service 정의
├── ingress.yaml # Ingress 정의
└── _helpers.tpl # 재사용 가능한 템플릿 정의각 파일의 역할은 다음과 같습니다.
deployment.yaml: 애플리케이션 컨테이너와 Pod의 배포 방식을 정의합니다.service.yaml: Pod에 안정적으로 접근할 수 있도록 Service를 정의합니다.ingress.yaml: HTTP/HTTPS 기반 외부 접근이 필요한 경우 Ingress를 정의합니다._helpers.tpl: 이름, 레이블 등 여러 템플릿에서 반복적으로 사용하는 값을 정의합니다.
_helpers.tpl에 정의한 템플릿은 Chart 전체에서 재사용할 수 있으므로 리소스 이름과 레이블을 일관되게 관리하는 데 유용합니다.
특히 Kubernetes에서는 다음과 같은 표준 레이블을 사용하는 것이 권장됩니다.
app.kubernetes.io/name
app.kubernetes.io/instance
app.kubernetes.io/managed-by
app.kubernetes.io/version
helm.sh/chartHelm 공식 Best Practices에서도 이러한 표준 레이블을 권장하고 있습니다.
1.1.2 Deployment, Service, Ingress 템플릿 작성#
이제 templates/ 디렉토리에 Kubernetes 리소스 템플릿을 작성합니다.
1.1.2.1 Deployment 템플릿 (templates/deployment.yaml)#
다음은 기본적인 Deployment 템플릿입니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-web-app.fullname" . }}
labels:
{{- include "my-web-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "my-web-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-web-app.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- toYaml .Values.env | nindent 12 }}주요 표현은 다음과 같습니다.
.Release.Name: 현재 설치된 Release의 이름입니다..Chart.Name: Chart의 이름입니다..Values:values.yaml에서 정의한 설정값에 접근합니다..Values.replicaCount: Pod 복제본 수를 지정합니다..Values.image.repository: 사용할 컨테이너 이미지 저장소를 지정합니다..Values.image.tag: 컨테이너 이미지 태그를 지정합니다..Values.service.targetPort: 컨테이너가 사용하는 포트를 지정합니다.toYaml: YAML 형태의 값을 템플릿에 삽입할 수 있도록 변환합니다.nindent: 지정된 공백만큼 들여쓰기를 적용하면서 줄바꿈을 처리합니다.
기존 예제에서 사용한 indent보다 nindent를 사용하는 방식이 템플릿의 들여쓰기와 YAML 구조를 관리하기에 편리합니다. Helm 공식 템플릿 가이드에서도 YAML을 생성할 때 적절한 들여쓰기와 whitespace 처리를 중요하게 다룹니다.
1.1.2.2 Service 템플릿 (templates/service.yaml)#
Service는 Deployment가 생성한 Pod에 안정적으로 접근할 수 있는 네트워크 엔드포인트를 제공합니다.
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-web-app.fullname" . }}
labels:
{{- include "my-web-app.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "my-web-app.selectorLabels" . | nindent 4 }}주요 설정은 다음과 같습니다.
service.type: Service 유형을 지정합니다.service.port: Service가 외부에 제공하는 포트입니다.service.targetPort: 실제 Pod의 컨테이너가 사용하는 포트입니다.selector: Service가 연결할 Pod를 선택합니다.
예를 들어 다음과 같이 설정할 수 있습니다.
service:
type: ClusterIP
port: 80
targetPort: 80ClusterIP를 사용하는 경우 Service는 기본적으로 클러스터 내부에서 접근할 수 있습니다.
1.1.2.3 Ingress 템플릿 (templates/ingress.yaml)#
외부에서 HTTP 또는 HTTPS를 통해 애플리케이션에 접근해야 하는 경우 Ingress를 사용할 수 있습니다.
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-web-app.fullname" . }}
labels:
{{- include "my-web-app.labels" . | nindent 4 }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- toYaml .Values.ingress.tls | nindent 4 }}
{{- end }}
rules:
- host: {{ .Values.ingress.host | quote }}
http:
paths:
- path: {{ .Values.ingress.path }}
pathType: Prefix
backend:
service:
name: {{ include "my-web-app.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}주요 설정은 다음과 같습니다.
.Values.ingress.enabled: Ingress 사용 여부를 결정합니다..Values.ingress.className: 사용할 Ingress Controller의 클래스를 지정할 수 있습니다..Values.ingress.host: 애플리케이션에 연결할 호스트 이름입니다..Values.ingress.path: HTTP 요청 경로입니다..Values.ingress.tls: HTTPS를 위한 TLS 설정입니다.
Ingress Controller가 실제로 클러스터에 설치되어 있어야 Ingress를 통해 외부 요청을 처리할 수 있습니다.
1.1.3 _helpers.tpl을 이용한 공통 템플릿 관리#
여러 리소스에서 동일한 이름과 레이블을 반복해서 작성하는 대신 _helpers.tpl에 공통 템플릿을 정의할 수 있습니다.
{{/*
Expand the name of the chart.
*/}}
{{- define "my-web-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "my-web-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name (include "my-web-app.name" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{/*
Common labels.
*/}}
{{- define "my-web-app.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
app.kubernetes.io/name: {{ include "my-web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels.
*/}}
{{- define "my-web-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}이처럼 이름과 레이블을 공통 템플릿으로 관리하면 Deployment, Service, Ingress 등 여러 리소스에서 동일한 규칙을 사용할 수 있습니다.
또한 템플릿 이름에는 Chart 이름을 포함하여 네임스페이스를 명확하게 하는 것이 좋습니다. Helm 공식 Best Practices에서도 정의된 템플릿 이름을 네임스페이스화하는 방식을 권장합니다.
1.1.4 values.yaml 설정 값 관리#
values.yaml은 Chart에서 사용하는 기본 설정값을 정의하는 파일입니다.
사용자는 values.yaml의 기본값을 그대로 사용하거나 별도의 values 파일 또는 --set 등의 명령줄 옵션을 이용하여 값을 변경할 수 있습니다.
예제는 다음과 같습니다.
# replicaCount is the number of application Pod replicas.
replicaCount: 3
# nameOverride overrides the chart name.
nameOverride: ""
# fullnameOverride overrides the generated full resource name.
fullnameOverride: ""
# image configures the container image.
image:
repository: nginx
tag: "1.29"
pullPolicy: IfNotPresent
# service configures the Kubernetes Service.
service:
type: ClusterIP
port: 80
targetPort: 80
# resources defines CPU and memory requests and limits.
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# ingress configures HTTP/HTTPS external access.
ingress:
enabled: false
className: ""
host: my-app.example.com
path: /
tls: []
# env defines container environment variables.
env:
- name: MY_ENV_VAR
value: my-value주요 설정값은 다음과 같습니다.
replicaCount: 실행할 Pod의 복제본 수image.repository: 컨테이너 이미지 저장소image.tag: 컨테이너 이미지 버전image.pullPolicy: 이미지 Pull 정책service.type: Kubernetes Service 유형service.port: Service 포트service.targetPort: 컨테이너 포트resources.requests: 컨테이너가 요청하는 CPU와 메모리resources.limits: 컨테이너가 사용할 수 있는 CPU와 메모리의 최대값ingress.enabled: Ingress 활성화 여부ingress.host: 외부 접근에 사용할 호스트env: 컨테이너 환경 변수
values.yaml의 설정값은 가능하면 명확하게 문서화하는 것이 좋습니다. Helm Best Practices에서도 정의된 각 속성에 대한 설명을 작성하는 것을 권장합니다.
1.2 Helm Chart 패키징 및 배포#
Chart를 작성한 후에는 helm lint, helm template 등을 이용하여 Chart를 검증한 다음 패키징하거나 직접 설치할 수 있습니다.
실무에서는 단순히 .tgz 파일을 만드는 것뿐만 아니라 OCI 기반 레지스트리 또는 전통적인 Chart Repository를 이용하여 Chart를 배포하는 방식도 많이 사용합니다. Helm 4에서는 OCI 레지스트리 지원이 더욱 강화되었습니다.
1.2.1 Chart 검증#
패키징하기 전에 먼저 Chart에 문제가 없는지 확인합니다.
helm lint my-web-app템플릿을 실제 Kubernetes API 서버에 적용하지 않고 렌더링 결과만 확인하려면 다음과 같이 사용할 수 있습니다.
helm template my-release ./my-web-app디버깅 정보를 포함하려면 다음과 같이 실행합니다.
helm template my-release ./my-web-app --debug실제 클러스터에 설치하기 전에 렌더링된 Kubernetes YAML을 확인하는 것은 Chart 오류를 조기에 발견하는 데 유용합니다.
1.2.2 Chart 패키징 (helm package)#
helm package는 Chart 디렉토리를 버전이 포함된 .tgz 파일로 패키징합니다.
helm package <Chart 디렉토리 경로> [옵션]예를 들어 다음과 같이 실행할 수 있습니다.
helm package my-web-appChart의 버전이 0.1.0이라면 다음과 같은 파일이 생성됩니다.
my-web-app-0.1.0.tgz특정 디렉토리에 저장하려면 다음과 같이 합니다.
helm package my-web-app --destination ./packagesChart 버전을 지정하여 패키징할 수도 있습니다.
helm package my-web-app --version 1.0.0애플리케이션 버전은 다음과 같이 지정할 수 있습니다.
helm package my-web-app --app-version 1.2.3version은 Chart 자체의 버전이고 appVersion은 Chart가 배포하는 애플리케이션의 버전이라는 점을 구분해야 합니다.
1.2.3 Chart Repository 활용#
전통적인 Helm Chart Repository는 패키징된 .tgz 파일과 index.yaml을 이용하여 Chart를 제공합니다.
예를 들어 로컬 디렉토리를 다음과 같이 구성할 수 있습니다.
local-repo/
├── index.yaml
└── my-web-app-0.1.0.tgz먼저 Chart를 패키징합니다.
helm package my-web-app --destination ./local-repo그다음 index.yaml을 생성합니다.
helm repo index ./local-repoHTTP 서버 등을 통해 해당 디렉토리를 제공한다면 다음과 같이 Repository를 등록할 수 있습니다.
helm repo add local-repo http://localhost:8080등록된 Repository는 다음 명령으로 확인할 수 있습니다.
helm repo listRepository의 Chart 정보를 갱신합니다.
helm repo updateChart를 검색합니다.
helm search repo local-repo참고:
file://경로를 일반적인 원격 Chart Repository처럼 사용하는 방식보다는, 로컬 테스트에서는 Chart 디렉토리나.tgz파일을 직접 참조하고, 실제 배포 환경에서는 HTTP 기반 Chart Repository 또는 OCI 레지스트리를 사용하는 것이 이해하기 쉽습니다.
1.2.4 OCI 레지스트리를 이용한 Chart 배포#
최근 Helm에서는 OCI-compliant 레지스트리를 이용하여 Chart를 저장하고 배포할 수 있습니다.
예를 들어 OCI 레지스트리에서 Chart를 직접 설치할 수 있습니다.
helm install my-release oci://registry.example.com/charts/my-web-app특정 Chart 버전을 지정하려면 다음과 같이 합니다.
helm install my-release \
oci://registry.example.com/charts/my-web-app \
--version 1.0.0OCI 방식은 별도의 helm repo add 없이 레지스트리의 oci:// 주소를 직접 사용할 수 있다는 장점이 있습니다. Helm 공식 Quickstart에서도 OCI 레지스트리를 주요 Chart 배포 방식으로 소개하고 있습니다.
1.2.5 Chart 설치 (helm install)#
helm install은 Chart를 Kubernetes 클러스터에 설치하고 Release를 생성합니다.
helm install <Release 이름> <Chart 경로 또는 이름> [옵션]로컬 Chart 디렉토리를 직접 설치할 수 있습니다.
helm install my-release ./my-web-app패키징된 Chart를 설치할 수도 있습니다.
helm install my-release ./my-web-app-0.1.0.tgzChart Repository에서 설치하는 경우:
helm install my-release local-repo/my-web-app특정 네임스페이스에 설치하려면:
helm install my-release ./my-web-app \
--namespace my-namespace \
--create-namespace별도의 values 파일을 사용할 수도 있습니다.
helm install my-release ./my-web-app \
--values my-values.yaml특정 설정값만 변경하려면 --set을 사용할 수 있습니다.
helm install my-release ./my-web-app \
--set image.tag=1.2.3 \
--set replicaCount=5Helm은 Chart의 템플릿과 설정값을 이용하여 Kubernetes 매니페스트를 생성하고, 해당 리소스를 클러스터에 적용합니다. 생성된 배포 정보는 Release 단위로 관리됩니다.
1.3 Helm Release 관리#
Helm에서 Release는 특정 Chart를 특정 설정값으로 Kubernetes 클러스터에 설치한 하나의 배포 인스턴스를 의미합니다.
예를 들어 동일한 my-web-app Chart를 다음과 같이 여러 번 설치할 수 있습니다.
my-web-app
├── development
├── staging
└── production각각 서로 다른 Release로 관리할 수 있습니다.
Release 관리에서 자주 사용하는 명령은 다음과 같습니다.
helm list
helm status
helm history
helm get
helm upgrade
helm rollback
helm uninstallHelm 4 공식 명령 체계에서도 이러한 Release 관리 명령을 제공합니다.
1.3.1 Release 목록 확인 (helm list)#
현재 클러스터에 설치된 Release를 확인하려면 helm list를 사용합니다.
helm list특정 네임스페이스의 Release를 확인하려면:
helm list --namespace my-namespace모든 네임스페이스의 Release를 확인하려면:
helm list --all-namespaces1.3.2 Release 상태 확인 (helm status)#
특정 Release의 현재 상태를 확인하려면 helm status를 사용합니다.
helm status my-release특정 네임스페이스에 설치된 Release라면:
helm status my-release \
--namespace my-namespaceJSON 형식으로 출력하려면:
helm status my-release --output jsonRelease의 상태와 함께 관리되는 리소스를 확인할 수도 있습니다.
helm status my-release --show-resources주요 상태에는 다음과 같은 값이 사용됩니다.
deployed: 정상적으로 배포된 상태failed: 설치 또는 업그레이드에 실패한 상태pending-install: 설치가 진행 중인 상태pending-upgrade: 업그레이드가 진행 중인 상태pending-rollback: 롤백이 진행 중인 상태uninstalled: 삭제되었지만 Release 기록이 남아 있는 상태
1.3.3 Release 이력 확인 (helm history)#
Release의 revision 이력을 확인하려면 helm history를 사용합니다.
helm history my-release예를 들어 다음과 같은 이력이 나타날 수 있습니다.
REVISION STATUS CHART
1 superseded my-web-app-0.1.0
2 superseded my-web-app-1.0.0
3 deployed my-web-app-1.1.0Revision은 Release의 변경 이력을 추적하고 롤백할 대상을 선택할 때 사용합니다.
1.3.4 Release 업그레이드 (helm upgrade)#
helm upgrade는 기존 Release에 새로운 Chart 또는 설정값을 적용합니다.
helm upgrade <Release 이름> <Chart 경로 또는 이름> [옵션]예를 들어 새로운 Chart 버전을 사용하여 업그레이드할 수 있습니다.
helm upgrade my-release ./my-web-app-1.1.0.tgz네임스페이스를 지정하려면:
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--namespace my-namespace사용자 정의 values 파일을 적용하려면:
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--values my-values.yaml설정값을 직접 변경하려면:
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--set image.tag=1.2.3 \
--set replicaCount=5특정 Chart 버전을 지정하여 Repository 또는 OCI Chart를 업그레이드할 수도 있습니다.
helm upgrade my-release \
oci://registry.example.com/charts/my-web-app \
--version 1.1.0업그레이드가 완료될 때까지 리소스 상태를 확인하면서 기다리려면 --wait를 사용할 수 있습니다.
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--wait대기 시간을 지정하려면:
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--wait \
--timeout 5m실패 시 변경 사항을 되돌리는 동작이 필요한 경우 Helm 4에서는 --rollback-on-failure 옵션을 사용할 수 있습니다.
helm upgrade my-release \
./my-web-app-1.1.0.tgz \
--rollback-on-failureHelm 4의 업그레이드 명령은 Chart 디렉토리, 패키지 파일, Chart Repository의 Chart, URL 또는 OCI Chart 등을 대상으로 사용할 수 있습니다. 또한 --values, --set, --set-string, --set-file, --set-json 등의 방법으로 값을 변경할 수 있습니다.
1.3.5 Release 롤백 (helm rollback)#
업그레이드 후 문제가 발생하면 이전 Revision으로 Release를 되돌릴 수 있습니다.
helm rollback <Release 이름> <Revision>예를 들어 Revision 2로 롤백하려면:
helm rollback my-release 2롤백이 완료될 때까지 기다리려면:
helm rollback my-release 2 --wait시간 제한을 지정할 수도 있습니다.
helm rollback my-release 2 \
--wait \
--timeout 5m롤백할 Revision을 확인하려면 먼저 다음 명령을 사용하는 것이 좋습니다.
helm history my-release예를 들어 다음과 같은 Release 이력이 있다면:
REVISION STATUS
1 superseded
2 superseded
3 deployedRevision 2로 롤백할 경우:
helm rollback my-release 2Helm은 해당 Release의 이전 Revision을 기준으로 리소스를 복원하고 새로운 Revision을 생성합니다. 따라서 롤백했다고 해서 기존 Revision 번호가 삭제되는 것은 아닙니다.
1.3.6 Release 삭제 (helm uninstall)#
더 이상 필요하지 않은 Release는 helm uninstall로 삭제할 수 있습니다.
helm uninstall my-release특정 네임스페이스의 Release를 삭제하려면:
helm uninstall my-release \
--namespace my-namespaceRelease의 이력을 유지하면서 리소스만 삭제하려면 다음과 같이 할 수 있습니다.
helm uninstall my-release --keep-history이 경우 Release 기록이 남아 있으므로 이후 helm status 또는 Release 이력 등을 통해 과거 정보를 확인할 수 있습니다. Helm 공식 Quickstart에서도 --keep-history를 사용하면 삭제 이후에도 Release 기록을 유지할 수 있다고 설명합니다.
1.4 기본 실습 정리#
이번 장에서 작성한 Chart의 전체적인 흐름은 다음과 같습니다.
Helm Chart 작성
│
▼
values.yaml 작성
│
▼
templates 작성
│
▼
helm lint
│
▼
helm template
│
▼
helm package
│
▼
Chart 배포
┌────┴─────────────┐
▼ ▼
Chart Repository OCI Registry
└────┬─────────────┘
▼
helm install
│
▼
Release 생성
│
├── helm status
├── helm history
├── helm get
│
▼
helm upgrade
│
├── 정상 → 새로운 Revision
│
└── 문제 → helm rollbackHelm을 이용한 Kubernetes 애플리케이션 배포는 단순히 YAML 파일을 작성하는 것에서 끝나지 않습니다. Chart의 템플릿과 설정값을 분리하고, 이를 검증·패키징한 후 Release 단위로 설치, 업그레이드, 롤백하는 것이 핵심입니다.
특히 실무에서는 다음과 같은 흐름을 기본 작업 과정으로 이해하는 것이 좋습니다.
Chart 작성
→ 검증
→ 렌더링 확인
→ 패키징
→ 배포
→ Release 관리
→ 업그레이드
→ 필요 시 롤백