LabHub
배우기 러닝패스 코스

Helm Deployment and Rollback Scenarios

What --atomic and --wait Actually Do

LabHub 에서 이어서 보기

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

한 줄 요약

--wait 은 "다 뜰 때까지 기다린다", --atomic 은 "다 못 뜨면 되돌린다" 이다. 이 둘을 안 쓰면 실패한 배포가 성공으로 보고된다.

Concept map: 실패한 배포가 성공으로 보고된다. · 바로 성공을 반환한다. · --atomic 은 --wait 을 포함한다 · 가장 느린 파드의 기동 시간 + 여유

왜 이게 필요했나

helm upgrade 는 기본적으로 매니페스트를 API 서버에 보내고 바로 성공을 반환한다. 파드가 실제로 뜨는지는 보지 않는다. 이미지 태그를 잘못 적어 ImagePullBackOff 가 나도 helm 은 STATUS: deployed 를 출력한다. CI 로그는 초록색이고, 사용자만 장애를 겪는다.

--wait 을 붙이면 helm 이 Deployment·StatefulSet·DaemonSet 의 준비 상태를 폴링한다. --timeout(기본 5분) 안에 준비되지 않으면 실패로 처리한다. 이제 CI 가 빨간불이 된다.

그런데 실패한 채로 두면 문제가 남는다. 새 리비전은 이미 만들어졌고 리소스는 반쯤 바뀐 상태다. --atomic 은 여기서 자동으로 helm rollback 을 걸어 이전 상태로 되돌린다. --atomic--wait 을 포함한다 — 기다리지 않으면 실패를 알 수 없으니 당연하다.

어떻게 동작하나

helm upgrade demo ./chart \
  --atomic \
  --timeout 5m \
  --history-max 10

이 한 줄이 배포 스크립트의 기본형이어야 한다. 그리고 timeout 값은 가장 느린 파드의 기동 시간 + 여유로 잡는다. 너무 짧으면 멀쩡한 배포가 롤백되고, 너무 길면 장애를 늦게 안다.

흔한 착각

--atomic 이 있으면 안전하다는 착각. atomic 은 쿠버네티스 리소스만 되돌린다. 훅으로 돌린 마이그레이션 Job 이 DB 를 이미 바꿨다면 그건 그대로 남는다. 그래서 스키마 변경은 앞뒤 버전이 모두 견디는 형태로 나눠서 배포한다(확장 → 배포 → 정리).

timeout 을 늘리면 해결된다는 착각. ImagePullBackOff 는 기다려도 낫지 않는다. 30분 timeout 은 장애를 30분 늦게 알려 줄 뿐이다.

릴리스가 pending 에 갇히면

배포가 중간에 죽으면 릴리스가 pending-upgradepending-install 로 남습니다. 이 상태에서는 다음 배포가 이렇게 거절됩니다.

Error: another operation (install/upgrade/rollback) is in progress

Helm 3 은 릴리스 상태를 네임스페이스의 Secret 에 저장하고, 잠금이 따로 없어 "진행 중" 표시가 그대로 남는 것입니다. 프로세스는 이미 죽었는데 표시만 남았습니다.

푸는 순서는 이렇습니다.

helm history demo                    # 1) 마지막 리비전의 상태를 본다
helm rollback demo <직전 성공 리비전>  # 2) 대개 이걸로 풀린다

# 롤백도 거절되면 마지막 수단 — 갇힌 리비전의 Secret 을 지운다
kubectl -n <ns> get secret -l owner=helm,name=demo
kubectl -n <ns> delete secret sh.helm.release.v1.demo.v<갇힌 번호>

마지막 방법은 그 리비전의 기록을 지우는 것 이라 되돌릴 수 없습니다. 지우기 전에 helm get manifest demo --revision <n> 으로 내용을 남겨 둡니다.

롤백이 되돌리지 못하는 것들

helm rollback 은 릴리스 매니페스트를 되돌립니다. 그 밖의 것은 그대로입니다.

되돌아온다 되돌아오지 않는다
Deployment·Service·ConfigMap 의 spec 훅이 실행한 DB 마이그레이션
이미지 태그, 환경변수, replicas PVC 안의 데이터
리소스 요청·한도 다른 시스템에 보낸 이벤트·알림
삭제된 리소스가 갖고 있던 상태

특히 마지막 줄을 조심합니다. 차트에서 리소스를 하나 빼고 배포하면 Helm 이 그것을 지웁니다. 롤백하면 다시 만들어지지만 안에 있던 것은 새 것 입니다. StatefulSet 을 잠시 뺐다가 되돌리는 일이 데이터 유실로 이어지는 경로입니다.

배포 파이프라인의 기본형

helm upgrade --install demo ./chart   -f values/prod.yaml   --set image.tag="$GIT_SHA"   --atomic --timeout 5m --history-max 10   --wait-for-jobs

# helm 이 초록불을 준 뒤에 바깥에서 확인한다
curl -fsS --retry 5 --retry-delay 3 https://demo.example.com/healthz

--wait-for-jobs 를 빠뜨리는 일이 흔합니다. --wait 은 Deployment·StatefulSet 은 기다리지만 Job 은 기다리지 않습니다. 마이그레이션 Job 이 끝나기 전에 새 파드가 트래픽을 받는 사고가 여기서 납니다.

실무에서 진짜 중요한 것

--wait 이 보는 것은 워크로드의 준비 상태지 "서비스가 정상"이 아니다. 파드가 Ready 여도 응답이 500 일 수 있다. 그래서 배포 파이프라인의 마지막에는 항상 바깥에서 때려 보는 스모크 테스트가 있어야 한다. helm 이 초록불을 줬다는 것과 사용자가 쓸 수 있다는 것은 다른 명제다.