🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Helm을 이용한 패키지 관리 완벽 가이드 - 슬라이드 1/11
A

AI Generated

2025. 11. 30. · 24 Views

Helm을 이용한 패키지 관리 완벽 가이드

Kubernetes 애플리케이션 배포를 위한 Helm 패키지 매니저의 핵심 개념과 실무 활용법을 다룹니다. Chart 생성부터 배포, 업그레이드, 롤백까지 단계별로 쉽게 설명합니다.


목차

  1. Helm_소개와_기본_개념
  2. Chart_구조_이해하기
  3. Values_파일_활용하기
  4. 템플릿_문법_익히기
  5. 릴리스_관리와_업그레이드
  6. 차트_저장소_활용하기
  7. 의존성_관리하기
  8. Hooks_활용하기
  9. 디버깅과_트러블슈팅
  10. 보안_모범_사례

1. Helm 소개와 기본 개념

어느 날 김개발 씨는 Kubernetes 클러스터에 새로운 서비스를 배포하라는 업무를 받았습니다. YAML 파일을 하나씩 작성하고 kubectl apply를 반복하다 보니 어느새 파일이 20개가 넘어갔습니다.

"이걸 매번 이렇게 해야 하나요?" 옆에 있던 박시니어 씨가 웃으며 대답했습니다. "Helm을 써보세요."

Helm은 Kubernetes의 패키지 매니저입니다. 마치 우분투의 apt나 맥의 brew처럼, 복잡한 Kubernetes 애플리케이션을 하나의 패키지로 묶어서 설치하고 관리할 수 있게 해줍니다.

Helm을 사용하면 수십 개의 YAML 파일을 하나의 명령어로 배포할 수 있습니다.

다음 코드를 살펴봅시다.

# Helm 설치 확인
helm version

# Helm 저장소 추가
helm repo add bitnami https://charts.bitnami.com/bitnami

# 저장소 업데이트
helm repo update

# 사용 가능한 차트 검색
helm search repo nginx

# 차트 설치 (릴리스 이름: my-nginx)
helm install my-nginx bitnami/nginx

# 설치된 릴리스 목록 확인
helm list

김개발 씨는 입사 6개월 차 DevOps 엔지니어입니다. 오늘도 열심히 Kubernetes 매니페스트 파일을 작성하던 중, 문득 의문이 들었습니다.

Deployment, Service, ConfigMap, Secret, Ingress... 하나의 애플리케이션을 배포하는 데 왜 이렇게 많은 파일이 필요한 걸까요?

선배 개발자 박시니어 씨가 다가와 화면을 살펴봅니다. "아, 아직도 그렇게 하고 있었어요?

Helm을 쓰면 훨씬 편해질 텐데요." 그렇다면 Helm이란 정확히 무엇일까요? 쉽게 비유하자면, Helm은 마치 이케아 가구 패키지와 같습니다.

이케아에서 책상을 사면 나사, 판자, 설명서가 하나의 박스에 담겨 옵니다. 그냥 설명서대로 조립하면 되죠.

마찬가지로 Helm은 Kubernetes 애플리케이션에 필요한 모든 리소스를 하나의 패키지로 묶어줍니다. 이 패키지를 Chart라고 부릅니다.

Helm이 없던 시절에는 어땠을까요? 개발자들은 Deployment, Service, ConfigMap 등 모든 YAML 파일을 직접 작성하고 관리해야 했습니다.

환경별로 다른 설정이 필요하면 파일을 복사해서 수정하거나, sed 같은 도구로 값을 치환해야 했습니다. 더 큰 문제는 버전 관리였습니다.

"지난주에 배포한 버전으로 롤백해주세요"라는 요청이 들어오면, 어떤 파일이 변경되었는지 일일이 확인해야 했습니다. 바로 이런 문제를 해결하기 위해 Helm이 등장했습니다.

Helm을 사용하면 템플릿화가 가능해집니다. 환경에 따라 달라지는 값들을 변수로 분리하고, 하나의 템플릿으로 여러 환경에 배포할 수 있습니다.

또한 버전 관리도 쉬워집니다. Helm은 배포할 때마다 릴리스라는 단위로 기록을 남기기 때문에, 언제든지 이전 버전으로 롤백할 수 있습니다.

위의 명령어들을 하나씩 살펴보겠습니다. 먼저 helm repo add 명령어로 차트 저장소를 추가합니다.

이것은 apt에서 소스 리스트를 추가하는 것과 같습니다. bitnami는 많은 오픈소스 애플리케이션의 Helm 차트를 제공하는 유명한 저장소입니다.

helm install 명령어로 차트를 설치하면, Helm이 알아서 필요한 모든 Kubernetes 리소스를 생성합니다. 실제 현업에서는 어떻게 활용할까요?

예를 들어 마이크로서비스 아키텍처를 운영한다고 가정해봅시다. 10개의 서비스가 있고, 각 서비스마다 Deployment, Service, ConfigMap이 필요합니다.

Helm 없이는 30개 이상의 YAML 파일을 관리해야 합니다. 하지만 Helm을 사용하면 각 서비스를 하나의 Chart로 만들고, 환경별 설정은 values.yaml 파일로 분리할 수 있습니다.

하지만 주의할 점도 있습니다. 초보자들이 흔히 하는 실수 중 하나는 Helm 차트를 그대로 사용하는 것입니다.

공식 차트는 범용적으로 만들어져 있어서 불필요한 리소스가 포함될 수 있습니다. 따라서 values.yaml을 꼼꼼히 확인하고 필요한 설정만 활성화해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 Helm을 적용해보기로 했습니다.

