Helm 차트 제작과 배포 · 템플릿과 values · 실습
템플릿 함수로 values 를 안전하게 꽂기
목표
템플릿 함수로 values 를 안전하게 매니페스트에 꽂고, 값이 없을 때·필수일 때·블록일 때 각각 어떤 도구를 써야 하는지 손으로 익힙니다.
왜 중요한가
Helm 템플릿은 YAML 편집기가 아니라 문자열 생성기입니다. 최종 결과가 문자열로 완성된 뒤에야 YAML 파서가 그것을 읽습니다. 그래서 들여쓰기가 두 칸 어긋나면 오류가 나는 대신 블록이 통째로 사라지거나 엉뚱한 부모 밑으로 들어갑니다. toYaml 로 편 블록에 nindent 를 반드시 붙이는 이유가 여기 있습니다 — indent 는 앞의 줄바꿈을 만들어 주지 않아 첫 줄이 앞 키에 그대로 붙습니다. 값 설계도 마찬가지입니다. default 는 "없어도 되는 값"에, required 는 "없으면 배포하면 안 되는 값"에 씁니다. 이 둘을 뒤집으면 잘못된 기본값으로 조용히 배포되거나, 반대로 아무나 못 쓰는 차트가 됩니다. 마지막으로 값의 우선순위는 낮은 것부터 차트의 values.yaml, -f 로 준 파일들(왼쪽에서 오른쪽), --set 순서이며, 맵은 깊게 병합되지만 리스트는 통째로 교체된다는 점을 꼭 기억하세요.
단계
1. /root/helm/tpl/labhub-api 에 차트를 만드세요(helm create labhub-api 로 시작해도 좋습니다). values.yaml 의 image.repository 는 nginx, image.tag 는 "1.27" 로 두고 Chart.yaml 의 appVersion 은 "1.26" 으로 둡니다. 그다음 helm template labhub-api /root/helm/tpl/labhub-api > /root/helm/tpl/out/base.yaml 로 렌더링을 저장하세요. 결과에 Deployment 가 있고 컨테이너 이미지가 저장소:태그 형태여야 하며, 중괄호나 <no value> 가 남아 있으면 안 됩니다.
2. 컨테이너 이미지 태그를 {{ .Values.image.tag | default .Chart.AppVersion }} 처럼 쓰고, helm template labhub-api /root/helm/tpl/labhub-api --set image.tag="" > /root/helm/tpl/out/default.yaml 을 저장하세요. 태그를 비웠는데도 이미지에는 nginx:1.26 처럼 태그가 붙어 있어야 하며, 기본값으로 latest 를 쓰면 안 됩니다.
3. values.yaml 에 ingress.enabled: true 와 ingress.host: api.labhub.local 을 두고, /root/helm/tpl/labhub-api/templates/ingress.yaml 에서 호스트를 required 로 감싸세요(예: {{ required "ingress.host 를 반드시 지정하세요" .Values.ingress.host }}). 그다음 helm template labhub-api /root/helm/tpl/labhub-api --set ingress.host="" > /root/helm/tpl/out/required-error.txt 2>&1 로 일부러 실패시키고 그 출력을 저장하세요. 파일에는 렌더링 실패 메시지와 함께 어떤 키가 빠졌는지가 보여야 합니다.
4. values.yaml 의 resources 를 limits.cpu: 500m, limits.memory: 512Mi, requests.cpu: 100m, requests.memory: 128Mi 로 채우고, Deployment 컨테이너에서 {{- toYaml .Values.resources | nindent 12 }} 형태로 통째로 넘기세요. /root/helm/tpl/out/base.yaml 을 다시 렌더링하면 컨테이너의 resources.limits.cpu 와 resources.requests.memory 가 보여야 합니다.
5. values.yaml 에 env 를 맵으로 두고 APP_MODE: server, LOG_LEVEL: info, TZ: Asia/Seoul 세 개를 정의하세요. Deployment 에서 range $k, $v := .Values.env 로 컨테이너 env 목록을 만듭니다. /root/helm/tpl/out/base.yaml 의 컨테이너 env 는 정확히 3개여야 하고 그중 하나의 이름이 LOG_LEVEL 이어야 합니다.
6. /root/helm/tpl/labhub-api/templates/_helpers.tpl 에 define 으로 차트 식별 문자열(이름-버전)을 만들고, Deployment 의 metadata.annotations 에 labhub.io/chart: {{ include "labhub-api.chart" . }} 를 붙이세요. 그리고 /root/helm/tpl/out/include-note.txt 에 template 과 include 의 차이를 한 줄로 적으세요 — include 는 결과를 문자열로 반환하므로 파이프로 이어 후처리(들여쓰기)를 할 수 있다는 내용이 들어가야 합니다.
7. /root/helm/tpl/values-base.yaml 에 replicaCount: 2, env.LOG_LEVEL: info, image.tag: base 를, /root/helm/tpl/values-stage.yaml 에 replicaCount: 4, env.LOG_LEVEL: debug, image.tag: stage 를 두세요. 그다음 helm template labhub-api /root/helm/tpl/labhub-api -f /root/helm/tpl/values-base.yaml -f /root/helm/tpl/values-stage.yaml --set image.tag=cli > /root/helm/tpl/out/merged.yaml 을 실행하세요. 결과의 replicas 는 4, LOG_LEVEL 은 debug, 이미지 태그는 cli 여야 합니다. 마지막으로 /root/helm/tpl/out/precedence.txt 에 우선순위를 낮은 것부터 한 줄씩 적으세요: 차트의 values.yaml, -f values-base.yaml, -f values-stage.yaml, --set.
8. ConfigMap 템플릿을 추가해 values.yaml 의 config 맵을 data 로 내보내고, 파드 템플릿의 metadata.annotations 에 checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 를 붙이세요. 파드 수준 spec.template.spec.securityContext.runAsNonRoot 는 true 가 되어야 합니다. 완성된 렌더링을 /root/helm/tpl/out/final.yaml 로 저장하세요(오브젝트 3개 이상, 컨테이너 env 3개 이상, <no value> 없음). 그리고 helm lint /root/helm/tpl/labhub-api > /root/helm/tpl/out/lint.txt 도 저장하며 [ERROR] 가 없어야 합니다.
참고
- 실습 파드는 실습마다 새로 뜨므로 다른 실습에서 만든 차트는 남아 있지 않습니다. 이 실습의 차트도
/root/helm/tpl아래에 처음부터 만듭니다 — 차트가 곧 재현 가능한 패키지라는 사실이 여기서 드러납니다. helm template ... -s templates/deployment.yaml로 한 파일만 볼 수 있고,--debug를 붙이면 실패한 렌더링의 중간 결과까지 보여 줍니다.- 4·5·6번에서 템플릿을 고친 뒤에는
/root/helm/tpl/out/base.yaml을 반드시 다시 렌더링해 덮어쓰세요. 1·4·5·6번 채점이 모두 이 파일 하나를 봅니다. - 흔한 실수 1:
indent를 써서 블록의 첫 줄이 앞 키에 붙는 것. 앞에 줄바꿈이 필요하면nindent입니다. - 흔한 실수 2: 값 파일 두 개를 주면 리스트도 합쳐질 거라 기대하는 것. 맵은 깊게 병합되지만 리스트는 통째로 교체됩니다. 이 실습에서
env를 리스트가 아닌 맵으로 설계한 이유입니다.
단계 8개
- values 를 참조해 렌더링하기
- default 로 빈 값 메우기
- required 로 필수 값 강제하기
- toYaml 과 nindent 로 블록 넘기기
- range 로 환경변수 펼치기
- 네임드 템플릿 정의하고 include 하기
- 값 우선순위 확인하기
- 설정 해시와 보안 컨텍스트까지 붙이기