LabHub
배우기 러닝패스 코스

Helm Deployment and Rollback Scenarios

Confirm That Hooks Live Outside the Release

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

훅 리소스가 릴리스 바깥에 산다는 사실을 손으로 확인합니다. 애너테이션 세 개를 붙이고, 삭제 정책 둘을 나란히 놓고, 실행 순서를 계산하고, 롤백해도 훅이 남긴 것이 그대로인 것까지 봅니다.

왜 중요한가

DB 마이그레이션을 배포에 넣는 가장 흔한 방법이 pre-upgrade 훅입니다. 그런데 훅으로 만든 오브젝트는 릴리스 시크릿에 들어가지 않습니다. 결과가 둘입니다. 롤백해도 훅이 한 일은 남고, 삭제 정책을 안 걸면 오브젝트가 계속 쌓입니다.

여기서 실무 규칙이 따라 나옵니다. 성공한 훅은 치우고 실패한 훅은 다음 배포까지 남겨 로그를 볼 수 있게 한다는 것, 되돌릴 수 없는 스키마 변경은 배포와 분리해 여러 번에 나눈다는 것, 그리고 Job 훅에는 helm 의 타임아웃보다 짧은 자기 상한을 걸어 둔다는 것입니다. 마지막 것은 helm 이 기다리기를 그만두어도 Job 은 계속 돌기 때문입니다.

환경

이 파드는 kwok 으로 진짜 kube-apiserver 를 띄우지만 컨테이너는 실제로 실행되지 않습니다. 그래서 Job 훅은 끝나지 않고 릴리스를 갇히게 만듭니다. 앞의 여섯 단계는 즉시 준비 완료로 판정되는 ConfigMap 으로 훅을 다루고, Job 은 7단계에서 값 하나로 꺼 둔 채 렌더 결과만 봅니다. 작업 디렉터리는 /root/hs-hook 이고 산출물은 /root/hs-hook/out 아래에 둡니다.

단계

  1. 차트를 만들고 hook-migrate.yaml 에 훅 애너테이션 세 개를 붙입니다.
  2. hook-labpay 로 설치하고 클러스터와 매니페스트 양쪽을 봅니다.
  3. hook-scratch.yaml 을 더해 삭제 정책 두 가지를 비교합니다.
  4. hook-early.yaml 을 더하고 실행 순서를 /root/hs-hook/out/order.txt 에 적습니다.
  5. tests/smoke.yamltest 훅을 만들고 배포 때 돌지 않는 것을 확인합니다.
  6. --no-hooks 렌더를 /root/hs-hook/out/nohooks.yaml 에 저장합니다.
  7. hook-migrate-job.yaml 에 안전장치를 갖춘 Job 훅을 만들되 기본값은 꺼 둡니다.
  8. 업그레이드하고 롤백한 뒤 /root/hs-hook/out/residue.txt 에 네 줄로 정리합니다.

참고

훅 애너테이션 세 개를 붙인다

/root/hs-hook 에서 helm create svc 로 차트를 만들고 svc/templates/tests 디렉터리는 지우세요. 그다음 svc/templates/hook-migrate.yaml{{ .Release.Name }}-migrate ConfigMap 을 만들고 helm.sh/hookpre-install,pre-upgrade, helm.sh/hook-weight-5, helm.sh/hook-delete-policybefore-hook-creation 으로 적으세요.

훅은 별도의 리소스 종류가 아니라 애너테이션이 붙은 평범한 리소스입니다. 실무에서는 Job 을 쓰지만, 이 클러스터는 컨테이너를 실제로 실행하지 않아 Job 훅이 끝나지 않습니다. 그래서 앞의 여섯 단계는 즉시 준비 완료로 판정되는 ConfigMap 으로 훅을 다룹니다. 애너테이션 값은 반드시 문자열이어야 하므로 weight 는 따옴표로 감싸세요.

훅은 클러스터에 있는데 매니페스트에는 없다

차트를 hook-lab 네임스페이스에 pay 라는 이름으로 설치하고, kubectlhelm get manifest 두 곳에서 훅 ConfigMap 을 찾아보세요.

helm install pay ./svc -n hook-lab --create-namespace 입니다. 설치가 끝나면 kubectl -n hook-lab get cm 에는 훅 ConfigMap 이 보이는데 helm get manifest pay -n hook-lab 에는 없습니다. 훅 리소스는 릴리스가 관리하지 않기 때문입니다. 이 한 가지가 롤백이 훅을 되돌리지 못하는 이유의 전부입니다.

삭제 정책 둘을 나란히 놓고 차이를 본다

svc/templates/hook-scratch.yaml{{ .Release.Name }}-scratch ConfigMap 을 만드세요. 훅 시점은 앞과 같고 weight 는 0, 삭제 정책은 hook-succeeded 입니다. 그다음 업그레이드를 한 번 하세요.