20개가 넘던 YAML 파일이 하나의 Chart로 정리되자, 배포 작업이 훨씬 간단해졌습니다.

실전 팁

💡 - helm repo update를 주기적으로 실행하여 최신 차트 정보를 유지하세요

  • 프로덕션 환경에서는 차트 버전을 명시적으로 지정하여 예기치 않은 업데이트를 방지하세요

2. Chart 구조 이해하기

김개발 씨가 Helm을 사용하기 시작한 지 일주일이 지났습니다. 공식 차트를 설치하는 것은 익숙해졌지만, 팀에서 개발한 자체 서비스를 배포하려면 직접 Chart를 만들어야 했습니다.

"Chart는 대체 어떻게 생긴 거지?" 김개발 씨는 차트 디렉토리를 열어보기로 했습니다.

Helm Chart는 특정한 디렉토리 구조를 가진 패키지입니다. Chart.yaml에는 차트의 메타정보가, values.yaml에는 기본 설정값이, templates 폴더에는 Kubernetes 매니페스트 템플릿이 들어있습니다.

이 구조를 이해하면 어떤 차트든 커스터마이즈할 수 있습니다.

다음 코드를 살펴봅시다.

mychart/
  Chart.yaml          # 차트 메타정보 (이름, 버전)
  values.yaml         # 기본 설정값
  charts/             # 의존성 차트
  templates/          # 템플릿 파일들
    deployment.yaml
    service.yaml
    ingress.yaml
    _helpers.tpl      # 템플릿 헬퍼 함수
    NOTES.txt         # 설치 후 안내 메시지

# Chart.yaml 예시
apiVersion: v2
name: myapp
version: 1.0.0
appVersion: "1.0.0"

김개발 씨는 helm create myapp 명령어로 새 차트를 생성했습니다. 터미널에 익숙한 디렉토리 구조가 나타났습니다.

하지만 각 파일이 무슨 역할을 하는지는 아직 잘 모르겠습니다. 박시니어 씨가 화이트보드 앞으로 김개발 씨를 불렀습니다.

"Chart 구조를 집에 비유해서 설명해 줄게요." Chart.yaml은 집의 등기부등본과 같습니다. 이 집이 언제 지어졌는지, 누가 소유하고 있는지, 몇 평인지 같은 기본 정보가 담겨 있습니다.

Chart.yaml에는 차트의 이름, 버전, 설명, 의존성 등의 메타정보가 기록됩니다. 특히 versionappVersion을 구분하는 것이 중요합니다.

version은 차트 자체의 버전이고, appVersion은 배포되는 애플리케이션의 버전입니다. values.yaml은 집의 인테리어 설정서와 같습니다.

벽지 색상, 조명 밝기, 가구 배치 등 취향에 따라 바꿀 수 있는 설정들이 담겨 있습니다. values.yaml에는 복제본 수, 이미지 태그, 리소스 제한 등 배포 시 변경할 수 있는 값들이 정의됩니다.

이 파일의 값들은 설치 시 --set 플래그나 별도의 values 파일로 오버라이드할 수 있습니다. templates 폴더는 집의 설계도와 같습니다.

실제로 어떤 구조물이 만들어질지 정의하는 청사진입니다. 여기에는 Deployment, Service, ConfigMap 등 실제 Kubernetes 리소스의 템플릿이 들어갑니다.

템플릿 파일에는 Go 템플릿 문법으로 변수가 삽입되어 있어서, values.yaml의 값에 따라 최종 매니페스트가 달라집니다. 특별한 파일들도 있습니다.

_helpers.tpl은 이름 앞에 언더스코어가 붙어 있습니다. 이 파일은 Kubernetes 리소스를 생성하지 않고, 다른 템플릿에서 재사용할 수 있는 헬퍼 함수들을 정의합니다.

NOTES.txt는 차트 설치 후 사용자에게 보여줄 안내 메시지입니다. "다음 명령어로 서비스에 접근하세요" 같은 친절한 가이드를 넣어두면 좋습니다.

charts 폴더는 의존성 차트가 저장되는 곳입니다. 예를 들어 애플리케이션이 Redis를 필요로 한다면, Redis 차트를 의존성으로 추가할 수 있습니다.

Chart.yaml에 dependencies 섹션을 정의하고 helm dependency update를 실행하면, 의존성 차트가 charts 폴더에 다운로드됩니다. 김개발 씨가 물었습니다.

"그럼 차트를 수정하려면 어떤 파일부터 봐야 하나요?" 박시니어 씨가 대답했습니다. "대부분의 경우 values.yaml만 수정하면 됩니다.

템플릿 구조 자체를 바꿔야 할 때만 templates 폴더를 건드리면 돼요. 그래서 잘 설계된 차트는 values.yaml만으로도 다양한 환경에 대응할 수 있습니다."

실전 팁

💡 - helm template 명령어로 실제 생성될 매니페스트를 미리 확인할 수 있습니다

  • _helpers.tpl에 공통 레이블이나 이름 규칙을 정의해두면 일관성을 유지하기 쉽습니다

3. Values 파일 활용하기

김개발 씨는 개발 환경에서 테스트를 마친 서비스를 스테이징 환경에 배포해야 했습니다. 그런데 개발 환경과 스테이징 환경의 설정이 달랐습니다.

복제본 수도 다르고, 리소스 제한도 달라야 했습니다. "환경마다 차트를 따로 만들어야 하나?" 고민하던 김개발 씨에게 박시니어 씨가 해결책을 알려주었습니다.

values.yaml은 차트의 기본 설정을 정의하는 파일입니다. 환경별로 다른 values 파일을 만들어 두면, 하나의 차트로 여러 환경에 배포할 수 있습니다.

