본문 바로가기
IT/k8s

[k8s] Helm 4.0 차트 관리 완벽 가이드: OCI 정식 지원과 실전 배포

by 수누다 2026. 4. 9.

Helm 4.0이 드디어 나왔습니다 — 근데 뭐가 달라진 거죠?

쿠버네티스(Kubernetes) 운영하면서 Helm(헬름, 쿠버네티스 패키지 매니저)을 안 쓰는 분이 계실까요? 저도 처음 k8s를 접했을 때 "이걸 왜 쓰는 거지?" 싶었는데, 지금은 Helm 없이는 진짜 아무것도 못 하겠더라고요. 그런데 얼마 전 Helm 4.0 릴리즈 소식을 접하고 나서 꽤 설렜습니다. 13년 동안 인프라 바닥을 기어다니면서 메이저 버전 업그레이드가 가져오는 변화가 얼마나 크고 때로는 얼마나 골치 아픈지 잘 알거든요.

이번 글에서는 Helm 4.0 쿠버네티스 차트 관리의 핵심 변경점부터 실전 설정 가이드, kubectl과의 통합 배포 방법까지 제가 직접 홈랩에서 굴려보면서 정리한 내용을 공유해 드릴게요. 삽질도 꽤 했습니다 ㅎㅎ 그 과정도 솔직하게 담았으니까 끝까지 읽어보세요.

Helm 4.0과 쿠버네티스 클러스터 전체 아키텍처 다이어그램 — Chart Repository, OCI Registry, kubectl 연동 구조

Helm 4.0과 쿠버네티스 클러스터의 전체 구성 관계 — Chart Repository, Helm CLI, kubectl, API Server가 어떻게 연결되는지 한눈에 볼 수 있습니다.


Helm이 뭔지 다시 한번 짚고 가겠습니다

쉽게 말해, Helm은 쿠버네티스의 apt/yum이라고 보시면 됩니다. 리눅스에서 패키지 하나 설치할 때 apt install nginx 한 줄이면 되잖아요? Helm도 마찬가지예요. 복잡한 쿠버네티스 리소스 묶음(Deployment, Service, ConfigMap, Ingress 등)을 Chart(차트)라는 단위로 패키징해서 한 번에 배포하고 관리할 수 있게 해줍니다.

핵심 개념 세 가지만 기억하세요:

  • Chart(차트): 쿠버네티스 리소스 템플릿의 묶음. 마치 앱 설치 패키지 같은 거예요.
  • Release(릴리즈): 차트를 실제 클러스터에 배포한 인스턴스. 같은 차트를 여러 번 배포하면 릴리즈가 여러 개 생깁니다.
  • Repository(레포지터리): 차트를 저장하고 배포하는 저장소. Docker Hub처럼 생각하시면 돼요.

Helm 3에서 Tiller(틸러, 서버 사이드 컴포넌트)가 제거된 게 엄청난 변화였는데, Helm 4.0은 또 다른 차원의 변화를 가져왔습니다.

Helm 3 vs Helm 4.0 주요 변경점 비교

항목 Helm 3 Helm 4.0
OCI 레지스트리 지원 실험적(Experimental) ✅ 정식 지원 (GA)
Go 템플릿 엔진 기본 Go template 개선된 템플릿 함수 추가
JSON Schema 검증 선택적 지원 강화된 values 검증
kubectl 통합 별도 설정 필요 네이티브 플러그인 방식
차트 의존성 관리 Chart.lock 기반 개선된 의존성 해석
보안 컨텍스트 수동 설정 기본값 강화

Helm 4.0 설치 및 초기 설정 가이드

자, 이제 본격적으로 손을 더럽혀 봅시다. 제가 홈랩에서 사용하는 환경은 Ubuntu 22.04 + k3s 클러스터인데, 일반 kubeadm 환경에서도 동일하게 적용됩니다.

1단계: Helm 4.0 설치

