Helm "another operation in progress" 에러 해결: pending 락 5분 복구법
CI 파이프라인이 빨갛게 멈췄고, 로그 맨 아래엔 이 한 줄이 떠 있습니다.
Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress재실행을 눌러도 똑같은 에러. 이 글은 "지금 배포가 막혀 있는 당신"을 위한 것입니다. 결론부터 말하면, 이건 데이터 손실 없이 거의 항상 5분 안에 풀립니다. 단, 절대 하지 말아야 할 행동이 하나 있습니다.
⚠️ 가장 먼저 알아둘 것: 급한 마음에
helm delete(=helm uninstall)를 치지 마세요. 이건 락을 푸는 명령이 아니라 릴리스와 그에 딸린 워크로드(Deployment, Service 등)를 통째로 삭제하는 명령입니다. 프로덕션에서 이걸로 락을 풀려다 서비스가 내려간 사례가 정말 많습니다.
왜 락이 걸리나: Helm 3의 release state 메커니즘
Helm 2 시절엔 Tiller가 릴리스 상태를 ConfigMap에 저장했지만, Helm 3부터는 기본적으로 Secret에 저장합니다. 이름 규칙이 정해져 있어요.
sh.helm.release.v1.<release-name>.v<revision-number>배포할 때마다 새 리비전 Secret이 하나씩 쌓이고, 각 Secret에는 상태 라벨이 붙습니다. 정상적인 흐름은 이렇습니다.
| 시점 | Secret status 라벨 |
|---|---|
| 설치/업그레이드 시작 | pending-install / pending-upgrade |
| 정상 완료 | deployed |
| 명시적 삭제 | uninstalled |
문제는 배포가 중간에 죽었을 때입니다. 타임아웃, 파드 강제종료, CI 잡 강제 중단, 동시 트리거... 어떤 이유로든 Helm 프로세스가 deployed로 마무리하지 못하면, 그 리비전 Secret은 영원히 pending-* 상태로 남습니다.
pending-install— 첫 설치가 중단됨 (이전 deployed 리비전이 없음)pending-upgrade— 업그레이드가 중단됨 (이전 deployed 리비전이 있음)pending-rollback— 롤백이 중단됨
Helm은 다음 작업을 시작하기 전에 "마지막 리비전이 pending이면 다른 작업이 진행 중인 걸로 간주"하고 막아버립니다. 그게 바로 그 한 줄짜리 에러의 정체입니다. ArgoCD나 Flux 같은 GitOps 도구도 내부적으로 Helm을 쓰기 때문에 동일하게 발생합니다.
진단: 내 릴리스가 어디에 갇혔는지 5분 안에 찾기
복구 전에 반드시 상태부터 확인합니다. 어떤 리비전이 마지막 정상(deployed)인지 알아야 안전하게 풀 수 있어요.
# 1) 리비전 이력 — STATUS 컬럼을 보세요
helm history <release> -n <ns>
# 2) 현재 릴리스 상태
helm status <release> -n <ns>
# 3) 실제 Secret을 시간순으로 확인
kubectl get secret -n <ns> -l owner=helm,name=<release> \
--sort-by=.metadata.creationTimestamphelm history 출력은 이런 식입니다.
REVISION STATUS CHART DESCRIPTION
3 deployed myapp-1.2.0 Upgrade complete
4 pending-upgrade myapp-1.3.0 Preparing upgrade여기서 핵심은 두 가지입니다.
- 마지막으로
deployed인 리비전 번호 → 위 예시에서는3. 롤백 목표가 됩니다. - pending으로 갇힌 리비전 →
4. 이게 락의 원인입니다.
kubectl get secret으로 보면 sh.helm.release.v1.myapp.v4 Secret이 status=pending-upgrade 라벨을 달고 있는 걸 확인할 수 있습니다. 이 Secret이 범인입니다.
원인별 복구 3루트 (우선순위 순서대로)
가장 안전한 순서대로 시도하세요. 위에서부터 안 되면 아래로 내려갑니다.
1순위 — 직전 deployed 리비전으로 롤백 (가장 안전)
이전에 정상 배포된 리비전이 있다면(=pending-upgrade인 경우), 롤백이 정답입니다. Helm이 pending Secret을 정리하고 상태를 깔끔하게 되돌려 줍니다.
# 위에서 찾은 '마지막 deployed' 리비전 번호 사용
helm rollback <release> 3 -n <ns>롤백이 성공하면 락이 풀리고, 다시 helm upgrade를 할 수 있습니다. 데이터 손실 없이 가장 깔끔한 방법입니다.
2순위 — pending Secret 직접 삭제 (롤백 대상이 없거나 롤백도 실패할 때)
pending-install인 경우엔 돌아갈 deployed 리비전이 아예 없어서 롤백이 불가능합니다. 또는 롤백 자체가 실패하기도 합니다. 이럴 땐 pending Secret만 콕 집어 삭제합니다.
# 라벨로 pending 상태 Secret만 삭제 (status를 정확히 지정!)
kubectl delete secret -n <ns> \
-l owner=helm,name=<release>,status=pending-upgrade
# 또는 리비전 번호로 특정 Secret만 삭제
kubectl delete secret sh.helm.release.v1.<release>.v<N> -n <ns>삭제 후 재배포하면 락이 풀린 상태에서 다시 진행됩니다.
helm upgrade --install <release> ./chart -n <ns>3순위 — 상태가 꼬였을 때 정리
여러 번 재시도하다 pending Secret이 여러 개 쌓였다면, deployed Secret은 절대 건드리지 말고 pending 라벨이 붙은 것들만 정리한 뒤 재배포합니다. 삭제 전 kubectl get secret으로 대상을 한 번 더 눈으로 확인하는 습관이 사고를 막습니다.
⚠️ 주의사항 (꼭 지키세요)
- ❌
deployed상태 Secret을 지우면 릴리스 이력이 깨집니다. 오직pending-*만 삭제하세요.- ❌
helm delete/helm uninstall은 락 해제용이 아닙니다. 워크로드까지 사라집니다.- ✅ 항상 네임스페이스(
-n)와 리비전 번호를 명시하고, 삭제 전 대상을 한 번 더 확인하세요.
타임아웃이 근본 원인일 때
실무에서 pending 락의 가장 흔한 원인은 타임아웃입니다. --wait 옵션을 주면 Helm은 파드가 Ready가 될 때까지 기다리는데, 헬스체크가 안 통과하면 결국 이렇게 끝납니다.
Error: UPGRADE FAILED: timed out waiting for the condition이때 릴리스는 pending-upgrade로 남고, 다음 배포가 막힙니다. 제 경험상 readinessProbe 설정이 빡빡하거나 이미지 풀이 느린 환경에서 자주 터지는데, 락만 풀고 끝내면 다음에 또 같은 일이 반복됩니다. 근본 처방은 배포 옵션을 바꾸는 것입니다.
helm upgrade --install <release> ./chart -n <ns> \
--atomic \ # 실패 시 자동 롤백 → pending이 남지 않음
--cleanup-on-fail \ # 실패 시 생성된 리소스 정리
--wait \
--timeout 10m # 환경에 맞게 충분히--atomic이 핵심입니다. 배포가 실패해도 자동으로 직전 상태로 롤백되기 때문에, 애초에 pending 락이 남지 않습니다. CI 파이프라인 배포 명령에 이 옵션 하나만 추가해도 이 에러를 만날 일이 크게 줄어듭니다.
결론: 재발 방지 체크리스트 + 복붙용 요약
진단부터 복구까지 한 장으로 정리합니다.
# ── 진단 ──
helm history <release> -n <ns> # deployed / pending 리비전 확인
helm status <release> -n <ns>
kubectl get secret -n <ns> -l owner=helm,name=<release> \
--sort-by=.metadata.creationTimestamp
# ── 복구 1순위: 롤백 ──
helm rollback <release> <마지막 deployed REVISION> -n <ns>
# ── 복구 2순위: pending Secret 직접 삭제 ──
kubectl delete secret -n <ns> -l owner=helm,name=<release>,status=pending-upgrade
helm upgrade --install <release> ./chart -n <ns>
# ── 재발 방지: 배포 옵션 ──
helm upgrade --install <release> ./chart -n <ns> \
--atomic --cleanup-on-fail --wait --timeout 10m재발 방지 체크리스트:
- 배포 명령에
--atomic+--cleanup-on-fail적용 -
--timeout을 환경 현실에 맞게 충분히 설정 - CI에서 동시/중복 배포 트리거 방지 (GitHub Actions
concurrency, GitLabresource_group) - 배포 잡 타임아웃을 Helm
--timeout보다 길게 (잡이 먼저 죽으면 pending이 남음)
자주 묻는 질문 (FAQ)
Q. pending Secret을 지우면 운영 중인 파드도 같이 사라지나요?
A. 아닙니다. sh.helm.release.v1.* Secret은 릴리스의 **메타데이터(상태/매니페스트 이력)**만 담고 있습니다. 실제 워크로드(Deployment, Pod 등)는 별개의 리소스라서, pending Secret 하나를 지워도 실행 중인 파드에는 영향이 없습니다. 단 deployed Secret은 절대 지우지 마세요.
Q. ArgoCD로 배포하는데도 같은 에러가 납니다. 왜죠?
A. ArgoCD와 Flux도 내부적으로 Helm 템플릿/릴리스 메커니즘을 사용하기 때문에 동일한 pending 락이 발생할 수 있습니다. 진단과 복구 방법은 같습니다. kubectl로 pending Secret을 정리한 뒤 Sync를 다시 트리거하면 됩니다.
Q. helm rollback도 "another operation in progress"로 실패해요.
A. 마지막 리비전이 pending-install이라 돌아갈 deployed 리비전이 없거나, 상태가 꼬인 경우입니다. 이럴 땐 2순위 방법대로 kubectl delete secret으로 pending Secret만 삭제한 뒤 helm upgrade --install로 재배포하세요.
이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.
댓글
불러오는 중...