--set 플래그로 개별 값을 오버라이드하거나, -f 플래그로 전체 values 파일을 지정할 수 있습니다.

다음 코드를 살펴봅시다.

# values.yaml (기본값)
replicaCount: 1
image:
  repository: myapp
  tag: latest
  pullPolicy: IfNotPresent
resources:
  limits:
    cpu: 100m
    memory: 128Mi

# values-prod.yaml (프로덕션용)
replicaCount: 3
image:
  tag: "1.2.0"
resources:
  limits:
    cpu: 500m
    memory: 512Mi

# 프로덕션 배포 명령어
helm install myapp ./mychart -f values-prod.yaml

김개발 씨는 회사의 배포 파이프라인을 살펴보았습니다. 개발, 스테이징, 프로덕션 세 가지 환경이 있었고, 각 환경마다 요구사항이 달랐습니다.

개발 환경에서는 리소스를 아끼기 위해 복제본 하나만 띄우지만, 프로덕션에서는 고가용성을 위해 최소 세 개의 복제본이 필요했습니다. "이럴 때 values 파일 분리가 빛을 발합니다." 박시니어 씨가 설명을 시작했습니다.

values.yaml은 차트에 포함된 기본 설정 파일입니다. 이 파일에는 가장 일반적인 기본값을 넣어둡니다.

마치 휴대폰을 처음 샀을 때 설정되어 있는 기본 벨소리, 화면 밝기 같은 것입니다. 대부분의 사용자에게 무난하게 작동하는 값들이죠.

하지만 환경마다 다른 설정이 필요할 때가 있습니다. 이때 별도의 values 파일을 만들어 사용합니다.

values-dev.yaml, values-staging.yaml, values-prod.yaml처럼 환경별로 파일을 분리하면 관리가 훨씬 쉬워집니다. 설정값을 오버라이드하는 방법은 크게 세 가지가 있습니다.

첫 번째는 -f 또는 --values 플래그입니다. helm install myapp ./mychart -f values-prod.yaml처럼 사용하면, 지정한 파일의 값이 기본 values.yaml의 값을 덮어씁니다.

여러 파일을 순서대로 지정할 수도 있습니다. 나중에 지정한 파일이 앞서 지정한 파일의 값을 덮어씁니다.

두 번째는 --set 플래그입니다. helm install myapp ./mychart --set replicaCount=5처럼 명령줄에서 직접 값을 지정할 수 있습니다.

중첩된 값은 점 표기법으로 지정합니다. 예를 들어 --set image.tag=1.2.0처럼 사용합니다.

간단한 테스트나 CI/CD 파이프라인에서 동적으로 값을 전달할 때 유용합니다. 세 번째는 --set-file 플래그입니다.

값 자체가 긴 텍스트일 때, 예를 들어 인증서나 설정 파일 내용을 전달할 때 사용합니다. --set-file config=./app.conf처럼 파일 내용을 값으로 전달할 수 있습니다.

김개발 씨가 질문했습니다. "그럼 우선순위는 어떻게 되나요?" 박시니어 씨가 화이트보드에 적었습니다.

"기본 values.yaml이 가장 낮고, -f로 지정한 파일들이 순서대로 적용되고, 마지막으로 --set이 가장 높습니다. 즉, --set으로 지정한 값이 최종적으로 적용됩니다." 실무에서는 보통 기본 values.yaml에 개발 환경 설정을 넣고, 프로덕션용 설정만 별도 파일로 분리합니다.

CI/CD 파이프라인에서는 환경 변수로 이미지 태그를 전달하여 --set으로 오버라이드합니다.

실전 팁

💡 - values 파일에 민감한 정보(비밀번호, API 키)를 직접 넣지 말고 Kubernetes Secret이나 외부 시크릿 관리 도구를 사용하세요

  • helm get values 명령어로 현재 릴리스에 적용된 값을 확인할 수 있습니다

4. 템플릿 문법 익히기

김개발 씨는 values.yaml에서 변경할 수 없는 부분을 수정해야 했습니다. 특정 조건에서만 리소스를 생성하거나, 레이블을 동적으로 추가하고 싶었습니다.

"templates 폴더를 수정해야 할 것 같은데..." 막상 템플릿 파일을 열어보니 낯선 문법이 가득했습니다. 중괄호 두 개로 감싸진 이상한 코드들이 눈에 들어왔습니다.

Helm 템플릿은 Go 템플릿 문법을 사용합니다. 이중 중괄호 안에 변수, 조건문, 반복문을 작성하면 values.yaml의 값에 따라 동적으로 매니페스트가 생성됩니다.

파이프라인과 함수를 조합하면 강력한 템플릿을 만들 수 있습니다.

다음 코드를 살펴봅시다.

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-app
  labels:
    app: {{ .Values.appName | default "myapp" }}
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        {{- if .Values.resources }}
        resources:
          {{- toYaml .Values.resources | nindent 10 }}
        {{- end }}

템플릿 파일을 처음 본 김개발 씨는 당황했습니다. 익숙한 YAML 파일인 줄 알았는데, 여기저기 이상한 기호가 섞여 있었습니다.

박시니어 씨가 차근차근 설명을 시작했습니다. "Helm은 Go 언어로 만들어졌어요.

그래서 Go 템플릿 문법을 사용합니다. 복잡해 보이지만 핵심만 알면 금방 익숙해져요." 가장 기본적인 것은 변수 참조입니다.

