1. Helm 3 아키텍처 개요
1.1 Helm 2에서 Helm 3로의 변화
Helm 2는 클러스터 내에 **Tiller**라는 서버 사이드 컴포넌트가 필요했습니다. Tiller는 클러스터 내에서 릴리스를 관리하고 차트를 배포하는 역할을 했지만, 보안상 심각한 문제가 있었습니다.
**Tiller의 문제점:**
- 기본적으로 cluster-admin 권한으로 실행
- gRPC 엔드포인트가 인증 없이 노출
- 멀티테넌트 환경에서 권한 분리가 불가능
- RBAC 우회의 원인
Helm 3에서는 Tiller가 완전히 제거되었습니다. 이제 Helm CLI가 직접 Kubernetes API 서버와 통신하며, kubeconfig의 인증 정보를 그대로 사용합니다.
1.2 클라이언트 전용 아키텍처
+------------------+ +---------------------+
| Helm CLI | ----> | Kubernetes API |
| (클라이언트) | | Server |
+------------------+ +---------------------+
| |
v v
+-----------+ +-----------+
| Chart | | Release |
| Repository| | Storage |
+-----------+ | (Secrets) |
+-----------+
Helm 3의 아키텍처는 단순합니다:
1. **Helm CLI**: 차트 렌더링, API 호출, 릴리스 관리를 모두 클라이언트에서 수행
2. **Kubernetes API Server**: 리소스 생성/수정/삭제의 실제 실행
3. **Release Storage**: 릴리스 메타데이터를 Secret 또는 ConfigMap으로 저장
1.3 보안 모델 개선
Helm 3는 kubeconfig의 컨텍스트를 그대로 사용
RBAC이 자연스럽게 적용됨
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: helm-deployer
namespace: production
rules:
- apiGroups: ['', 'apps', 'batch']
resources: ['deployments', 'services', 'configmaps', 'secrets']
verbs: ['get', 'list', 'create', 'update', 'patch', 'delete']
Helm 3에서는 사용자의 kubeconfig 컨텍스트가 그대로 적용되므로, Kubernetes RBAC을 통한 세밀한 권한 제어가 가능합니다.
2. 릴리스 저장소(Release Storage)
2.1 Secret 기반 저장
Helm 3는 릴리스 정보를 기본적으로 Kubernetes **Secret** 리소스에 저장합니다.
릴리스 Secret 조회
kubectl get secrets -l owner=helm -n default
Secret 이름 형식: sh.helm.release.v1.RELEASE_NAME.vREVISION
예: sh.helm.release.v1.my-app.v1
각 Secret에는 다음 정보가 gzip 압축 + base64 인코딩되어 저장됩니다:
- 차트 메타데이터 (Chart.yaml 내용)
- 렌더링된 매니페스트
- values (사용자가 제공한 값 + 기본값)
- 릴리스 상태 (deployed, failed, uninstalled 등)
- 릴리스 노트
2.2 ConfigMap 기반 저장
Secret 대신 ConfigMap을 사용할 수도 있습니다:
ConfigMap 드라이버 사용
export HELM_DRIVER=configmap
helm install my-app ./my-chart
2.3 저장 드라이버 비교
| 드라이버 | 장점 | 단점 |
| ------------- | ----------------------------------------- | ----------------------------- |
| secret (기본) | etcd 암호화 적용 가능, RBAC으로 접근 제한 | Secret 리소스 크기 제한 (1MB) |
| configmap | Secret 접근 권한 불필요 | 데이터가 평문 저장 |
| sql | 대규모 릴리스 관리 | 외부 DB 필요, 설정 복잡 |
| memory | 테스트용 | 영구 저장 불가 |
3. 차트 구조(Chart Structure)
3.1 기본 디렉터리 구조
my-chart/
Chart.yaml # 차트 메타데이터 (필수)
Chart.lock # 의존성 잠금 파일
values.yaml # 기본 설정값 (필수)
values.schema.json # values 스키마 검증
charts/ # 의존성 차트 (서브차트)
crds/ # CRD 매니페스트
templates/ # Go 템플릿 파일
deployment.yaml
service.yaml
ingress.yaml
_helpers.tpl # 네임드 템플릿 헬퍼
NOTES.txt # 릴리스 노트 템플릿
tests/ # 테스트 Pod 정의
test-connection.yaml
3.2 Chart.yaml 상세
apiVersion: v2 # Helm 3에서는 반드시 v2
name: my-application
description: A Helm chart for my application
type: application # application 또는 library
version: 1.2.3 # 차트 버전 (SemVer)
appVersion: '2.0.0' # 애플리케이션 버전
kubeVersion: '>=1.25.0' # 지원 Kubernetes 버전 범위
home: https://example.com
sources:
- https://github.com/example/my-app
maintainers:
- name: developer
email: dev@example.com
icon: https://example.com/icon.png
keywords:
- app
- web
annotations:
artifacthub.io/changes: |
- kind: added
description: Initial release
dependencies:
- name: postgresql
version: '12.x.x'
repository: 'https://charts.bitnami.com/bitnami'
condition: postgresql.enabled
tags:
- database
3.3 CRD 디렉터리
`crds/` 디렉터리에 있는 파일은 특별한 처리를 받습니다:
- install 시에만 적용되며, upgrade나 rollback에서는 무시됩니다
- 템플릿 렌더링이 적용되지 않습니다 (순수 YAML)
- uninstall 시에도 삭제되지 않습니다 (데이터 보호)
crds/my-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: myresources.example.com
spec:
group: example.com
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
scope: Namespaced
names:
plural: myresources
singular: myresource
kind: MyResource
4. 템플릿 엔진 기초
4.1 Go 템플릿 기본 문법
Helm은 Go의 `text/template` 패키지를 기반으로 하며, Sprig 라이브러리의 함수들을 추가로 제공합니다.
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: { { include "my-chart.fullname" . } }
labels: { { - include "my-chart.labels" . | nindent 4 } }
spec:
replicas: { { .Values.replicaCount } }
selector:
matchLabels: { { - include "my-chart.selectorLabels" . | nindent 6 } }
template:
metadata:
labels: { { - include "my-chart.selectorLabels" . | nindent 8 } }
spec:
containers:
- name: { { .Chart.Name } }
image: '{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}'
ports:
- containerPort: { { .Values.service.port } }
4.2 빌트인 객체(Built-in Objects)
Helm 템플릿에서 사용할 수 있는 주요 빌트인 객체:
| 객체 | 설명 |
| --------------- | ------------------------------------------------------------- |
| `.Release` | 릴리스 정보 (Name, Namespace, Revision, IsUpgrade, IsInstall) |
| `.Values` | values.yaml과 사용자 제공 값의 병합 결과 |
| `.Chart` | Chart.yaml의 내용 |
| `.Capabilities` | 클러스터 능력 정보 (API 버전, Kubernetes 버전) |
| `.Template` | 현재 템플릿 정보 (Name, BasePath) |
| `.Files` | 차트 내 파일 접근 |
.Release 객체 활용 예시
metadata:
annotations:
helm.sh/release-name: {{ .Release.Name }}
helm.sh/release-namespace: {{ .Release.Namespace }}
helm.sh/revision: {{ .Release.Revision | quote }}
.Capabilities 활용 예시
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
apiVersion: networking.k8s.io/v1
{{- else }}
apiVersion: networking.k8s.io/v1beta1
{{- end }}
4.3 Sprig 함수 예시
문자열 함수
name: {{ .Values.name | upper }} # 대문자 변환
name: {{ .Values.name | lower }} # 소문자 변환
name: {{ .Values.name | title }} # 타이틀 케이스
name: {{ .Values.name | trim }} # 공백 제거
name: {{ .Values.name | trunc 63 }} # 63자로 자르기
기본값 설정
image: {{ .Values.image.tag | default "latest" }}
조건부 필수값
name: {{ required "A name is required" .Values.name }}
인코딩
data: {{ .Values.secret | b64enc }}
날짜
timestamp: {{ now | date "2006-01-02T15:04:05Z07:00" }}
5. 의존성 관리(Dependency Management)
5.1 Chart.yaml에서 의존성 선언
Chart.yaml
dependencies:
- name: redis
version: '17.x.x'
repository: 'https://charts.bitnami.com/bitnami'
condition: redis.enabled
tags:
- cache
- name: postgresql
version: '12.x.x'
repository: 'https://charts.bitnami.com/bitnami'
condition: postgresql.enabled
tags:
- database
- name: common
version: '2.x.x'
repository: 'https://charts.bitnami.com/bitnami'
import-values:
- child: image
parent: defaultImage
5.2 Chart.lock 파일
의존성 다운로드 및 잠금 파일 생성
helm dependency update ./my-chart
Chart.lock이 이미 있는 경우 정확한 버전으로 빌드
helm dependency build ./my-chart
`Chart.lock` 파일은 재현 가능한 빌드를 보장합니다:
Chart.lock
dependencies:
- name: redis
repository: https://charts.bitnami.com/bitnami
version: 17.15.2
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 12.10.0
digest: sha256:abc123def456...
generated: '2026-03-20T10:00:00.000000000Z'
5.3 condition과 tags
**condition**: 특정 값이 true일 때만 서브차트를 활성화
values.yaml
redis:
enabled: true
postgresql:
enabled: false # PostgreSQL 서브차트 비활성화
**tags**: 태그 그룹 단위로 서브차트를 활성화/비활성화
values.yaml
tags:
cache: true # cache 태그가 붙은 모든 의존성 활성화
database: false # database 태그가 붙은 모든 의존성 비활성화
condition은 tags보다 우선순위가 높습니다.
5.4 서브차트 값 오버라이드
부모 차트의 values.yaml에서 서브차트 값 오버라이드
redis:
enabled: true
architecture: standalone
auth:
enabled: false
master:
persistence:
size: 1Gi
postgresql:
enabled: true
auth:
postgresPassword: 'my-password'
database: mydb
5.5 전역 값(Global Values)
values.yaml
global:
imageRegistry: myregistry.io
imagePullSecrets:
- name: my-pull-secret
storageClass: fast-ssd
`global` 아래의 값은 모든 서브차트에서 접근 가능합니다.
6. OCI 레지스트리 지원
6.1 OCI 기반 차트 관리
Helm 3.8부터 OCI 레지스트리 지원이 GA(Generally Available)입니다:
레지스트리 로그인
helm registry login registry.example.com
차트를 OCI 아티팩트로 패키징 및 푸시
helm package ./my-chart
helm push my-chart-1.0.0.tgz oci://registry.example.com/charts
OCI 레지스트리에서 차트 설치
helm install my-release oci://registry.example.com/charts/my-chart --version 1.0.0
차트 정보 조회
helm show chart oci://registry.example.com/charts/my-chart --version 1.0.0
7. 정리
Helm 3의 아키텍처는 **보안**, **단순성**, **확장성**을 핵심 설계 원칙으로 합니다:
1. **Tiller 제거**: 클러스터 내 서버 컴포넌트 없이 CLI만으로 동작
2. **RBAC 네이티브**: kubeconfig 기반 인증/인가로 Kubernetes RBAC과 자연스럽게 통합
3. **Secret 기반 릴리스 저장**: etcd 암호화 지원, 릴리스 히스토리 관리
4. **구조화된 차트**: Chart.yaml, values.yaml, templates/ 등 명확한 관심사 분리
5. **OCI 레지스트리 지원**: 컨테이너 이미지와 동일한 인프라에서 차트 관리
다음 글에서는 Helm 템플릿 엔진의 내부 동작을 더 깊이 분석합니다.
현재 단락 (1/237)
Helm 2는 클러스터 내에 **Tiller**라는 서버 사이드 컴포넌트가 필요했습니다. Tiller는 클러스터 내에서 릴리스를 관리하고 차트를 배포하는 역할을 했지만, 보안상 심...