Helm은 Kubernetes 리소스를 차트(chart)라는 단위로 패키징하고, 값에 따라 매니페스트를 렌더링하며, 설치·업그레이드 이력을 관리하는 도구다. 차트는 단순한 YAML 묶음이라기보다 애플리케이션을 어떤 설정과 정책으로 배포할지 표현한 버전 있는 계약으로 볼 수 있다.
다만 Helm이 매니페스트를 만들어 준다고 배포가 자동으로 안전해지는 것은 아니다. 렌더링, Kubernetes API 검증, 실제 애플리케이션 확인, 되돌리기의 범위를 각각 나눠야 한다.

차트의 네 요소부터 구분한다
기본 차트는 다음 구조로 시작한다.
demo/
├── Chart.yaml
├── values.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── _helpers.tpl
└── charts/
Chart.yaml: 차트 이름과 버전, 의존성 같은 메타데이터values.yaml: 템플릿에 들어갈 기본값templates/: 값과 릴리스 정보를 조합해 Kubernetes 매니페스트를 만드는 템플릿charts/: 의존 차트를 내려받아 두는 위치
Chart.yaml의 version과 appVersion은 역할이 다르다.
apiVersion: v2
name: demo
type: application
version: 0.3.0
appVersion: "1.8.2"
version은 차트 패키지 자체의 버전이다. 템플릿이나 기본 정책만 바뀌어도 올릴 수 있다. appVersion은 차트가 담는 애플리케이션 버전을 설명하는 정보다. Helm은 appVersion을 자동으로 컨테이너 이미지 태그에 넣지 않는다. 템플릿에서 .Chart.AppVersion을 참조했을 때만 렌더링 결과에 반영된다.
이미지 태그를 명시적인 값으로 관리하려면 다음처럼 경계를 드러낼 수 있다.
# values.yaml
image:
repository: registry.example.com/team/demo
tag: "1.8.2"
# templates/deployment.yaml 중 일부
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
latest처럼 움직이는 태그보다 릴리스마다 고정된 태그나 digest를 쓰면 배포한 이미지를 추적하기 쉽다. values.yaml에는 비밀값을 평문으로 넣지 않는다. Git, 패키지, 렌더링 로그에 노출될 수 있기 때문이다.
values는 편리하지만 스키마 없는 설정 창구가 되기 쉽다
Helm은 차트 기본값, 별도 values 파일, --set 계열 옵션을 병합해 최종 값을 만든다. 환경별 차이는 values 파일로 나눌 수 있지만, 모든 Kubernetes 필드를 그대로 외부에 노출하면 차트 인터페이스가 불안정해진다.
좋은 values 항목은 사용자가 실제로 선택해야 하는 값에 집중한다.
- 이미지 저장소와 태그
- replica 수와 리소스 요청·제한
- Service와 Ingress의 필요한 옵션
- 애플리케이션 기능 플래그
- 조직이 허용한 범위의 보안 설정
반면 필수 라벨, 기본 보안 컨텍스트와 모니터링 규칙처럼 조직 표준으로 유지할 값은 템플릿과 정책 검증에 두는 편이 낫다. 이것은 모든 조직에 같은 답이 있는 규칙은 아니다. 플랫폼 팀과 애플리케이션 팀이 누가 어떤 값을 바꿀 수 있는지 합의하기 위한 설계 기준이다.
렌더링과 검증은 같은 단계가 아니다
차트를 배포하기 전에는 적어도 세 층을 나눠 본다.
helm lint ./demo
helm template demo ./demo -f values-dev.yaml > rendered.yaml
helm lint는 차트가 관례와 구조를 따르는지 확인하고, helm template은 로컬에서 템플릿을 렌더링한다. 여기서 생성된 YAML을 코드 리뷰하거나 정책 검사 도구에 넘길 수 있다.
하지만 로컬 helm template은 클러스터의 API 서버가 리소스를 실제로 받아들이는지 확인하지 않는다. 설치된 CRD, admission 정책, 권한, API 버전 지원 여부는 대상 클러스터와 맞닿아야 알 수 있다. 따라서 운영 전 검증은 보통 다음처럼 층을 쌓는다.
- 차트 구조와 템플릿 문법을 검사한다.
- 환경별 값으로 매니페스트를 렌더링하고 diff·정책 검사를 한다.
- 대상 Kubernetes 버전과 CRD를 갖춘 시험 환경에 적용한다.
- Pod가 Ready라는 사실뿐 아니라 애플리케이션의 핵심 경로를 확인한다.
이 단계들을 모두 거쳤다는 실험 결과를 이 글에서 주장하는 것은 아니다. 명령의 역할과 운영 경계를 설명하기 위한 흐름이다.
upgrade --install은 편리하지만 성공의 뜻을 정해야 한다
처음 설치와 이후 업그레이드를 같은 명령으로 다루려면 다음 형태를 쓸 수 있다.
helm upgrade --install demo ./demo \
--namespace demo \
--create-namespace \
-f values-prod.yaml \
--wait \
--timeout 10m
--wait는 관련 Kubernetes 리소스가 준비 상태에 도달하기를 제한 시간까지 기다린다. 그러나 이것이 비즈니스 기능, 데이터 마이그레이션과 외부 의존성이 모두 정상이라는 뜻은 아니다. readiness probe와 배포 후 확인 항목을 함께 설계해야 한다.
업그레이드 전에 다음 질문에 답할 수 있어야 한다.
- 새 이미지가 이전 설정과 데이터 형식을 읽을 수 있는가?
- readiness probe가 실제 트래픽을 받을 준비를 반영하는가?
- 실패했을 때 이전 애플리케이션이 새 DB 스키마와 함께 동작할 수 있는가?
- Hook이나 외부 API 호출처럼 매니페스트 밖의 변화가 있는가?
Helm 명령 하나가 무중단 배포를 보장하지 않는다. Deployment 전략, replica 수, probe, PodDisruptionBudget, 데이터 변경 방식이 함께 맞아야 한다.
rollback이 되돌리는 범위를 과신하지 않는다
릴리스 이력은 helm history로 보고, 이전 revision을 선택해 helm rollback을 실행할 수 있다.
helm history demo --namespace demo
helm rollback demo 3 --namespace demo --wait
Helm rollback은 선택한 revision의 릴리스 매니페스트와 설정으로 Kubernetes 리소스를 되돌리는 작업이다. 다음 항목까지 자동으로 원상 복구하지는 않는다.
- 이미 실행된 데이터베이스 마이그레이션
- PVC에 기록된 데이터
- 외부 시스템에 보낸 요청
- 되돌릴 수 없게 변경된 CRD 데이터
- Hook이 만든 부수 효과
따라서 롤백 가능성은 배포 전에 설계해야 한다. 데이터 변경은 전후 버전 호환성을 확보하거나 별도 복구 절차를 준비하고, Hook은 반복 실행과 실패 시 동작을 검토한다.
의존성은 Chart.lock으로 재현성을 남긴다
의존 차트는 Chart.yaml의 dependencies에 선언한다.
dependencies:
- name: redis
version: "20.11.5"
repository: "oci://registry.example.com/charts"
helm dependency build는 Chart.lock에 기록된 버전을 바탕으로 charts/를 재구성한다. 의존성을 바꿀 때는 helm dependency update로 잠금 파일을 갱신하고, Chart.yaml과 Chart.lock을 함께 리뷰한다.
버전 범위를 지나치게 넓게 열면 같은 소스에서 다른 의존 차트를 가져올 가능성이 커진다. 운영 차트는 검증한 버전을 명시하고, 공급망 정책에 따라 digest·서명·출처를 확인하는 절차를 더한다.
OCI 레지스트리도 차트 배포 경로가 된다
Helm 차트는 전통적인 차트 저장소뿐 아니라 OCI 레지스트리에 저장할 수 있다.
helm package ./demo
helm push demo-0.3.0.tgz oci://registry.example.com/team-charts
helm pull oci://registry.example.com/team-charts/demo --version 0.3.0
컨테이너 이미지와 차트를 같은 종류의 레지스트리에서 관리할 수 있지만, 두 아티팩트의 버전을 같게 만들어야 한다는 뜻은 아니다. 차트 버전과 애플리케이션 버전은 독립적으로 추적하고, 어떤 조합을 검증했는지 릴리스 메타데이터에 남기는 편이 명확하다.
GitOps에서는 Git의 선언 상태가 기준이다
Helm CLI로 직접 upgrade하면 클러스터 상태를 즉시 바꾼다. 반면 GitOps 컨트롤러가 Helm 차트를 렌더링하는 환경에서는 Git에 기록된 차트 버전과 values가 선언 상태다.
운영 클러스터에서 직접 Helm 명령으로만 수정하면 컨트롤러가 다시 Git 상태로 되돌리거나, Git과 실제 클러스터 사이에 추적하기 어려운 차이가 생길 수 있다. 긴급 변경이 필요해도 변경 기록, 승인, Git 반영과 reconcile 순서를 정해 두는 편이 낫다.
정적 YAML을 환경별로 조합하는 방식은 Kustomize 정리, Helm 결과를 지속적으로 맞추는 컨트롤러 흐름은 Argo CD 정리에서 이어서 볼 수 있다. Helm과 Kustomize 중 하나가 항상 우월한 것이 아니라, 패키지 인터페이스와 템플릿이 필요한지, 선언 상태를 어디에서 관리할지를 기준으로 고른다.
참고 자료
'배움과 성장 > DevOps·클라우드' 카테고리의 다른 글
| Argo CD GitOps 배포 실습: Helm·자동 동기화·Prune (0) | 2025.11.01 |
|---|---|
| Tekton CI와 GitOps CD 분리: Task·Pipeline·Trigger 학습노트 (0) | 2025.10.25 |
| Kustomize base·overlay 실전: patches와 configMapGenerator (0) | 2025.10.18 |
| 컨테이너 이미지 빌드 도구 비교: Docker·Jib·Buildpacks·Shipwright를 언제 쓸까 (0) | 2025.10.18 |
| macOS GitOps 실습 준비: kind 클러스터와 Docker Hub 이미지 푸시 (0) | 2025.10.18 |
댓글