{{ .Values.replicaCount }}처럼 이중 중괄호 안에 점으로 시작하는 경로를 적으면, 해당 값이 그 자리에 삽입됩니다. 점(.)은 현재 스코프를 의미하고, Values는 values.yaml 파일의 내용을 가리킵니다.

Helm에서 자주 사용하는 내장 객체들이 있습니다. .Values는 values.yaml과 사용자가 전달한 값을 담고 있습니다.

.Release는 릴리스 정보(이름, 네임스페이스, 버전 등)를 담고 있습니다. .Chart는 Chart.yaml의 내용을 담고 있습니다.

.Files는 차트 내의 파일에 접근할 때 사용합니다. 조건문도 자주 사용합니다.

{{- if .Values.ingress.enabled }}처럼 시작하고 {{- end }}로 끝냅니다. if와 end 사이의 내용은 조건이 참일 때만 출력됩니다.

중괄호 뒤의 하이픈(-)은 공백을 제거하는 역할을 합니다. YAML은 공백에 민감하기 때문에 이 하이픈이 중요합니다.

파이프라인은 유닉스의 파이프와 비슷합니다. {{ .Values.appName | default "myapp" }}에서 파이프(|) 기호는 앞의 값을 뒤의 함수로 전달합니다.

default 함수는 값이 비어있을 때 기본값을 반환합니다. 자주 쓰이는 함수로는 default, quote, upper, lower, trim, nindent 등이 있습니다.

toYamlnindent는 복잡한 값을 처리할 때 유용합니다. values.yaml에 정의된 resources 같은 맵 구조를 그대로 출력하려면 toYaml로 변환하고, nindent로 들여쓰기를 맞춥니다.

nindent 10은 10칸 들여쓰기를 의미합니다. 김개발 씨가 물었습니다.

"반복문도 있나요?" 박시니어 씨가 끄덕였습니다. "네, range를 사용합니다.

{{- range .Values.ports }}처럼 시작하면 리스트의 각 항목에 대해 반복합니다. 반복문 안에서 점(.)은 현재 항목을 가리킵니다." 템플릿 문법이 복잡하게 느껴지면 helm template 명령어를 활용하세요.

이 명령어는 실제로 생성될 매니페스트를 미리 보여줍니다. 오류가 있으면 어느 줄에서 문제가 생겼는지도 알려주기 때문에 디버깅에 유용합니다.

실전 팁

💡 - helm lint 명령어로 차트의 문법 오류를 미리 검사할 수 있습니다

  • 복잡한 템플릿 로직은 _helpers.tpl에 named template으로 분리하면 재사용성이 높아집니다

5. 릴리스 관리와 업그레이드

김개발 씨가 배포한 서비스에 버그가 발견되었습니다. 급하게 수정된 이미지를 배포해야 했습니다.

"kubectl apply로 Deployment만 업데이트하면 되나?" 잠시 고민하던 김개발 씨는 Helm으로 배포했다는 것을 떠올렸습니다. 그렇다면 업데이트도 Helm으로 해야 할 것 같았습니다.

helm upgrade는 기존 릴리스를 새로운 설정이나 차트 버전으로 업데이트합니다. Helm은 모든 릴리스 히스토리를 기록하기 때문에, 문제가 생기면 helm rollback으로 이전 버전으로 되돌릴 수 있습니다.

이것이 Helm을 사용하는 가장 큰 이유 중 하나입니다.

다음 코드를 살펴봅시다.

# 현재 릴리스 상태 확인
helm status my-nginx

# 이미지 태그만 변경하여 업그레이드
helm upgrade my-nginx bitnami/nginx --set image.tag=1.21.0

# values 파일로 업그레이드
helm upgrade my-nginx ./mychart -f values-prod.yaml

# 릴리스 히스토리 확인
helm history my-nginx

# 이전 리비전으로 롤백 (리비전 번호 2로)
helm rollback my-nginx 2

# 릴리스 삭제
helm uninstall my-nginx

김개발 씨는 Helm으로 배포한 서비스를 업데이트해야 했습니다. kubectl로 직접 리소스를 수정할 수도 있지만, 그러면 Helm이 관리하는 상태와 실제 클러스터의 상태가 달라지는 drift 문제가 생길 수 있습니다.

박시니어 씨가 조언했습니다. "Helm으로 배포했으면 업데이트도 Helm으로 해야 해요.

그래야 히스토리도 남고, 롤백도 가능합니다." helm upgrade 명령어는 기존 릴리스를 업데이트합니다. install과 비슷한 문법을 사용하지만, 이미 존재하는 릴리스를 대상으로 합니다.

변경된 값만 적용되고, 변경되지 않은 리소스는 그대로 유지됩니다. 업그레이드할 때 유용한 플래그들이 있습니다.

--reuse-values는 이전 릴리스의 values를 그대로 사용하고, 새로 지정한 값만 오버라이드합니다. --reset-values는 차트의 기본 values로 초기화합니다.

--atomic은 업그레이드가 실패하면 자동으로 롤백합니다. install-upgrade 패턴도 알아두면 좋습니다.

helm upgrade --install을 사용하면 릴리스가 없으면 설치하고, 있으면 업그레이드합니다. CI/CD 파이프라인에서 배포 스크립트를 단순하게 만들 수 있어서 많이 사용하는 패턴입니다.

helm history 명령어는 릴리스의 모든 리비전을 보여줍니다. 각 리비전에는 배포 시간, 상태, 차트 버전, 설명이 기록됩니다.

언제 어떤 변경이 있었는지 한눈에 파악할 수 있습니다. 문제가 생겼을 때 helm rollback이 진가를 발휘합니다.

