# Helm 차트를 올렸는데 새 기본값이 안 들어오는 이유 - values 병합 규칙
차트 버전을 올리고 나서 새 기능이 동작하지 않아 확인해 보면, 릴리스에 적용된 values가 예전 값 그대로인 경우가 있습니다. 매니페스트에는 분명히 새 값이 있는데도 그렇습니다. 원인은 대개 업그레이드 명령에 붙은 플래그 하나입니다.
Helm에는 이전 릴리스의 values를 어떻게 처리할지 정하는 플래그가 셋 있고, 셋의 동작이 미묘하게 다릅니다. 이 글에서는 그 차이가 차트 업그레이드 때 어떤 결과를 낳는지, values 스키마로 무엇을 막을 수 있는지 정리합니다.
# 1. 세 가지 병합 방식
문서의 설명을 그대로 옮기면 이렇습니다.
--reuse-values: when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f
--reset-values: when upgrading, reset the values to the ones built into the chart
--reset-then-reuse-values: when upgrading, reset the values to the ones built into the chart, apply the last release's values and merge in any overrides from the command line via --set and -f
차이를 표로 정리하면 이렇습니다.
| 플래그 | 새 차트 기본값 | 이전 릴리스 값 | 이번 -f/--set |
|---|---|---|---|
--reuse-values | 반영 안 됨 | 유지 | 덮어씀 |
--reset-values | 반영 | 버림 | 덮어씀 |
--reset-then-reuse-values | 반영 | 그 위에 덮어씀 | 덮어씀 |
문제의 핵심은 첫 줄입니다. --reuse-values는 이전 릴리스의 values를 기준으로 삼기 때문에, 차트가 새로 추가한 기본값이 들어올 자리가 없습니다. 차트 1.0에는 없던 probes.startup.enabled: true가 1.1에서 추가돼도, --reuse-values로 올리면 그 키는 존재하지 않는 상태로 렌더됩니다.
같은 명령이 차트 버전을 고정한 채 값만 바꿀 때는 편리하게 동작하기 때문에, 문제가 차트 버전을 올리는 순간에만 드러납니다. 평소에 잘 쓰던 플래그가 업그레이드 때 배신하는 구조입니다.
# 2. 그래서 어떻게 할 것인가
가장 안전한 기본값은 values를 파일로 전부 관리하고 플래그를 쓰지 않는 것입니다.
helm upgrade --install myapp ./charts/myapp \
--version 1.1.0 \
-f values/base.yaml \
-f values/prod.yaml
이 방식에서는 적용될 값이 전부 Git에 있습니다. 이전 릴리스에 무엇이 들어갔는지 추측할 필요가 없고, 차트가 새 기본값을 추가하면 자연스럽게 반영됩니다. --reuse-values가 필요해지는 상황은 대개 "어딘가에서 --set으로 넣은 값이 릴리스에만 있고 Git에는 없는" 상태이고, 그 상태 자체가 문제입니다.
값이 파일 밖에서 주입되는 것을 피할 수 없다면(예: CI가 이미지 태그를 주입) --reset-then-reuse-values가 절충안입니다. 새 차트 기본값을 받으면서 이전 값도 유지합니다. 다만 "이전 값"이 무엇인지는 여전히 릴리스에만 있으므로, 무엇이 적용될지 미리 확인하는 습관이 필요합니다.
# 현재 릴리스에 실제로 적용된 값 (사용자 지정분)
helm get values myapp
# 차트 기본값까지 포함한 전체
helm get values myapp --all
# 이번 업그레이드가 무엇을 바꾸는지 미리 확인
helm upgrade myapp ./charts/myapp --version 1.1.0 -f values/prod.yaml --dry-run
helm get values --all과 helm get values의 차이를 아는 것이 진단의 출발점입니다. 전자는 병합 결과, 후자는 사용자가 준 값입니다. 예상과 다른 값이 렌더된다면 둘을 비교해 어디서 온 값인지 좁힐 수 있습니다.
# 3. values 스키마로 막을 수 있는 것
차트를 올릴 때 values 구조가 바뀌는 경우가 있습니다. resources.limits.memory가 resources.memory로 바뀌었다면, 예전 키는 아무 데도 쓰이지 않은 채 조용히 무시됩니다. 오타도 마찬가지입니다. Helm은 values에 있는 모르는 키를 오류로 취급하지 않습니다.
values.schema.json을 차트에 두면 이 검증을 강제할 수 있습니다.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["image", "resources"],
"additionalProperties": false,
"properties": {
"image": {
"type": "object",
"required": ["repository", "tag"],
"properties": {
"repository": { "type": "string" },
"tag": { "type": "string", "minLength": 1 }
}
},
"replicaCount": { "type": "integer", "minimum": 0 }
}
}
additionalProperties: false가 핵심입니다. 스키마에 없는 키가 들어오면 실패하므로, 오타와 폐기된 키를 배포 전에 잡습니다. 다만 이 설정은 엄격해서 차트 사용자가 임의 키를 넣는 것을 막습니다. 사내 차트라면 대체로 원하는 동작이고, 외부에 배포하는 차트라면 부분적으로만 적용하는 편이 낫습니다.
검증은 렌더 전에 실행됩니다.
helm lint ./charts/myapp -f values/prod.yaml
helm template myapp ./charts/myapp -f values/prod.yaml > /dev/null
# 4. 업그레이드가 실패했을 때 무엇이 남는가
values 문제로 업그레이드가 중간에 깨지면 클러스터 상태가 어중간해집니다. 여기서 두 플래그가 의미가 있습니다.
--atomic은 실패 시 이전 릴리스로 되돌립니다. --cleanup-on-fail의 정의는 문서에 이렇게 적혀 있습니다.
allow deletion of new resources created in this upgrade when upgrade fails
이번 업그레이드에서 새로 만들어진 리소스를 정리합니다. 둘을 함께 쓰면 실패한 업그레이드가 잔여물을 남기지 않습니다.
helm upgrade --install myapp ./charts/myapp \
--version 1.1.0 -f values/prod.yaml \
--atomic --cleanup-on-fail --timeout 10m
--atomic은 롤백까지 기다리므로 타임아웃 설정이 함께 필요합니다. 그리고 롤백이 항상 무해하지는 않습니다. 스키마 마이그레이션이 이미 실행된 상태에서 애플리케이션만 되돌리면 더 나쁜 상태가 될 수 있습니다. 마이그레이션을 훅으로 돌리는 차트라면 자동 롤백을 켜기 전에 이 조합을 검토해야 합니다.
# 5. GitOps로 넘어가면 달라지는 것
배포 도구가 매니페스트를 관리하는 환경에서는 위 플래그 대부분이 의미를 잃습니다. 도구가 매번 values를 통째로 넘기기 때문에 "이전 릴리스의 값"이라는 개념이 사라집니다. 이것이 GitOps의 실질적 이점 중 하나입니다. 적용될 값이 항상 Git에 전부 있습니다.
대신 다른 문제가 생깁니다. 컨트롤러나 오토스케일러가 런타임에 바꾸는 필드를 Git이 계속 되돌립니다. 이 충돌을 다루는 방법은 ArgoCD ignoreDifferences가 동작하지 않는 세 가지 이유 (opens new window)에 정리했습니다.
기존 릴리스를 GitOps로 옮기는 과정 자체도 별도의 작업입니다. 그 절차는 수동 설치된 컴포넌트를 Helm 릴리스로 인수하고 GitOps에 넘기기 (opens new window)에 정리했습니다.
# 6. 트러블슈팅
| 증상 | 원인 | 조치 |
|---|---|---|
| 차트를 올렸는데 새 기본값이 없음 | --reuse-values | 파일 기반 관리 또는 --reset-then-reuse-values |
| values 키를 고쳤는데 반영 안 됨 | 오타·폐기된 키가 무시됨 | values.schema.json + additionalProperties: false |
| 어떤 값이 적용됐는지 모름 | 릴리스에만 존재하는 값 | helm get values --all로 비교 |
| 실패한 업그레이드 잔여물이 남음 | 정리 옵션 없음 | --atomic --cleanup-on-fail |
| 자동 롤백 후 상태가 더 나빠짐 | 마이그레이션은 되돌아가지 않음 | 훅 설계 검토 후 자동 롤백 여부 결정 |
| 로컬은 되는데 CI에서 다름 | CI가 --set으로 값 주입 | 주입 값을 파일로 옮기거나 명시적으로 관리 |
# 7. 마무리
--reuse-values는 이전 릴리스 값을 기준으로 삼기 때문에 차트가 새로 추가한 기본값을 놓칩니다. 문제는 차트 버전을 올리는 순간에만 드러납니다.- 가장 안전한 기본은 values를 전부 파일로 관리하고 병합 플래그를 쓰지 않는 것입니다.
- 오타와 폐기된 키는
values.schema.json으로 배포 전에 잡을 수 있습니다. Helm은 모르는 키를 오류로 보지 않습니다. --atomic은 편리하지만 되돌릴 수 없는 작업이 이미 실행된 경우를 함께 고려해야 합니다.