본문으로 건너뛰기

12.1 Helm

같은 애플리케이션을 dev와 prod에 배포하려면 매니페스트 묶음을 복사해 이미지 태그, replica 수, 자원량만 다른 사본을 만들게 된다. 사본이 늘어날수록 공통 부분의 수정이 전체에 반영되었는지 확인하기 어려워진다. 서드파티 소프트웨어는 문제가 더 크다. 모니터링 스택 하나를 설치하는 데 Deployment, Service, ConfigMap, RBAC까지 수십 장의 매니페스트가 필요하고, 이것을 손으로 옮겨 적는 것은 현실적이지 않다. Helm은 매니페스트 묶음을 차트(chart)라는 패키지로 묶고, 환경마다 바뀌는 값만 밖으로 분리해 설치와 업그레이드를 명령 하나로 만드는 Kubernetes의 패키지 매니저다.

차트의 구조

helm create mychart를 실행하면 차트의 골격이 생성된다.

    • Chart.yaml
    • values.yaml
      • deployment.yaml
      • service.yaml
      • _helpers.tpl

    Chart.yaml은 차트의 이름, 버전, 의존성을 선언하는 메타데이터다. values.yaml은 이 차트가 노출하는 설정값의 기본값 모음이고, templates/에는 그 값을 참조하는 Go 템플릿 형태의 매니페스트가 들어간다. charts/에는 의존하는 다른 차트가 내려받아진다.

    템플릿 문법은 처음에는 값 치환만 알아도 충분하다. .Values는 values.yaml과 사용자가 넘긴 값, .Release는 설치 시점에 정해지는 릴리스 정보, .Chart는 Chart.yaml의 내용을 가리킨다.

    # templates/deployment.yaml (일부)
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ .Release.Name }}-web
    spec:
      replicas: {{ .Values.replicaCount }}
      template:
        spec:
          containers:
            - name: web
              image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

    조건문(if), 반복문(range), 공통 조각 재사용(include)도 있지만, 차트를 만들 때 필요해지는 순서대로 익히면 된다. _helpers.tpl은 여러 템플릿에서 재사용하는 이름 규칙 같은 조각을 모아 두는 파일이다.

    릴리스와 리비전

    차트를 클러스터에 설치한 인스턴스를 릴리스(release)라고 부른다. 같은 차트를 이름만 달리해 한 클러스터에 여러 번 설치하는 것이 가능하고, 각 릴리스는 서로 다른 값으로 동작한다.

    helm install my-web ./mychart -n web --create-namespace
    helm upgrade my-web ./mychart -n web --set replicaCount=3
    helm history my-web -n web
    helm rollback my-web 1 -n web

    릴리스는 변경될 때마다 리비전 번호가 올라간다. install이 리비전 1, 위의 upgrade가 리비전 2다. helm history는 이 이력을 보여주고, helm rollback은 지정한 리비전의 매니페스트로 되돌린다. 되돌리는 동작 자체도 새 리비전(여기서는 3)으로 기록되므로 이력이 끊기지 않는다. Helm은 각 리비전의 렌더링 결과와 값을 릴리스가 있는 namespace의 Secret에 저장하고, rollback은 이 저장본을 근거로 동작한다.

        flowchart TD
      V["values.yaml + -f + --set"] --> R["템플릿 렌더링"]
      T["templates/"] --> R
      R --> M["최종 매니페스트"]
      M --> A["apiserver 적용"]
      A --> REV["릴리스 리비전 N 기록"]
      

    values 우선순위

    값은 세 경로로 들어오고, 뒤로 갈수록 우선순위가 높다. 차트의 values.yaml 기본값이 가장 낮고, -f(--values)로 넘긴 파일이 그 값을 덮어쓰고, --set으로 넘긴 개별 값이 최우선이다. -f를 여러 번 지정하면 뒤에 지정한 파일이 우선한다.

    helm upgrade my-web ./mychart \
      -f values.yaml \
      -f values-prod.yaml \
      --set image.tag=1.27.1

    환경별로 고정할 값은 values-prod.yaml 같은 파일로 관리하고, --set은 일회성 실험에만 쓰는 편이 추적에 유리하다. 현재 릴리스에 실제로 적용된 값은 helm get values my-web으로 확인한다.

    helm upgrade는 기본적으로 직전 릴리스에 적용했던 값을 이어받지 않는다. 지난번에 --set replicaCount=3으로 올렸어도 이번 upgrade에서 그 값을 다시 지정하지 않으면 차트 기본값으로 되돌아간다. --reuse-values 옵션이 있지만 차트 버전이 바뀔 때 새 기본값과 충돌하기 쉬우므로, 환경별 값 파일을 매 upgrade에 같이 지정하는 방식이 안전하다.

    OCI 레지스트리와 디버깅

    차트를 배포하는 전통적인 방법은 index.yaml을 둔 HTTP 차트 저장소였지만, Helm 3.8부터 OCI 레지스트리 지원이 GA되어 컨테이너 이미지와 같은 레지스트리에 차트를 저장하는 방식이 표준이 됐다. 이미지 저장소의 인증, 복제, 보존 정책을 차트에도 그대로 재사용한다.

    helm package ./mychart
    helm push mychart-0.1.0.tgz oci://registry.example.com/charts
    helm install my-web oci://registry.example.com/charts/mychart --version 0.1.0

    템플릿이 의도대로 렌더링되는지는 설치 전에 확인한다. helm template은 클러스터 연결 없이 로컬에서 최종 매니페스트를 출력하므로 렌더링 결과를 눈으로 검토하거나 다른 도구로 넘기기에 적합하다. helm install --dry-run --debug는 설치를 시뮬레이션하며 렌더링 결과와 계산된 값을 함께 보여준다. Helm 3.13부터는 --dry-run=server로 템플릿 안의 lookup 함수가 실제 클러스터를 조회하게 만들 수 있다. 문법과 관례 수준의 점검은 helm lint가 담당한다.

    helm template my-web ./mychart -f values-prod.yaml | less
    helm install my-web ./mychart --dry-run --debug

    정리

    • 차트는 Chart.yaml(메타데이터), values.yaml(기본값), templates/(Go 템플릿 매니페스트)로 구성되고, 환경 차이는 값으로 분리한다.
    • 설치된 차트는 릴리스라는 단위로 관리되며, upgrade마다 리비전이 쌓이고 rollback으로 이전 리비전에 되돌아간다.
    • 값 우선순위는 values.yaml < -f 파일 < --set 순이고, upgrade는 직전 값을 이어받지 않으므로 환경별 값 파일을 매번 지정한다.