helm rollback my-nginx 2처럼 릴리스 이름과 리비전 번호를 지정하면, 해당 리비전의 상태로 클러스터가 복원됩니다. 새벽에 긴급 롤백이 필요할 때, 이 한 줄이면 됩니다.

김개발 씨가 안도의 한숨을 내쉬었습니다. "휴, 버그 있는 버전을 빨리 롤백해야겠네요." 박시니어 씨가 덧붙였습니다.

"롤백도 히스토리에 새 리비전으로 기록돼요. 그러니까 롤백한 후에 다시 롤백하면 롤백 전 상태로 돌아갑니다.

복잡하죠? 그래서 항상 history를 확인하면서 작업하는 게 좋아요." helm uninstall은 릴리스를 완전히 삭제합니다.

해당 릴리스로 생성된 모든 Kubernetes 리소스가 제거됩니다. 단, PersistentVolumeClaim은 기본적으로 삭제되지 않으니 데이터를 보존하려면 수동으로 관리해야 합니다.

실전 팁

💡 - 프로덕션에서는 항상 --atomic 플래그를 사용하여 실패 시 자동 롤백되도록 하세요

  • helm diff 플러그인을 설치하면 업그레이드 전에 변경될 내용을 미리 확인할 수 있습니다

6. 차트 저장소 활용하기

팀에서 만든 Helm 차트가 점점 늘어났습니다. 처음에는 Git 저장소에서 직접 차트를 가져다 썼지만, 버전 관리도 어렵고 다른 팀과 공유하기도 불편했습니다.

"공식 차트들은 어떻게 배포하는 거지?" 김개발 씨는 차트 저장소에 대해 알아보기로 했습니다.

Helm 저장소는 차트 패키지를 호스팅하는 서버입니다. HTTP로 접근 가능한 index.yaml과 차트 아카이브 파일로 구성됩니다.

공개 저장소를 사용할 수도 있고, Harbor나 ChartMuseum으로 사설 저장소를 운영할 수도 있습니다.

다음 코드를 살펴봅시다.

# 저장소 목록 확인
helm repo list

# 저장소 추가
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami

# 저장소 정보 업데이트
helm repo update

# 저장소에서 차트 검색
helm search repo nginx
helm search repo bitnami/nginx --versions

# 차트 패키징 (배포용 .tgz 파일 생성)
helm package ./mychart

# 저장소 인덱스 생성
helm repo index ./charts --url https://myrepo.example.com/charts

김개발 씨는 회사에서 만든 차트를 다른 팀과 공유해야 했습니다. 지금까지는 Git 저장소의 특정 경로를 알려주고 clone 받아서 쓰라고 했지만, 이 방식에는 문제가 있었습니다.

버전 태그를 일일이 확인해야 하고, 의존성 관리도 어려웠습니다. "차트 저장소를 구축하면 이런 문제가 해결돼요." 박시니어 씨가 화면을 보여주며 설명했습니다.

Helm 저장소의 구조는 매우 단순합니다. index.yaml 파일 하나와 차트 아카이브 파일(.tgz)들로 구성됩니다.

index.yaml에는 저장소에 있는 모든 차트의 메타정보가 들어있습니다. helm repo update를 실행하면 이 index.yaml을 다운로드해서 로컬에 캐싱합니다.

공개 저장소로는 Bitnami, Artifact Hub 등이 유명합니다. Artifact Hub는 Helm 공식 차트 허브로, 수천 개의 차트를 검색하고 설치할 수 있습니다.

웹 인터페이스에서 차트의 README, values, 템플릿 내용까지 미리 볼 수 있어서 편리합니다. 사설 저장소를 구축하는 방법도 여러 가지입니다.

가장 간단한 방법은 정적 파일 서버를 사용하는 것입니다. S3, GCS, GitHub Pages 등에 차트 파일과 index.yaml을 올려두면 됩니다.

ChartMuseum은 Helm 차트 전용 저장소 서버로, 차트 업로드, 버전 관리, 인증 기능을 제공합니다. Harbor는 컨테이너 레지스트리이면서 Helm 저장소 기능도 지원합니다.

차트를 저장소에 배포하려면 먼저 패키징이 필요합니다. helm package ./mychart를 실행하면 mychart-1.0.0.tgz 같은 아카이브 파일이 생성됩니다.

버전은 Chart.yaml의 version 필드에서 가져옵니다. 패키지를 저장소에 업로드한 후 인덱스를 업데이트해야 합니다.

helm repo index ./charts --url https://myrepo.example.com/charts를 실행하면 charts 폴더의 모든 .tgz 파일을 스캔하여 index.yaml을 생성합니다. 기존 인덱스에 새 차트를 추가하려면 --merge 플래그를 사용합니다.

김개발 씨가 물었습니다. "OCI 레지스트리라는 것도 있던데, 그건 뭔가요?" 박시니어 씨가 대답했습니다.

"Helm 3.8부터는 OCI(Open Container Initiative) 레지스트리에 차트를 저장할 수 있어요. Docker Hub나 ECR 같은 컨테이너 레지스트리에 차트를 푸시하고 풀할 수 있습니다.

helm pushhelm pull 명령어를 사용하면 됩니다. 별도의 차트 저장소 인프라가 필요 없어서 점점 인기를 얻고 있어요."

실전 팁

💡 - 프로덕션 환경에서는 차트 버전을 명시적으로 고정하여 예기치 않은 업데이트를 방지하세요

  • helm search repo --versions로 특정 차트의 모든 버전을 확인할 수 있습니다

7. 의존성 관리하기

김개발 씨가 만든 웹 애플리케이션 차트에는 Redis가 필요했습니다. Redis도 별도의 차트로 배포해야 하는데, 애플리케이션을 설치할 때마다 Redis도 같이 설치해야 했습니다.

