Helm 차트 제작과 배포 · 범위와 공백 · 실습
렌더 결과가 YAML 이 아니었다 — 범위와 공백
목표
with·range 가 점을 바꾸는 것, 공백 다듬기가 줄을 붙여 버리는 것, 따옴표를 뺀 값이 숫자와 불리언이 되는 것을 각각 일부러 일으켜 보고, --debug·required·fail·helm lint --strict 로 막는 법까지 간다.
왜 중요한가
템플릿에서 나는 사고의 대부분은 함수를 몰라서가 아니라 결과가 YAML 이 아니게 되어서 난다. 그래서 오류 메시지가 원인을 가리키지 않는다. mapping values are not allowed in this context 는 YAML 파서의 말이지 템플릿의 말이 아니라서, 그 줄을 아무리 들여다봐도 -}} 하나가 범인이라는 것은 보이지 않는다. 같은 이유로 with 안에서 .Release 가 nil 이라는 메시지도 '점이 바뀌었다' 는 사실을 알기 전에는 읽히지 않는다. 여기에 따옴표 문제가 겹치면 렌더까지는 멀쩡히 되고 클러스터가 거절한다 — 배포 파이프라인의 가장 늦은 지점에서 터지는 종류다. 이 넷을 한 번씩 직접 만들어 보면 다음부터는 메시지 두 줄만 보고 어디를 볼지 정할 수 있다.
단계
1. /root/hc-scope/frontier 차트(이름 frontier, 버전 0.1.0)를 만들고 values.yaml 에 app(name portal, team core, port 8080), notes(owner sre, runbook wiki/portal), envs(STAGE, PROD), release(tag "1.10", enabled "no") 를 두세요. templates/base.yaml 은 이름이 .Values.app.name, data.port 가 따옴표로 감싼 포트인 ConfigMap 입니다. helm template web /root/hc-scope/frontier 결과를 /root/hc-scope/out/base.yaml 에 저장하세요.
2. /root/hc-scope/frontier/templates/scoped.yaml 을 만드세요. 이름은 <app.name>-scoped, 그 아래를 {{- with .Values.app }} 블록으로 감싸고 그 안에서 data.release 를 {{ .Release.Name }}, data.team 을 {{ .team }} 로 씁니다. 렌더하면 실패합니다 — 그 출력을 /root/hc-scope/out/with-error.txt 에 저장하세요.
3. /root/hc-scope/frontier/templates/scoped.yaml 에서 with 블록은 그대로 두고 data.release 만 고쳐 릴리스 이름이 렌더되게 하세요. 렌더 결과를 /root/hc-scope/out/scoped.yaml 에 저장합니다 (릴리스 이름 web). data 에는 release: web 과 team: core 두 줄이 나와야 합니다.
4. /root/hc-scope/frontier/templates/envs.yaml 을 만드세요. 이름은 <app.name>-envs 이고, .Values.envs 를 인덱스와 값 두 변수로 받아 돌면서 data 에 <소문자 환경이름>: "<인덱스>-<app.port>" 한 줄씩 냅니다. 렌더 결과에 stage: "0-8080" 과 prod: "1-8080" 이 나와야 합니다. 결과를 /root/hc-scope/out/envs.yaml 에 저장하세요.
5. /root/hc-scope/broken 차트(이름 broken)를 따로 만들고 values.yaml 에 app(name portal, team core)과 notes(owner sre, runbook wiki/portal)를 두세요. templates/portal.yaml 은 annotations: 아래 줄에서 {{- toYaml .Values.notes | indent 4 -}} 로 주석을 꽂고 그 뒤에 labels: 가 오는 모양입니다. 렌더하면 실패합니다 — 보통 출력은 /root/hc-scope/out/ws-error.txt 에, --debug 를 붙인 출력은 /root/hc-scope/out/ws-debug.txt 에 저장하세요. 이 차트는 고치지 말고 그대로 둡니다.
6. /root/hc-scope/broken 을 /root/hc-scope/fixed 로 복사하고(차트 이름은 fixed 로 바꿉니다) templates/portal.yaml 만 고쳐 렌더가 성공하게 만드세요. 주석 블록은 annotations: 아래에 네 칸 들여써서 두 줄로, labels.team 은 core 로 나와야 합니다. 결과를 /root/hc-scope/out/fixed.yaml 에 저장하세요.
7. /root/hc-scope/frontier/templates/release.yaml 을 만드세요. 이름은 <릴리스이름>-release, data.tag 는 .Values.release.tag, data.enabled 는 .Values.release.enabled 를 따옴표 없이 꽂습니다. 이 템플릿만 렌더해 yq -o=json 을 거친 결과를 /root/hc-scope/out/quote-yaml12.json 에, 그 렌더를 kubectl apply --dry-run=server 에 넣은 출력을 /root/hc-scope/out/quote-error.txt 에 저장하세요. 그다음 두 값에 quote 를 걸어 고치고, 다시 서버 검증을 통과한 출력을 /root/hc-scope/out/quote-ok.txt 에 저장하세요.
8. /root/hc-scope/frontier/templates/guard.yaml 을 만드세요. 포트가 1024 미만이면 fail 로 멈추고, data.team 은 required 로 값이 없을 때 멈춥니다. 정상 값으로는 이름이 <app.name>-guard 인 ConfigMap 이 나와야 합니다. --set app.port=80 으로 렌더한 출력을 /root/hc-scope/out/guard-fail.txt 에, --set app.team=null 로 렌더한 출력을 /root/hc-scope/out/guard-required.txt 에 저장하고, 옵션 없이 렌더한 전체 결과를 /root/hc-scope/out/guard-ok.yaml 에 저장하세요.
9. /root/hc-scope/lintbad 차트(이름 lintbad)를 만들고 templates/cm.yaml 의 ConfigMap 이름을 Bad_Name 으로 두세요. helm lint 의 출력과 종료 코드를 /root/hc-scope/out/lint-plain.txt 에, helm lint --strict 의 출력과 종료 코드를 /root/hc-scope/out/lint-strict.txt 에 저장하세요. 두 파일의 마지막 줄에 exit=<종료 코드> 를 덧붙입니다. 같은 차트인데 통과 여부가 갈리는 것이 이 단계의 답입니다.
참고
helm template --debug는 YAML 로 파싱되지 않는 결과도 그대로 보여 준다helm template <릴리스> <차트> -s templates/<파일>로 한 템플릿만 렌더한다- 키 바로 아래에 블록을 꽂을 때는
indent가 아니라nindent - 흔한 실수:
with블록 안에서.Release·.Chart를 그대로 쓴다 — 뿌리는$다 - 흔한 실수: 태그 끝의
-}}가 다음 줄을 앞줄에 붙인다 - 공식 문서: https://helm.sh/docs/chart_template_guide/control_structures/ · https://helm.sh/docs/chart_template_guide/variables/ · https://helm.sh/docs/chart_template_guide/yaml_techniques/
단계 9개
- 값 구조를 먼저 깔고 한 번 렌더한다
- with 안에서 .Release 를 찾지 못한다
- 달러 기호로 뿌리를 다시 잡는다
- range 안에서도 뿌리 값을 함께 쓴다
- 공백 다듬기 하나가 YAML 을 무너뜨린다
- nindent 로 줄바꿈까지 넘겨 준다
- 따옴표를 빼먹자 클러스터가 거절했다
- 잘못된 값이면 렌더 단계에서 멈춘다
- 경고를 오류로 다루게 만든다