hook-succeeded 는 성공하는 즉시 오브젝트를 지우고, before-hook-creation 은 다음 배포에서 같은 훅을 만들기 직전까지 남겨 둡니다. 업그레이드가 끝난 뒤 kubectl -n hook-lab get cm 을 보면 둘 중 하나만 남아 있습니다. 실패한 훅의 로그를 볼 수 있느냐가 여기서 갈립니다.

weight 로 실행 순서를 정한다

svc/templates/hook-early.yaml{{ .Release.Name }}-early ConfigMap 훅을 weight -10 으로 더하세요. 그다음 pre-upgrade 단계에서 도는 훅들의 실행 순서를 계산해 /root/hs-hook/out/order.txt 에 이름만 한 줄씩 적으세요.

hook-weight 는 문자열이지만 숫자로 정렬됩니다. 작을수록 먼저 돌고, 값이 같으면 리소스 종류와 이름 순서로 갈립니다. 그래서 실무에서는 기본을 -5 로 두고 더 먼저 돌아야 하는 것에 -10 을 줍니다. 순서는 짐작하지 말고 helm template 결과에서 애너테이션을 뽑아 정렬해 확인하세요.

test 훅은 배포 때 돌지 않는다

svc/templates/tests/smoke.yaml{{ .Release.Name }}-smoke 파드를 만들고 helm.sh/hooktest 로, 삭제 정책을 hook-succeeded 로 두세요. 그다음 업그레이드를 한 번 더 하세요.

test 훅은 배포 과정에 끼어들지 않고 helm test 를 부를 때만 돕니다. 그래서 업그레이드가 끝난 뒤에도 그 파드는 클러스터에 없고 helm get manifest 에도 없습니다. 렌더 결과에는 나옵니다. 이 셋의 차이를 직접 확인하는 것이 이 단계입니다. 배포 과정에 테스트를 섞어 넣으면 테스트가 흔들릴 때마다 배포가 막히므로, 자리를 나눠 둔 설계입니다.

--no-hooks 가 무엇을 빼는지 본다

helm template--no-hooks 를 붙여 렌더한 결과를 /root/hs-hook/out/nohooks.yaml 에 저장하세요. 훅만 빠지고 본 매니페스트는 그대로여야 합니다.

--no-hookshelm install·upgrade·template 모두에 붙일 수 있습니다. 사고 대응 중 훅을 건너뛰고 리소스만 밀어 넣어야 할 때 쓰지만, 마이그레이션을 건너뛰는 셈이므로 결과를 알고 써야 합니다. 저장한 뒤 훅이 붙은 리소스가 하나도 없고 나머지 개수는 그대로인지 확인하세요.

마이그레이션 Job 에 안전장치를 건다

svc/templates/hook-migrate-job.yamlpre-upgrade Job 훅을 만드세요. values.yamlmigrationJob.enabled 로 켜고 끄되 기본값은 false 여야 합니다. Job 에는 activeDeadlineSeconds(300 미만), backoffLimit: 0, restartPolicy: Never 를 두고 삭제 정책은 before-hook-creation,hook-succeeded 로 하세요.

helm 의 --timeout 기본값은 5분인데, 타임아웃이 나도 Job 은 클러스터에서 계속 돕니다. helm 은 기다리기를 그만둘 뿐입니다. 그래서 Job 이 스스로 먼저 끝나도록 activeDeadlineSeconds 를 그보다 짧게 겁니다. 삭제 정책에 hook-failed 를 넣으면 실패한 순간 로그가 사라지니 넣지 마세요. 이 클러스터에서는 Job 훅이 끝나지 않으므로 기본값을 꺼 두어야 합니다. 켠 상태로 업그레이드하면 릴리스가 pending 에 갇힙니다.

롤백해도 훅이 한 일은 남는다

업그레이드를 한 번 더 한 뒤 helm rollback 으로 되돌리고, 훅 ConfigMap 들이 그대로 남아 있는지 확인하세요. 확인 결과를 /root/hs-hook/out/residue.txt 에 네 줄로 적습니다. HOOK_ROLLED_BACK, HOOK_IN_MANIFEST, MIGRATION_UNDONE, SAFE_PATTERN 입니다.

롤백은 릴리스가 관리하는 오브젝트를 예전 매니페스트로 다시 적용하는 일입니다. 훅이 만든 것은 그 매니페스트에 없으니 손대지 않습니다. 그래서 마이그레이션이 바꾼 스키마도 그대로 남습니다. 앞의 세 줄은 예/아니오를 yes 또는 no 로 적고, 마지막 줄에는 되돌릴 수 없는 스키마 변경을 안전하게 내보내는 패턴 이름을 적으세요. 이론에서 확장과 수축이라고 부른 그것입니다.