"이걸 하나로 묶을 수 없을까?" 김개발 씨는 Helm의 의존성 기능을 찾아보았습니다.

Helm 차트는 다른 차트를 의존성으로 가질 수 있습니다. Chart.yaml의 dependencies 섹션에 필요한 차트를 정의하면, helm dependency update로 의존 차트를 다운로드하고 함께 배포할 수 있습니다.

조건부로 의존성을 활성화하거나 비활성화할 수도 있습니다.

다음 코드를 살펴봅시다.

# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
  - name: redis
    version: "17.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled
  - name: postgresql
    version: "12.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled

# values.yaml
redis:
  enabled: true
  auth:
    password: "mypassword"
postgresql:
  enabled: false

# 의존성 다운로드
helm dependency update ./mychart

복잡한 애플리케이션은 혼자 동작하지 않습니다. 데이터베이스, 캐시, 메시지 큐 등 다양한 컴포넌트가 필요합니다.

이런 컴포넌트들을 각각 따로 배포하면 관리가 번거롭습니다. Helm의 의존성 기능을 사용하면 관련 컴포넌트들을 하나의 우산 아래 묶을 수 있습니다.

박시니어 씨가 비유를 들었습니다. "스마트폰 앱을 생각해 보세요.

앱을 설치하면 필요한 프레임워크나 라이브러리가 자동으로 같이 설치되죠? Helm의 의존성도 마찬가지예요." dependencies 섹션에는 필요한 차트의 이름, 버전, 저장소 URL을 명시합니다.

버전에는 시맨틱 버저닝 범위를 사용할 수 있습니다. "17.x.x"는 17로 시작하는 모든 버전을 허용합니다.

"~17.3.0"은 17.3.x 범위를 의미합니다. "^17.0.0"은 17.x.x 범위를 의미합니다.

condition 필드를 사용하면 조건부로 의존성을 활성화할 수 있습니다. 위 예제에서 redis.enabled가 true일 때만 Redis 차트가 배포됩니다.

개발 환경에서는 로컬 Redis를 쓰고 프로덕션에서는 관리형 Redis를 쓰는 경우, 조건부 의존성이 유용합니다. helm dependency update를 실행하면 정의된 의존성 차트들이 charts/ 폴더에 다운로드됩니다.

이 폴더의 .tgz 파일들은 보통 .gitignore에 추가합니다. 대신 Chart.lock 파일이 생성되는데, 이 파일에는 실제로 다운로드된 차트의 정확한 버전이 기록됩니다.

하위 차트의 values 오버라이드도 가능합니다. 상위 차트의 values.yaml에서 의존성 차트 이름을 키로 하여 값을 정의하면 됩니다.

위 예제에서 redis.auth.password는 Redis 차트의 auth.password 값을 오버라이드합니다. 김개발 씨가 물었습니다.

"의존성 차트와 상위 차트에서 같은 리소스를 만들면 어떻게 되나요?" 박시니어 씨가 대답했습니다. "Kubernetes 리소스 이름이 충돌하면 문제가 됩니다.

그래서 보통 릴리스 이름을 접두어로 붙여서 유니크하게 만들어요. _helpers.tpl에 정의된 fullname 템플릿이 이 역할을 합니다." alias를 사용하면 같은 차트를 여러 번 의존성으로 추가할 수 있습니다.

예를 들어 마스터 Redis와 슬레이브 Redis를 다른 설정으로 배포하고 싶을 때, alias로 이름을 구분합니다.

실전 팁

💡 - Chart.lock 파일은 반드시 버전 관리에 포함하여 빌드 재현성을 보장하세요

  • helm dependency list로 현재 의존성 상태를 확인할 수 있습니다

8. Hooks 활용하기

김개발 씨는 데이터베이스 마이그레이션 문제로 고민하고 있었습니다. 애플리케이션이 시작되기 전에 DB 스키마를 업데이트해야 하는데, 순서를 보장하기 어려웠습니다.

"Deployment가 뜨기 전에 Job을 실행할 방법이 없을까?" 박시니어 씨가 Helm Hooks를 소개해 주었습니다.

Helm Hooks는 릴리스 라이프사이클의 특정 시점에 실행되는 리소스입니다. pre-install, post-install, pre-upgrade, post-upgrade 등의 시점에 Job이나 다른 리소스를 실행할 수 있습니다.

데이터베이스 마이그레이션, 백업, 클린업 작업에 유용합니다.

다음 코드를 살펴봅시다.

# templates/pre-upgrade-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ .Release.Name }}-db-migrate
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      containers:
      - name: migrate
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["./migrate.sh"]
      restartPolicy: Never
  backoffLimit: 1

김개발 씨의 팀은 데이터베이스 마이그레이션 때문에 매번 배포가 복잡해졌습니다. 애플리케이션 Pod가 뜨기 전에 마이그레이션 스크립트를 실행해야 하는데, 타이밍을 맞추기 어려웠습니다.

수동으로 Job을 먼저 실행하고 완료를 확인한 후 애플리케이션을 배포하는 식으로 진행했습니다. 박시니어 씨가 말했습니다.

"Helm Hooks를 쓰면 이런 순서를 자동화할 수 있어요." Hook은 릴리스 라이프사이클의 특정 시점에 자동으로 실행되는 리소스입니다. 어노테이션 하나로 "이 Job은 업그레이드 전에 실행해"라고 지정할 수 있습니다.

사용 가능한 Hook 시점은 다양합니다. pre-install은 템플릿이 렌더링된 후, 리소스가 생성되기 전에 실행됩니다.