공식 스크립트로 설치하는 게 제일 편합니다. 버전 고정해서 설치하는 습관 들이세요 — 나중에 팀원들이랑 버전 맞출 때 훨씬 편하거든요.

# Helm 공식 설치 스크립트 다운로드 및 실행
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 특정 버전 지정 설치 (권장)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | DESIRED_VERSION=v4.0.0 bash

# 설치 확인
helm version
# 출력 예시: version.BuildInfo{Version:"v4.0.0", ...}

macOS 사용자라면 Homebrew로도 됩니다:

brew install helm
# 또는 특정 버전
brew install helm@4

2단계: 자동완성(Autocomplete) 설정

이거 설정 안 하는 분들 많은데, 진짜 꼭 하세요. 명령어 치다가 오타 나는 거 방지해줍니다.

# bash 자동완성
echo 'source <(helm completion bash)' >> ~/.bashrc
source ~/.bashrc

# zsh 자동완성
echo 'source <(helm completion zsh)' >> ~/.zshrc
source ~/.zshrc

3단계: 공식 레포지터리 추가

# Artifact Hub 기반 주요 레포지터리 추가
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# 레포지터리 목록 확인
helm repo list

# 레포지터리 인덱스 업데이트
helm repo update

💡 Helm 4.0 팁: OCI(Open Container Initiative) 레지스트리가 이제 정식 지원되니까, Docker Hub나 Harbor 같은 컨테이너 레지스트리에서 직접 차트를 pull할 수 있습니다.

# OCI 레지스트리에서 차트 직접 사용 (Helm 4.0 정식 지원)
helm pull oci://registry-1.docker.io/bitnamicharts/nginx
helm install my-nginx oci://registry-1.docker.io/bitnamicharts/nginx

Helm 차트 디렉토리 구조와 values.yaml이 쿠버네티스 템플릿에 주입되는 과정 다이어그램

Helm 차트의 디렉토리 구조와 values.yaml이 템플릿에 어떻게 주입되는지 보여주는 구성 다이어그램입니다.

나만의 Helm 차트 만들기 — 실전 예제

남의 차트 쓰는 것도 좋지만, 직접 만들어봐야 진짜 이해가 됩니다. 간단한 Node.js 앱을 배포하는 차트를 처음부터 만들어볼게요.

차트 스캐폴딩 생성

# 새 차트 생성
helm create my-nodeapp

# 생성된 구조 확인
tree my-nodeapp/
# my-nodeapp/
# ├── Chart.yaml          # 차트 메타데이터
# ├── values.yaml         # 기본 설정값
# ├── charts/             # 의존 차트 디렉토리
# └── templates/          # 쿠버네티스 리소스 템플릿
#     ├── deployment.yaml
#     ├── service.yaml
#     ├── ingress.yaml
#     ├── hpa.yaml
#     └── _helpers.tpl    # 헬퍼 템플릿

Chart.yaml 설정

# my-nodeapp/Chart.yaml
apiVersion: v2
name: my-nodeapp
description: Node.js 앱 배포용 Helm 차트
type: application
version: 0.1.0          # 차트 버전
appVersion: "1.0.0"     # 실제 앱 버전

# Helm 4.0: 의존성 선언
dependencies:
  - name: redis
    version: "17.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled

values.yaml 커스터마이징

이게 Helm의 핵심이에요. values.yaml(밸류즈 파일)에서 환경별로 다른 값을 주입하는 방식입니다.

# my-nodeapp/values.yaml
replicaCount: 2

image:
  repository: my-registry/my-nodeapp
  pullPolicy: IfNotPresent
  tag: "latest"

service:
  type: ClusterIP
  port: 3000

ingress:
  enabled: true
  className: nginx
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

# Redis 의존성 설정
redis:
  enabled: true
  auth:
    enabled: false

# Helm 4.0: 강화된 환경변수 관리
env:
  NODE_ENV: production
  PORT: "3000"

Deployment 템플릿 작성

