LabHub

GitOps 와 ArgoCD · 헬름·Kustomize 연동 · 이론

환경 차이를 다루는 두 가지 문법

LabHub 에서 이어서 보기

한 줄 요약

dev·prod 의 차이를 YAML 복사본으로 표현하면 반드시 갈라지고, Kustomize 오버레이나 Helm 값 파일로 표현하면 차이만 파일로 남는다.

왜 이게 필요했나

같은 앱을 세 환경에 배포한다고 하자. replicas, 로그 레벨, 이미지 태그 세 가지만 다르다. 이때 deployment-dev.yaml, deployment-prod.yaml 을 각각 만들면 처음 한 달은 편하다. 그러나 여섯 달이 지나면 두 파일은 서로 다른 생물이 된다. prod 에만 추가한 보안 설정이 dev 에는 없고, dev 에서 고친 프로브 설정이 prod 에는 반영되지 않는다. 어느 쪽이 정답인지 아무도 모르는 상태가 되는 순간 "dev 에서는 됐는데요"라는 문장이 시작된다.

해법의 방향은 같다. 공통을 한 번만 쓰고 차이만 따로 적는다. Kustomize 는 이것을 "베이스에 패치를 얹는다"로 풀고, Helm 은 "템플릿에 값을 주입한다"로 푼다.

어떻게 동작하나

Kustomize 의 단위는 kustomization.yaml 이다. 베이스에는 완전한 매니페스트와 그것을 묶는 지시서가 있고, 오버레이는 베이스를 resources 로 가져와 변형만 적는다.

| 필드 | 하는 일 |
| --- | --- |
| resources | 무엇을 가져올지 (파일 또는 다른 kustomization 디렉터리) |
| namePrefix / nameSuffix | 이름 앞뒤에 붙일 문자열 |
| namespace | 모든 리소스의 네임스페이스를 일괄 지정 |
| labels (구 commonLabels) | 모든 리소스에 공통 라벨 부착 |
| patches | 전략적 병합 패치로 특정 필드만 덮어쓰기 |
| images | 이미지 이름/태그를 갈아 끼우기 |
| configMapGenerator | 파일·리터럴로 ConfigMap 을 생성 |

중요한 성질이 둘 있다. 첫째, kustomize build 의 결과에는 Kustomization 자체가 들어 있지 않다. 그것은 결과물이 아니라 지시서이기 때문이다. 빌드 결과에 Kustomization 이 섞여 나온다면 어딘가에서 지시서를 resources 로 잘못 가져온 것이다.

둘째, configMapGenerator 가 만든 ConfigMap 이름 끝에는 내용 해시가 붙는다. app-config-9b2f4kt6md 같은 이름이 되고, 그 ConfigMap 을 참조하는 Deployment 의 참조 이름도 자동으로 같이 바뀐다. 이 설계 덕분에 설정 파일을 고치면 파드 템플릿이 달라져 롤아웃이 저절로 일어난다. 해시가 없으면 ConfigMap 만 바뀌고 파드는 옛 설정을 들고 계속 도는, 원인 찾기 가장 어려운 부류의 사고가 난다.

Helm 은 접근이 다르다. 템플릿에 values.yaml 을 주입해 매니페스트를 만들고, 환경 차이는 values-prod.yaml 같은 값 파일이나 개별 파라미터로 준다. ArgoCD 에서 이 둘은 spec.source.helm.valueFilesspec.source.helm.parameters 에 대응한다. 여기서 반드시 알아야 할 것 하나 — ArgoCD 는 helm install 을 하지 않는다. repo-server 가 helm template 로 매니페스트를 렌더한 뒤 그것을 apply 한다. 그래서 클러스터에서 helm list 를 해도 아무것도 나오지 않고, 롤백도 Helm 리비전이 아니라 git 커밋으로 한다.

현장에서 만나는 모습

첫째, 베이스를 고쳐 dev 를 맞추는 실수. dev 의 replicas 를 1로 하고 싶어서 베이스를 1로 고치면 prod 까지 1이 된다. 베이스는 모든 환경의 공통분모여야 하고, 환경 고유의 값은 반드시 오버레이에 있어야 한다.

둘째, targetRevision: HEAD 의 함정. 브랜치의 최신을 따라가면 편하지만, 같은 Application 정의가 시점마다 다른 것을 배포한다. 재현 가능한 배포를 원한다면 태그나 커밋 해시로 고정한다. :latest 이미지 태그를 금지하는 것과 정확히 같은 이유다.

셋째, 이름 접두어와 패치 대상. 베이스에 namePrefix 가 붙어 있으면 빌드 결과의 이름은 labhub-web 이지만, 패치는 베이스에 적힌 원래 이름으로 대상을 찾는다. 이 규칙을 모르면 "패치가 적용이 안 된다"에서 한참 헤맨다.

다음 실습에서 할 것

/root/gitops/kustomize/ 아래에 베이스와 dev·prod 오버레이를 만들고, 이름 접두어·공통 라벨·네임스페이스·전략적 병합 패치·configMapGenerator·images 를 하나씩 얹으며 kustomize build 결과가 어떻게 달라지는지 파일로 남긴다. 그다음 Helm 소스를 쓰는 Application 과 Kustomize 오버레이를 가리키는 Application 을 각각 작성해, ArgoCD 가 두 문법을 어떻게 받아들이는지 선언으로 표현한다.