왜 환경별 values 파일이 문제가 되는가
가장 흔한 시작점은 values-dev.yaml, values-staging.yaml, values-prod.yaml을 각각 통째로 복제하는 방식이다. 처음엔 편하지만 시간이 지나면 세 파일이 서로 드리프트(drift)한다. dev에서만 바꾼 리소스 리밋이 prod에 반영되지 않거나, 공통 설정 하나를 고치려고 세 파일을 모두 편집하다가 하나를 빠뜨린다. 결국 "환경별로 다른 값이 정확히 무엇인가"가 파일 전체에 묻혀버려서 리뷰가 불가능해진다.
핵심은 공통 기본값(base)과 환경별 차이(overlay)를 분리하는 것이다. Helm은 -f 플래그를 여러 번 받을 수 있고, 뒤에 오는 파일이 앞의 값을 병합/덮어쓰기한다. 이 병합 규칙을 이용하면 환경 파일에는 "차이"만 남길 수 있다.
기본 오버레이 병합 동작
values.yaml에 공통값을 두고, 환경 파일에는 달라지는 키만 적는다. Helm은 스칼라/맵은 깊게 병합하지만 리스트는 통째로 교체한다는 점이 가장 중요한 함정이다.
# values.yaml (base)
replicaCount: 2
image:
repository: registry.int4.io/api
tag: "1.0.0"
pullPolicy: IfNotPresent
resources:
requests:
cpu: 100m
memory: 128Mi
# values-prod.yaml (overlay — 차이만)
replicaCount: 6
image:
tag: "1.4.2" # repository/pullPolicy는 base 유지
resources:
requests:
cpu: 500m
memory: 512Mi
배포는 base를 먼저, overlay를 나중에 지정한다. 순서가 곧 우선순위다.
helm upgrade --install api ./chart \
-f values.yaml \
-f values-prod.yaml \
--namespace prod --create-namespace
레이어 순서와 우선순위
실무에서는 보통 세 겹으로 쌓는다. 공통 → 환경 → 인스턴스/시크릿 순이며, 마지막 --set이 최우선이다.
| 레이어 | 내용 | 커밋 대상 |
|---|---|---|
| values.yaml | 모든 환경 공통 기본값 | Git |
| values-<env>.yaml | 환경별 차이(리소스, 레플리카, 도메인) | Git |
| --set / 외부 시크릿 | 이미지 태그, 동적 값, 민감정보 | CI 파이프라인 주입 |
이미지 태그처럼 배포마다 바뀌는 값을 values 파일에 넣지 말자. CI에서 --set image.tag=$GIT_SHA로 주입해야 파일 커밋 없이 롤백/추적이 깔끔해진다.
리스트 병합 함정 다루기
환경별로 env 배열이나 ingress.hosts를 조금만 추가하려 해도, overlay에서 리스트를 쓰면 base 리스트 전체가 사라진다. 해결책은 두 가지다. 첫째, 리스트를 맵으로 모델링해서 깊은 병합이 되게 한다.
# base: 리스트 대신 맵으로 설계
extraEnv:
LOG_LEVEL: info
POOL_SIZE: "10"
# overlay-prod: 특정 키만 덮어쓰기
extraEnv:
LOG_LEVEL: warn
템플릿에서 range $k, $v := .Values.extraEnv로 순회하면 두 레이어가 안전하게 합쳐진다. 둘째, 정말 리스트가 필요하면 환경 파일에 전체 리스트를 명시적으로 다시 적고, 그 사실을 주석으로 남겨 리뷰어가 인지하게 한다.
렌더링 검증을 CI에 넣기
오버레이는 실제 배포 전에 최종 결과를 눈으로 확인할 수 있어야 한다. helm template으로 병합 결과를 렌더링하고 --dry-run으로 서버 검증까지 파이프라인에 건다.
# CI: 병합 결과 diff 확인 + 서버 유효성 검사
helm template api ./chart -f values.yaml -f values-prod.yaml \
| kubectl diff -f - || true
helm upgrade --install api ./chart \
-f values.yaml -f values-prod.yaml \
--namespace prod --dry-run=server
kubectl diff는 클러스터 현재 상태와 렌더 결과의 차이만 보여주므로, PR 리뷰에서 "이 배포가 무엇을 바꾸는가"를 정확히 판단할 수 있다.
주의점 정리
- 시크릿을 values 파일에 넣지 않는다. External Secrets, SOPS, 또는 CI 변수로 주입하고 Git에는 참조만 남긴다.
- 환경 파일은 최대한 짧게. overlay가 100줄을 넘으면 base 설계가 잘못됐다는 신호다. 공통값을 base로 끌어올려라.
- 레이어 순서를 스크립트로 고정한다. 사람이 매번
-f를 손으로 나열하면 순서 실수가 난다. Makefile이나 헬퍼 스크립트로 감싼다. - 리스트 병합 규칙을 팀 규약으로. 리스트 통째 교체 동작을 모르는 팀원이 base 값을 날리는 사고가 가장 흔하다.
정리하면, values 파일을 복제하지 말고 base+overlay로 쪼개되 리스트 병합만 주의하면, 환경별 차이가 diff 한 줄로 드러나는 관리 가능한 배포 구조를 얻는다.