# my-nodeapp/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-nodeapp.fullname" . }}
  labels:
    {{- include "my-nodeapp.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-nodeapp.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-nodeapp.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
          env:
            {{- range $key, $value := .Values.env }}
            - name: {{ $key }}
              value: {{ $value | quote }}
            {{- end }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          # Helm 4.0: 보안 컨텍스트 기본 강화
          securityContext:
            allowPrivilegeEscalation: false
            runAsNonRoot: true
            runAsUser: 1000

kubectl과 통합 배포 — 실무에서 이렇게 씁니다

혼자 개발할 때야 Helm CLI만 써도 되는데, 팀 환경이나 CI/CD 파이프라인에서는 kubectl과 Helm을 함께 쓰는 경우가 많습니다. 저도 처음엔 이 둘을 어떻게 조합해야 하나 헷갈렸거든요.

환경별 values 파일 분리 전략

# 디렉토리 구조
my-nodeapp/
├── Chart.yaml
├── values.yaml              # 기본값 (공통)
├── values-dev.yaml          # 개발 환경
├── values-staging.yaml      # 스테이징 환경
└── values-prod.yaml         # 프로덕션 환경
# values-prod.yaml (프로덕션 오버라이드)
replicaCount: 5

image:
  tag: "v1.2.3"  # 프로덕션은 latest 절대 금지!

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

ingress:
  hosts:
    - host: myapp.company.com
      paths:
        - path: /
          pathType: Prefix

배포 명령어 실전 레시피

# 1. 차트 문법 검증 (배포 전 필수!)
helm lint my-nodeapp/
helm lint my-nodeapp/ -f my-nodeapp/values-prod.yaml

# 2. 렌더링 결과 미리보기 (dry-run)
helm template my-nodeapp my-nodeapp/ \
  -f my-nodeapp/values-prod.yaml \
  --namespace production

# 3. 실제 배포 전 서버 사이드 검증
helm install my-nodeapp my-nodeapp/ \
  --dry-run \
  --debug \
  -f my-nodeapp/values-prod.yaml \
  --namespace production

# 4. 실제 배포
helm install my-nodeapp my-nodeapp/ \
  -f my-nodeapp/values-prod.yaml \
  --namespace production \
  --create-namespace \
  --wait \
  --timeout 5m

# 5. kubectl로 배포 상태 확인
kubectl get all -n production
kubectl rollout status deployment/my-nodeapp -n production

업그레이드와 롤백

이게 Helm의 진짜 강점입니다. 배포 히스토리를 관리하고, 문제 생기면 한 방에 롤백할 수 있거든요.

# 업그레이드 (없으면 설치, 있으면 업그레이드)
helm upgrade --install my-nodeapp my-nodeapp/ \
  -f my-nodeapp/values-prod.yaml \
  --namespace production \
  --atomic \
  --cleanup-on-fail

# 릴리즈 히스토리 확인
helm history my-nodeapp -n production

# 이전 버전으로 롤백
helm rollback my-nodeapp 1 -n production

# kubectl로 롤백 상태 확인
kubectl rollout status deployment/my-nodeapp -n production

💡 실무 팁: --atomic 옵션을 쓰면 배포가 실패했을 때 자동으로 이전 버전으로 롤백됩니다. CI/CD 파이프라인에서 이거 꼭 넣으세요.

Helm 자동배포 — GitHub Actions 연동 예시

# .github/workflows/deploy.yml
name: Helm 자동배포

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Helm 설치
        uses: azure/setup-helm@v3
        with:
          version: 'v4.0.0'
      
      - name: kubeconfig 설정
        run: |
          mkdir -p ~/.kube
          echo "${{ secrets.KUBECONFIG }}" > ~/.kube/config
      
      - name: Helm 차트 검증
        run: helm lint ./my-nodeapp -f ./my-nodeapp/values-prod.yaml
      
      - name: Helm 배포
        run: |
          helm upgrade --install my-nodeapp ./my-nodeapp \
            -f ./my-nodeapp/values-prod.yaml \
            --namespace production \
            --create-namespace \
            --atomic \
            --timeout 10m \
            --set image.tag=${{ github.sha }}

⚠️ 제가 삽질한 것들 — 트러블슈팅 모음

이 섹션이 제일 중요할 수도 있어요. 공식 문서에는 안 나오는 것들이거든요.

문제 1: "Error: INSTALLATION FAILED: cannot re-use a name that is still in use"

처음 배포할 때 실패하고 나서 다시 helm install 하면 이 에러 납니다. 이미 실패한 릴리즈가 남아있어서 그래요.

# 실패한 릴리즈 상태 확인
helm list -a -n production
# STATUS가 failed로 뜨는 릴리즈 확인

# 해결: 실패한 릴리즈 삭제 후 재설치
helm uninstall my-nodeapp -n production
helm install my-nodeapp my-nodeapp/ -f values-prod.yaml -n production

# 또는 upgrade --install 사용 (이게 더 나음)
helm upgrade --install my-nodeapp my-nodeapp/ -f values-prod.yaml -n production

문제 2: values.yaml의 시크릿 관리

values.yaml에 패스워드 같은 민감 정보 넣으면 절대 안 됩니다. Git에 올라가는 순간 끝이에요. 저도 초반에 이 실수 한 번 했습니다 ㅎㅎ (물론 내부망이라 다행이었지만...)

# helm-secrets 플러그인 설치 (SOPS 기반 암호화)
helm plugin install https://github.com/jkroepke/helm-secrets

# secrets.yaml 암호화
helm secrets enc secrets.yaml

# 암호화된 secrets와 함께 배포
helm secrets upgrade --install my-nodeapp my-nodeapp/ \
  -f values-prod.yaml \
  -f secrets.yaml

# 또는 쿠버네티스 Secret을 별도로 관리
kubectl create secret generic my-nodeapp-secret \
  --from-literal=db-password='supersecret' \
  -n production

문제 3: 차트 의존성 업데이트 안 됨

# 증상: Error: found in Chart.yaml, but missing in charts/ directory
# 해결: 의존성 다운로드
helm dependency update my-nodeapp/
helm dependency build my-nodeapp/

# 의존성 목록 확인
helm dependency list my-nodeapp/

문제 4: Helm 4.0에서 달라진 OCI 인증

# OCI 레지스트리 로그인 (Helm 4.0 정식 지원)
helm registry login registry.example.com \
  --username myuser \
  --password mypassword

# 차트 push
helm package my-nodeapp/
helm push my-nodeapp-0.1.0.tgz oci://registry.example.com/charts

# 차트 pull
helm pull oci://registry.example.com/charts/my-nodeapp --version 0.1.0

Helm 배포 후 릴리즈 히스토리와 kubectl 파드 상태 확인 대시보드 결과 화면

Helm 배포 후 릴리즈 히스토리와 쿠버네티스 리소스 상태를 확인하는 대시보드 화면 — helm history 명령어와 kubectl get all 결과를 함께 보여줍니다.

✅ 배포 결과 검증 — 이렇게 확인하세요

배포했다고 끝이 아닙니다. 실제로 잘 떴는지, 트래픽 받을 준비가 됐는지 꼭 확인해야 해요.

# 1. Helm 릴리즈 상태 확인
helm status my-nodeapp -n production

# 2. 배포된 values 확인 (뭘로 배포했는지)
helm get values my-nodeapp -n production

# 3. 실제 렌더링된 매니페스트 확인
helm get manifest my-nodeapp -n production

# 4. kubectl로 파드 상태 확인
kubectl get pods -n production -l app.kubernetes.io/name=my-nodeapp

# 5. 파드 로그 확인
kubectl logs -l app.kubernetes.io/name=my-nodeapp -n production --tail=50

# 6. Ingress 확인
kubectl get ingress -n production

# 7. 서비스 엔드포인트 확인
kubectl get endpoints -n production

🎉 모든 파드가 Running 상태고, Ingress에 ADDRESS가 잡혔다면 성공입니다! 드디어 됐다 싶은 그 느낌, 정말 좋죠.

Helm 릴리즈 전체 관리 명령어 요약

# 전체 릴리즈 목록
helm list -A  # 모든 네임스페이스

# 릴리즈 삭제 (리소스도 함께 삭제)
helm uninstall my-nodeapp -n production

# 히스토리 보관하며 삭제
helm uninstall my-nodeapp -n production --keep-history

# 차트 정보 검색
helm search repo nginx
helm search hub wordpress  # Artifact Hub 검색

# 차트 정보 확인
helm show chart bitnami/nginx
helm show values bitnami/nginx

Helm 4.0과 Helm 3 주요 기능 비교 인포그래픽 — OCI 지원, 보안 강화, kubectl 통합 등 핵심 개선사항 요약

Helm 4.0과 Helm 3의 주요 차이점 비교 인포그래픽 — OCI 지원, 보안 강화, kubectl 통합 등 핵심 개선사항을 한눈에 정리했습니다.

자주 묻는 질문 (FAQ)

Q. Helm 3에서 4.0으로 마이그레이션하면 기존 릴리즈가 날아가나요?

A. 아니요, 날아가지 않습니다. Helm 릴리즈 정보는 쿠버네티스 Secret으로 저장되기 때문에 Helm 버전을 업그레이드해도 기존 릴리즈는 그대로 유지됩니다. 다만 Helm 4.0의 새 기능(OCI 정식 지원 등)을 쓰려면 차트를 업데이트해야 할 수 있어요.

Q. values.yaml에서 비밀번호 같은 민감 정보는 어떻게 관리하나요?

A. 위에서 언급한 helm-secrets 플러그인이나, 쿠버네티스 Secret을 별도로 생성하고 차트에서 참조하는 방식을 권장합니다. 절대 values.yaml에 평문으로 넣지 마세요.

Q. Helm으로 배포한 리소스를 kubectl로 직접 수정해도 되나요?

A. 기술적으로는 되지만, 절대 하지 마세요. 다음 번에 helm upgrade 하면 kubectl로 수정한 내용이 덮어써집니다. 항상 values.yaml을 수정하고 helm upgrade로 적용하세요.

Q. 쿠버네티스 패키지 관리 도구로 Helm 말고 다른 선택지는?

A. Kustomize(커스터마이즈)가 대표적인 대안입니다. Helm은 템플릿 기반, Kustomize는 오버레이 기반이라 철학이 다릅니다. 둘을 함께 쓰는 경우도 많아요. 이 부분은 다음 글에서 자세히 다룰 예정입니다.


마무리 — Helm 4.0, 이것만 기억하세요

오늘 꽤 긴 여정을 함께 했네요. 정리해 드리면:

  • Helm 4.0은 OCI 레지스트리 정식 지원이 가장 큰 변화
  • values.yaml 분리 전략으로 환경별 배포를 깔끔하게 관리
  • --atomic 옵션으로 배포 실패 시 자동 롤백 설정
  • 민감 정보는 절대 values.yaml에 평문으로 넣지 말 것
  • helm upgrade --install로 설치/업그레이드를 하나의 명령어로
  • kubectl과 조합해서 배포 상태를 꼼꼼하게 검증

13년 동안 수많은 배포 도구를 써봤는데, Helm은 쿠버네티스 생태계에서 진짜 없어서는 안 될 도구가 됐습니다. 처음엔 Go 템플릿 문법이 낯설어서 적응하는 데 시간이 좀 걸리지만, 한 번 손에 익으면 정말 편하더라고요.

다음 글에서는 Helm과 ArgoCD(아르고시디, GitOps 배포 도구)를 연동해서 완전 자동화된 GitOps 파이프라인을 구축하는 방법을 다룰 예정입니다. 이전 글에서 다뤘던 k3s 클러스터 구축 내용도 참고하시면 도움이 될 거예요.

궁금한 점이나 삽질 경험 있으시면 댓글로 나눠주세요. 저도 아직 배우는 중입니다 😄