--atomicと--waitが実際にやっていること
한국어 원문으로 표시합니다.
한 줄 요약
--wait 은 "다 뜰 때까지 기다린다", --atomic 은 "다 못 뜨면 되돌린다" 이다. 이 둘을 안 쓰면 실패한 배포가 성공으로 보고된다.
왜 이게 필요했나
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-upgrade 나 pending-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 이 초록불을 줬다는 것과 사용자가 쓸 수 있다는 것은 다른 명제다.