post-install은 모든 리소스가 생성된 후 실행됩니다. pre-upgradepost-upgrade도 마찬가지로 업그레이드 전후에 실행됩니다.

pre-deletepost-delete는 릴리스 삭제 시 실행됩니다. hook-weight 어노테이션으로 같은 시점의 여러 Hook 간 실행 순서를 제어할 수 있습니다.

낮은 숫자가 먼저 실행됩니다. 음수도 가능합니다.

예를 들어 -5, 0, 5 순서대로 실행됩니다. hook-delete-policy는 Hook 리소스의 삭제 정책을 정의합니다.

hook-succeeded는 Hook이 성공하면 삭제합니다. hook-failed는 실패하면 삭제합니다.

before-hook-creation은 새 Hook이 실행되기 전에 이전 Hook을 삭제합니다. 아무것도 지정하지 않으면 Hook 리소스가 계속 남아있습니다.

김개발 씨가 질문했습니다. "Hook이 실패하면 어떻게 되나요?" 박시니어 씨가 대답했습니다.

"Hook이 실패하면 전체 릴리스 작업이 실패합니다. pre-upgrade Hook이 실패하면 업그레이드가 진행되지 않아요.

이런 동작이 데이터베이스 마이그레이션에서 중요합니다. 마이그레이션이 실패했는데 애플리케이션이 배포되면 안 되니까요." 실무에서 Hook은 여러 용도로 활용됩니다.

데이터베이스 마이그레이션 외에도 백업(pre-upgrade에서 현재 상태 백업), 캐시 워밍(post-install에서 캐시 미리 로드), 헬스 체크(post-upgrade에서 서비스 상태 확인), 클린업(pre-delete에서 외부 리소스 정리) 등에 사용합니다. 주의할 점도 있습니다.

Hook 리소스는 일반 릴리스 리소스와 별도로 관리됩니다. helm list에서 보이는 리소스 목록에 포함되지 않습니다.

따라서 delete-policy를 적절히 설정하지 않으면 완료된 Job이 클러스터에 계속 남아있을 수 있습니다.

실전 팁

💡 - 마이그레이션 Job에는 적절한 backoffLimit과 timeout을 설정하여 무한 대기를 방지하세요

  • test Hook을 사용하면 helm test로 배포 후 검증 테스트를 실행할 수 있습니다

9. 디버깅과 트러블슈팅

김개발 씨의 차트 배포가 실패했습니다. "Error: INSTALLATION FAILED: template: mychart/templates/deployment.yaml:15:3: executing..." 길고 복잡한 에러 메시지가 화면에 떴습니다.

무엇이 문제인지 알 수 없었습니다. "이런 에러는 어떻게 디버깅하나요?" 박시니어 씨에게 물었습니다.

Helm은 다양한 디버깅 도구를 제공합니다. helm template으로 렌더링 결과를 미리 확인하고, helm lint로 문법 오류를 검사하며, --debug 플래그로 상세한 로그를 볼 수 있습니다.

배포 후에는 helm get으로 릴리스 정보를 조회합니다.

다음 코드를 살펴봅시다.

# 템플릿 렌더링 결과 확인 (실제 배포하지 않음)
helm template myapp ./mychart -f values.yaml

# 특정 템플릿만 렌더링
helm template myapp ./mychart -s templates/deployment.yaml

# 차트 문법 검사
helm lint ./mychart

# 디버그 모드로 설치 (드라이런)
helm install myapp ./mychart --dry-run --debug

# 릴리스의 현재 values 확인
helm get values myapp

# 릴리스의 전체 매니페스트 확인
helm get manifest myapp

# 릴리스 상태 확인
helm status myapp

Helm 차트 개발에서 가장 어려운 부분은 디버깅입니다. 템플릿 문법 오류, YAML 들여쓰기 문제, 값 참조 오류 등 다양한 문제가 발생할 수 있습니다.

다행히 Helm은 이런 문제를 찾아내는 도구들을 제공합니다. 박시니어 씨가 디버깅 프로세스를 설명했습니다.

"문제가 생기면 순서대로 확인하세요." 첫 번째 단계는 helm lint입니다. 이 명령어는 차트의 기본적인 구조와 문법을 검사합니다.

Chart.yaml이 제대로 되어 있는지, 필수 파일이 있는지, 템플릿에 명백한 오류가 없는지 확인합니다. 에러는 빨간색, 경고는 노란색으로 표시됩니다.

두 번째 단계는 helm template입니다. 이 명령어는 실제 Kubernetes에 배포하지 않고 템플릿만 렌더링합니다.

어떤 매니페스트가 생성되는지 눈으로 확인할 수 있습니다. values.yaml의 값들이 제대로 치환되었는지, YAML 형식이 올바른지 검사하기 좋습니다.

-s 플래그로 특정 템플릿만 렌더링할 수도 있습니다. 세 번째 단계는 --dry-run --debug 플래그입니다.

helm install myapp ./mychart --dry-run --debug처럼 사용하면 실제 설치 과정을 시뮬레이션합니다. Kubernetes API 서버와 통신하여 리소스 유효성까지 검사하지만, 실제로 생성하지는 않습니다.

더 상세한 로그를 볼 수 있어서 문제 원인을 파악하기 쉽습니다. 이미 배포된 릴리스에 문제가 있을 때는 helm get 명령어를 사용합니다.

helm get values myapp은 현재 적용된 values를 보여줍니다. 예상과 다른 값이 적용되었는지 확인할 수 있습니다.

helm get manifest myapp은 실제 클러스터에 배포된 매니페스트를 보여줍니다. helm status는 릴리스의 현재 상태를 보여줍니다.

