LabHub
배우기 러닝패스 코스

Authoring and Shipping Helm Charts

Injecting values Safely With Template Functions

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

템플릿 함수로 values 를 안전하게 매니페스트에 꽂고, 값이 없을 때·필수일 때·블록일 때 각각 어떤 도구를 써야 하는지 손으로 익힙니다.

왜 중요한가

Helm 템플릿은 YAML 편집기가 아니라 문자열 생성기입니다. 최종 결과가 문자열로 완성된 뒤에야 YAML 파서가 그것을 읽습니다. 그래서 들여쓰기가 두 칸 어긋나면 오류가 나는 대신 블록이 통째로 사라지거나 엉뚱한 부모 밑으로 들어갑니다. toYaml 로 편 블록에 nindent 를 반드시 붙이는 이유가 여기 있습니다 — indent 는 앞의 줄바꿈을 만들어 주지 않아 첫 줄이 앞 키에 그대로 붙습니다. 값 설계도 마찬가지입니다. default 는 "없어도 되는 값"에, required 는 "없으면 배포하면 안 되는 값"에 씁니다. 이 둘을 뒤집으면 잘못된 기본값으로 조용히 배포되거나, 반대로 아무나 못 쓰는 차트가 됩니다. 마지막으로 값의 우선순위는 낮은 것부터 차트의 values.yaml, -f 로 준 파일들(왼쪽에서 오른쪽), --set 순서이며, 맵은 깊게 병합되지만 리스트는 통째로 교체된다는 점을 꼭 기억하세요.

단계

  1. /root/helm/tpl/labhub-api 에 차트를 만드세요(helm create labhub-api 로 시작해도 좋습니다). values.yamlimage.repositorynginx, image.tag"1.27" 로 두고 Chart.yamlappVersion"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.yamlingress.enabled: trueingress.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.yamlresourceslimits.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.cpuresources.requests.memory 가 보여야 합니다.
  5. values.yamlenv으로 두고 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.tpldefine 으로 차트 식별 문자열(이름-버전)을 만들고, Deployment 의 metadata.annotationslabhub.io/chart: {{ include "labhub-api.chart" . }} 를 붙이세요. 그리고 /root/helm/tpl/out/include-note.txttemplateinclude 의 차이를 한 줄로 적으세요 — include 는 결과를 문자열로 반환하므로 파이프로 이어 후처리(들여쓰기)를 할 수 있다는 내용이 들어가야 합니다.
  7. /root/helm/tpl/values-base.yamlreplicaCount: 2, env.LOG_LEVEL: info, image.tag: base 를, /root/helm/tpl/values-stage.yamlreplicaCount: 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_LEVELdebug, 이미지 태그는 cli 여야 합니다. 마지막으로 /root/helm/tpl/out/precedence.txt 에 우선순위를 낮은 것부터 한 줄씩 적으세요: 차트의 values.yaml, -f values-base.yaml, -f values-stage.yaml, --set.
  8. ConfigMap 템플릿을 추가해 values.yamlconfig 맵을 data 로 내보내고, 파드 템플릿의 metadata.annotationschecksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 를 붙이세요. 파드 수준 spec.template.spec.securityContext.runAsNonRoottrue 가 되어야 합니다. 완성된 렌더링을 /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] 가 없어야 합니다.

참고

values 를 참조해 렌더링하기

/root/helm/tpl/labhub-api 에 차트를 만드세요(helm create labhub-api 로 시작해도 좋습니다). values.yamlimage.repositorynginx, image.tag"1.27" 로 두고 Chart.yamlappVersion"1.26" 으로 둡니다. 그다음 helm template labhub-api /root/helm/tpl/labhub-api > /root/helm/tpl/out/base.yaml 로 렌더링을 저장하세요. 결과에 Deployment 가 있고 컨테이너 이미지가 저장소:태그 형태여야 하며, 중괄호나 <no value> 가 남아 있으면 안 됩니다.

