LabHub

Helm 차트 제작과 배포 · 배포·업그레이드·롤백 · 이론

릴리스 — 클러스터 안에 남는 배포의 기억

LabHub 에서 이어서 보기

한 줄 요약

릴리스는 명령의 기록이 아니라 클러스터 안에 저장된 상태이고, 그 상태는 리비전마다 시크릿 하나로 쌓인다.

왜 이게 필요했나

kubectl apply 로 배포하면 "지금 무엇이 떠 있는지"는 알 수 있어도 "어제는 무엇이 떠 있었는지"는 알 수 없다. 문제가 생겼을 때 되돌리려면 이전 매니페스트를 어딘가에서 찾아와야 하는데, 그 어딘가가 사람의 기억이거나 누군가의 노트북인 경우가 대부분이다.

Helm 은 이 문제를 "배포할 때마다 그 배포의 전체 스냅샷을 클러스터에 남긴다"로 푼다. 남는 것은 렌더링된 매니페스트만이 아니다. 그때 쓴 차트 메타데이터, 사용자가 넘긴 값, 상태, 릴리스 노트가 통째로 들어간다. 그래서 롤백이 "예전 파일 찾기"가 아니라 "저장된 리비전 고르기"가 된다.

어떻게 동작하나

Helm 3 에는 클러스터 안에 상주하는 서버 컴포넌트가 없다. CLI 가 kubeconfig 로 API 서버와 직접 이야기하므로 쿠버네티스 RBAC 이 그대로 적용된다. 그러면 상태는 어디에 두나 — 릴리스가 설치된 네임스페이스의 Secret 에 둔다.

| 항목 | 값 |
| --- | --- |
| 시크릿 이름 | sh.helm.release.v1.<릴리스이름>.v<리비전번호> |
| 시크릿 타입 | helm.sh/release.v1 |
| 라벨 | owner=helm, name=<릴리스이름>, status=<상태> |
| 내용 | 차트 메타데이터, 렌더링된 매니페스트, values, 상태, 노트를 gzip 압축 후 base64 인코딩 |

리비전마다 시크릿이 하나씩 늘어난다. 그래서 kubectl get secret -l owner=helm 만 봐도 그 네임스페이스의 배포 역사가 몇 겹인지 보인다. 기본적으로 최근 10개까지 보관하며 --history-max 로 조절한다.

업그레이드는 단순한 덮어쓰기가 아니다. Helm 3 는 세 가지를 비교한다 — 이전 리비전의 매니페스트, 지금 클러스터의 실제 상태, 그리고 새로 렌더링한 매니페스트. 이것이 three-way strategic merge patch 다. 덕분에 누군가 kubectl 로 직접 손댄 필드를 알아채고, 차트가 관리하지 않는 필드는 건드리지 않으며, 바뀐 것만 골라 적용한다.

그리고 반드시 기억할 두 가지 성질이 있다.

첫째, 실패한 업그레이드도 리비전으로 남는다. 렌더링은 됐는데 API 서버가 거부했다면 그 리비전은 failed 상태로 기록되고, 실물은 이전 상태 그대로 남는다. 이력에 실패가 남는 것은 사고가 아니라 기능이다 — 무엇을 시도했다가 왜 안 됐는지가 클러스터에 남는다.

둘째, 롤백은 되돌리는 것이 아니라 새 리비전을 만드는 일이다. 리비전 2로 롤백하면 번호가 2로 돌아가는 것이 아니라, 리비전 2의 차트와 values 로 계산한 새 리비전 4가 생긴다. 리비전 번호는 언제나 앞으로만 간다. 이 성질 덕분에 "롤백했다가 다시 롤백을 취소하는" 일도 이력에 온전히 남는다.

값을 조회하는 방법도 두 갈래다. helm get values 는 사용자가 실제로 넘긴 값만, -a(--all)를 붙이면 차트 기본값까지 병합된 최종 값을 보여 준다. --revision N 을 함께 주면 특정 리비전의 값을 볼 수 있다. 장애 대응에서 "이 설정이 기본값인가 누가 넣은 값인가"를 가르는 것이 이 두 명령의 차이다.

현장에서 만나는 모습

첫째, 멈춰 버린 pending 상태. 업그레이드 중 프로세스가 죽으면 릴리스가 pending-upgrade 로 남아 다음 명령이 거부된다. 이때 필요한 것은 시크릿을 손으로 지우는 것이 아니라 마지막 성공 리비전으로 롤백해 상태를 정리하는 일이다.

둘째, --atomic 의 두 얼굴. --atomic--wait 를 포함하고 실패 시 자동으로 되돌려 주므로 파이프라인에 좋다. 그런데 자동으로 되돌아가 버리면 실패한 상태를 관찰할 기회가 사라진다. 원인을 봐야 하는 상황에서는 일부러 붙이지 않는다.

셋째, 값의 드리프트. 누군가 --set 으로 급히 복제 수를 올려 장애를 넘겼다면 그 값은 그 리비전에만 존재한다. 다음 배포가 그것을 조용히 되돌린다. 그래서 임시로 넣은 값은 반드시 저장소의 값 파일에 반영해야 한다.

다음 실습에서 할 것

네임스페이스 helm-lab 에 릴리스 lab-app 을 설치해 리비전 1을 만들고, 복제 수를 올려 리비전 2를 만든다. 그다음 API 서버가 거부할 값을 일부러 넣어 실패 리비전 3을 만들고, 리비전 2로 롤백해 리비전 4를 얻는다. helm get values-a 와 함께 그리고 없이 각각 뽑아 비교하고, 네임스페이스에 쌓인 릴리스 시크릿을 직접 확인한 뒤 수명주기 보고서를 만든다.