배포 시간, 네임스페이스, 리비전 번호, 리소스 상태 등을 한눈에 볼 수 있습니다. NOTES.txt의 내용도 함께 표시됩니다.

김개발 씨가 물었습니다. "템플릿에서 변수 값을 확인하고 싶을 때는 어떻게 하나요?" 박시니어 씨가 팁을 알려주었습니다.

"임시로 {{/* debug */}}{{ .Values.something }}처럼 출력해볼 수 있어요. 또는 templates 폴더에 debug.yaml을 만들어서 ConfigMap에 원하는 값들을 넣어보는 방법도 있습니다.

문제를 찾으면 삭제하면 됩니다." 자주 발생하는 오류와 해결책을 알아두면 좋습니다. "YAML parse error"는 대부분 들여쓰기 문제입니다.

nindent의 숫자를 확인하세요. "nil pointer evaluating"은 존재하지 않는 값을 참조할 때 발생합니다.

default 함수나 조건문으로 방어하세요.

실전 팁

💡 - CI/CD 파이프라인에 helm lint와 helm template을 포함하여 배포 전 오류를 잡으세요

  • helm plugin install으로 helm-diff 같은 유용한 플러그인을 설치할 수 있습니다

10. 보안 모범 사례

보안팀에서 Helm 차트 감사를 진행했습니다. 결과 보고서에는 여러 취약점이 지적되어 있었습니다.

"values.yaml에 비밀번호가 평문으로..." 김개발 씨는 당황했습니다. 그동안 보안은 크게 신경 쓰지 않았던 것입니다.

어떻게 해야 안전하게 Helm을 사용할 수 있을까요?

Helm 차트의 보안은 시크릿 관리, 이미지 보안, RBAC 설정, 차트 서명 등 여러 측면에서 고려해야 합니다. Helm Secrets 플러그인이나 외부 시크릿 관리 도구를 사용하고, 이미지 태그는 digest로 고정하며, 최소 권한 원칙을 적용해야 합니다.

다음 코드를 살펴봅시다.

# values.yaml - 민감한 정보는 직접 넣지 않음
database:
  host: postgres.default.svc
  name: myapp
  # existingSecret을 통해 외부에서 관리되는 Secret 참조
  existingSecret: myapp-db-credentials
  existingSecretKey: password

# templates/deployment.yaml에서 Secret 참조
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: {{ .Values.database.existingSecret }}
        key: {{ .Values.database.existingSecretKey }}

# 이미지는 digest로 고정
image:
  repository: myapp
  digest: sha256:abc123def456...

보안은 처음부터 고려해야 합니다. 나중에 수정하려면 이미 많은 차트와 배포가 엉켜있어서 어렵기 때문입니다.

박시니어 씨가 Helm 보안의 핵심 원칙들을 정리해 주었습니다. 첫 번째는 시크릿 관리입니다.

절대로 values.yaml이나 차트에 비밀번호, API 키, 인증서를 평문으로 넣지 마세요. Git에 커밋되면 히스토리에서 지우기 어렵습니다.

대신 Kubernetes Secret을 별도로 생성하고, values.yaml에서는 Secret의 이름만 참조하도록 합니다. Helm Secrets 플러그인은 SOPS나 age로 암호화된 values 파일을 지원합니다.

External Secrets Operator를 사용하면 AWS Secrets Manager, HashiCorp Vault 같은 외부 저장소에서 시크릿을 가져올 수 있습니다. 두 번째는 이미지 보안입니다.

태그는 변할 수 있습니다. 누군가 악의적으로 latest 태그에 변조된 이미지를 올릴 수 있습니다.

digest를 사용하면 특정 이미지 버전을 고정할 수 있습니다. 또한 신뢰할 수 있는 레지스트리에서만 이미지를 가져오고, 이미지 스캐닝 도구로 취약점을 검사하세요.

세 번째는 RBAC 설정입니다. Helm은 kubectl과 같은 권한으로 동작합니다.

클러스터 관리자 권한으로 Helm을 실행하면 차트가 무엇이든 만들 수 있습니다. 배포 파이프라인의 서비스 계정에는 필요한 최소 권한만 부여하세요.

특정 네임스페이스에서만 리소스를 생성할 수 있도록 제한하는 것이 좋습니다. 네 번째는 차트 서명과 검증입니다.

helm package --sign으로 차트에 서명할 수 있고, helm verifyhelm install --verify로 서명을 검증할 수 있습니다. 프로덕션 환경에서는 서명된 차트만 배포하도록 정책을 수립하세요.

다섯 번째는 컨테이너 보안 컨텍스트입니다. 차트에서 생성하는 Pod에 적절한 securityContext를 설정해야 합니다.

runAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation: false 등의 설정으로 컨테이너 권한을 제한하세요. 김개발 씨가 물었습니다.

"공개 차트를 쓸 때도 주의해야 하나요?" 박시니어 씨가 강조했습니다. "물론이죠.

공개 차트를 그대로 프로덕션에 배포하면 안 됩니다. 항상 values.yaml을 검토하고, templates 폴더도 확인하세요.

어떤 리소스가 생성되는지, 어떤 권한이 필요한지 파악해야 합니다. 가능하면 사내 저장소에 검증된 차트만 올려두고 사용하는 것이 좋습니다."

실전 팁

💡 - kubeval이나 kubeconform으로 생성된 매니페스트의 스키마를 검증하세요

  • OPA Gatekeeper나 Kyverno로 보안 정책을 강제할 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Kubernetes#Helm#Chart#Release#DevOps#Data Science

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.