이미지는 저장소와 태그를 각각 values 에서 가져와 조합합니다. 렌더링 결과에 중괄호나 '' 가 남았다면 참조한 키가 values 에 없다는 뜻입니다.

default 로 빈 값 메우기

컨테이너 이미지 태그를 {{ .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 를 쓰면 안 됩니다.

태그를 비운 채 렌더링해도 이미지에 태그가 붙어야 합니다. 대신 쓸 값을 Chart.yaml 에서 가져오면 차트와 앱 버전이 자연히 맞습니다. latest 는 답이 아닙니다.

required 로 필수 값 강제하기

values.yamlingress.enabled: trueingress.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 로 일부러 실패시키고 그 출력을 저장하세요. 파일에는 렌더링 실패 메시지와 함께 어떤 키가 빠졌는지가 보여야 합니다.

필수 값이 비면 렌더링 자체가 실패해야 합니다. 오류 메시지에는 어떤 키가 빠졌는지 적으세요. 실패 출력은 표준 오류로 나오므로 저장할 때 함께 받아야 합니다.

toYaml 과 nindent 로 블록 넘기기

values.yamlresourceslimits.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.cpuresources.requests.memory 가 보여야 합니다.

리소스 제한처럼 통째로 넘길 블록은 한 줄씩 쓰지 않습니다. 앞에 줄바꿈이 필요한지 아닌지가 두 들여쓰기 함수의 차이입니다.

range 로 환경변수 펼치기

values.yamlenv으로 두고 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 이어야 합니다.

values 의 맵을 키와 값 두 변수로 받아 반복합니다. 값은 따옴표로 감싸는 편이 안전합니다. 정확히 세 개가 나와야 합니다.

네임드 템플릿 정의하고 include 하기

/root/helm/tpl/labhub-api/templates/_helpers.tpldefine 으로 차트 식별 문자열(이름-버전)을 만들고, Deployment 의 metadata.annotationslabhub.io/chart: {{ include "labhub-api.chart" . }} 를 붙이세요. 그리고 /root/helm/tpl/out/include-note.txttemplateinclude 의 차이를 한 줄로 적으세요 — include 는 결과를 문자열로 반환하므로 파이프로 이어 후처리(들여쓰기)를 할 수 있다는 내용이 들어가야 합니다.

define 으로 만든 조각을 어노테이션 자리에 끼워 넣습니다. 두 호출 방식 중 파이프로 이어 쓸 수 있는 쪽이 무엇인지, 그 이유가 무엇인지 메모로 남기세요.

값 우선순위 확인하기

/root/helm/tpl/values-base.yamlreplicaCount: 2, env.LOG_LEVEL: info, image.tag: base 를, /root/helm/tpl/values-stage.yamlreplicaCount: 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_LEVELdebug, 이미지 태그는 cli 여야 합니다. 마지막으로 /root/helm/tpl/out/precedence.txt 에 우선순위를 낮은 것부터 한 줄씩 적으세요: 차트의 values.yaml, -f values-base.yaml, -f values-stage.yaml, --set.

값 파일 두 개와 명령줄 옵션을 한 번에 걸어 보세요. 값 파일은 준 순서가 의미를 가집니다. 결과를 보고 낮은 것부터 순서를 적으세요.

설정 해시와 보안 컨텍스트까지 붙이기

ConfigMap 템플릿을 추가해 values.yamlconfig 맵을 data 로 내보내고, 파드 템플릿의 metadata.annotationschecksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 를 붙이세요. 파드 수준 spec.template.spec.securityContext.runAsNonRoottrue 가 되어야 합니다. 완성된 렌더링을 /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] 가 없어야 합니다.

ConfigMap 내용이 바뀌어도 파드가 안 바뀌는 문제를 막는 관례가 있습니다. 렌더링된 설정 파일의 해시를 파드 어노테이션에 넣으세요. 파드 수준 보안 설정도 함께 채웁니다.