LabHub
배우기 러닝패스 코스

Helmのデプロイとロールバック

フックはリリースの外に住んでいる

LabHub 에서 이어서 보기

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

한 줄 요약

훅 리소스는 릴리스가 관리하지 않는다. 그래서 롤백해도 사라지지 않고, 삭제 정책을 안 걸면 클러스터에 쌓인다.

概念マップ: 릴리스가 관리하지 않는다.・롤백해도 훅이 한 일은 남는다.・Job 오브젝트가 계속 쌓인다.・로그가 사라진다 — 대개 나쁜 선택

왜 이게 필요했나

DB 마이그레이션을 배포에 넣는 가장 흔한 방법이 pre-upgrade 훅 Job 이다. 그런데 이 Job 은 릴리스의 일부가 아니다. Helm 은 훅을 적용하고, 완료를 기다리고, 그다음 본 매니페스트를 적용한다. 훅으로 만든 Job 오브젝트는 릴리스 시크릿에 들어가지 않는다.

결과는 둘이다.

어떻게 동작하나

metadata:
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "-5"          # 작을수록 먼저
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded

hook-delete-policy 값 세 가지의 뜻이 다르다.

언제 지우나
before-hook-creation 다음 배포에서 같은 훅을 만들기 직전 (실패한 Job 을 남겨 조사 가능)
hook-succeeded 성공하면 즉시
hook-failed 실패하면 즉시 (로그가 사라진다 — 대개 나쁜 선택)

실무 기본형은 before-hook-creation,hook-succeeded 다. 성공한 건 치우고, 실패한 건 다음 배포까지 남겨 로그를 볼 수 있게 한다.

흔한 착각

훅이 실패하면 롤백된다는 착각. pre-upgrade 훅이 실패하면 업그레이드가 중단되고 릴리스는 failed 로 남는다. --atomic 이 있으면 롤백이 걸리지만, 이미 실행된 마이그레이션은 되돌아오지 않는다.

훅으로 하지 말아야 할 것

훅은 편리해서 온갖 것을 넣게 됩니다. 넣지 말아야 할 것이 셋 있습니다.

오래 걸리는 데이터 이관. 수백만 행을 옮기는 작업은 배포를 몇십 분 붙잡습니다. 그동안 릴리스는 pending-upgrade 로 잠겨 다른 배포가 막힙니다. 이런 일은 배포와 분리해 별도 Job 으로 돌리고, 애플리케이션이 두 스키마를 모두 읽을 수 있게 만듭니다.

외부 시스템에 알리는 일. post-install 훅으로 슬랙에 알리는 것은 흔한데, 훅이 실패하면 배포 전체가 실패로 표시됩니다. 알림이 안 갔다고 배포를 실패로 볼 이유는 없습니다. 이런 것은 CI 쪽에 둡니다.

테스트. helm test 는 별도 명령이고 helm.sh/hook: test 를 씁니다. 배포 과정에 섞어 넣으면 테스트가 흔들릴 때마다 배포가 막힙니다.

훅이 걸리면 배포가 멈춰 선다

훅 Job 이 끝나지 않으면 helm upgrade 는 계속 기다립니다. --timeout 기본값은 5분이고, 그 뒤에는 실패로 처리합니다. 그런데 타임아웃이 나도 Job 은 클러스터에서 계속 돕니다. Helm 은 기다리기를 그만둘 뿐 Job 을 죽이지 않습니다.

여기서 위험한 상황이 생깁니다. 실패로 판단하고 다시 배포하면, 앞의 마이그레이션이 아직 돌고 있는데 두 번째가 시작됩니다. 같은 테이블에 ALTER 를 두 개가 동시에 걸면 잠금 대기로 서비스 전체가 멈출 수 있습니다.

세 가지로 막습니다.

spec:
  activeDeadlineSeconds: 240      # helm --timeout 5m 보다 짧게
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never

훅과 일반 매니페스트의 순서

한 차트 안에 훅과 일반 리소스가 섞여 있으면 순서가 헷갈립니다. 실제 순서는 이렇습니다.

pre-install 훅  →  일반 매니페스트 적용  →  post-install 훅
   (weight 순)        (Helm 의 종류별 순서)      (weight 순)

여기서 자주 밟는 함정. pre-install 훅은 Secret·ConfigMap 이 아직 없을 때 돕니다. 훅 Job 이 릴리스의 Secret 을 참조하면 "그런 secret 이 없다" 로 실패합니다. 훅이 쓸 값은 훅 자신이 만들거나(같은 훅 그룹에 weight 를 낮게 준 Secret), 릴리스 밖에서 미리 만들어 두어야 합니다.

hook-weight문자열이지만 숫자로 정렬 됩니다. "10""9" 를 주면 9 가 먼저입니다. 음수를 쓰는 관례가 여기서 나왔습니다 — -5 를 기본으로 두고 더 먼저 돌아야 하는 것에 -10 을 줍니다.

실무에서 진짜 중요한 것

되돌릴 수 없는 마이그레이션은 배포와 분리한다. 컬럼을 지우는 변경은 세 번에 나눠 배포한다 — ① 새 컬럼 추가(옛 코드도 동작) ② 새 코드 배포 ③ 옛 컬럼 삭제. 이렇게 하면 어느 단계에서 롤백해도 앞뒤 버전이 모두 견딘다. 이걸 확장-수축(expand-contract) 패턴이라 부른다.