Helm lookup 함수, ArgoCD랑 같이 쓰면 함정 있다
오늘 동료가 PR 리뷰 부탁한다고 해서 봤는데, Helm chart에서 lookup 함수를 쓰는 부분이 있었다. 클러스터에 이미 떠 있는 ConfigMap을 읽어서 그 값을 기반으로 다른 리소스를 만드는 패턴. 코드는 깔끔했고 로컬 helm install로도 잘 돌았는데, 내가 한 마디 했다. "이거 ArgoCD에서 안 될걸요."
근데 동료는 "어 저번에 다른 차트에서도 비슷하게 썼는데 됐는데?"라고 했고, 결국 같이 한 번 더 들여다보기로 했다. 그 김에 정리.
lookup이 뭐였더라
lookup은 Helm 3에서 추가된 템플릿 함수다. 차트 렌더링 시점에 K8s API 서버를 쳐서 기존 리소스를 읽어올 수 있다. 예를 들면 이런 식.
{{- $existing := lookup "v1" "Secret" .Release.Namespace "db-credentials" -}}
{{- if $existing }}
password: {{ $existing.data.password }}
{{- else }}
password: {{ randAlphaNum 32 | b64enc }}
{{- end }}
이미 시크릿이 있으면 재사용하고, 없으면 새로 생성. helm upgrade할 때마다 비밀번호가 바뀌는 사고를 막는 흔한 패턴이다.
함정 1: helm template에선 항상 빈 값
근데 공식 문서에도 나와 있는데, lookup은 helm template이나 helm install --dry-run에선 클러스터 연결 자체를 안 한다. 그래서 항상 빈 dict를 리턴한다.
뭐가 문제냐면, CI에서 helm template으로 차트를 검증하는 파이프라인이 있다면 — 우리 팀도 그렇다 — 그 단계에선 lookup 결과가 항상 비어 있다는 거다. 위 예제 같은 fallback 패턴이면 그나마 괜찮은데, lookup 결과가 nil이면 panic 나는 코드는 CI에서 다 깨진다.
3.13부터 --dry-run=server 옵션이 생겼다. 이걸 쓰면 클러스터에 실제로 쿼리를 날린다. 다만 CI 러너가 클러스터 접근 권한이 있어야 해서, 실무에서 채택하려면 또 한 번 고민해야 한다.
함정 2: ArgoCD가 진짜 문제
이게 오늘의 본론. ArgoCD의 manifest 생성은 내부적으로 helm template을 쓴다. 즉 ArgoCD가 차트를 렌더링할 때 lookup은 항상 빈 값을 리턴한다. 위에서 말한 그 함정이 그대로 적용된다.
argo-cd 이슈 #5202에서 몇 년째 트래킹되고 있는 문제고, 결론은 "기본적으로 지원 안 함, 별도 플래그 필요"다. ArgoCD 2.7부터는 차트별로 helm.passCredentials나 --api-versions, 그리고 별도의 helm hook 패턴 등을 쓸 수 있는데, lookup만큼은 ArgoCD CMP(Config Management Plugin)을 만들어서 우회하는 게 현실적이다.
동료의 차트가 "저번엔 됐다"고 한 이유는 단순했다. 그 차트의 lookup 호출이 nil이어도 동작하는 fallback 경로가 있었던 거다. 즉 lookup이 작동한 게 아니라, lookup 실패 시 분기가 잘 짜여 있었던 거였다.
그래서 어떻게 쓰냐
우리 팀 가이드는 단순하다.
- lookup 결과는 항상 nil일 수 있다고 가정한다. fallback 없는 lookup은 PR 리뷰에서 막는다.
- GitOps 환경에서 비밀번호 보존이 목적이라면 ExternalSecrets나 Sealed Secrets로 가라. lookup 의존하지 마라.
- lookup이 꼭 필요하면, 그 차트는 ArgoCD가 아닌 helm CLI로 직접 배포한다. 보통 인프라 차트 한두 개에만 해당된다.
생각해보면 lookup 자체가 "선언적 GitOps"의 철학과 살짝 안 맞는다. 클러스터 상태에 따라 렌더링 결과가 바뀐다는 건, 같은 Git revision이 다른 매니페스트를 만들어낼 수 있다는 뜻이니까. 디버깅도 어렵고, 재현도 어렵다.
마무리
저번에 이거 때문에 새벽에 한 번 깬 적이 있어서 동료한테 잔소리한 것 같다. 모르고 쓰면 첫 배포는 잘 되는데, 두 번째 sync에서 갑자기 password 필드가 비어버리는 식으로 터진다. 그 시점엔 이미 앱이 DB 못 붙어서 502 깔리는 중이고.
혹시 lookup 함수 잘 쓰고 계신 분들 패턴 있으면 댓글로 공유 부탁드립니다.
'IT > Kubernets' 카테고리의 다른 글
| etcd MVCC와 compaction, defrag가 K8s API에 미치는 진짜 영향 (0) | 2026.05.02 |
|---|---|
| kubectl debug --target, 이거 모르는 분 꽤 많더라 (0) | 2026.05.02 |
| ValidatingAdmissionPolicy vs Kyverno, 정책 일부를 옮기고 나서 (0) | 2026.05.01 |
| ingress-nginx EOL 이후, ingress2gateway로 Gateway API 옮기기 (0) | 2026.05.01 |
| Cilium Hubble로 Network Policy 디버깅하기 (0) | 2026.04.30 |