← Все статьи

Helm пишет «another operation is in progress», а ничего не запущено

Отменённая CI-джоба оставила два Helm-релиза в pending-upgrade и заблокировала все деплои. Как найти lock, безопасно его снять и проверить весь namespace разом.

Однажды утром в Gambchamp деплой-джобы двух бэкенд-сервисов покраснели одновременно. Обе упали с одной и той же строкой:

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

При этом никто ничего не деплоил. Ни один пайплайн не шёл, ни у кого не было открытого терминала к этому namespace. А Helm настаивал, что какая-то операция идёт.

Первая гипотеза и почему она не подтвердилась

Когда два сервиса падают вместе, обычно подозреваешь общую зависимость: реестр образов, API кластера, раннер. Их мы и проверили первыми. API отвечал, образы тянулись, другие релизы в других namespace деплоились нормально. Сбой касался только этих двух релизов, и общее у них было одно: их деплоит одна и та же группа пайплайнов в один и тот же namespace.

Что Helm на самом деле помнит

Helm хранит состояние каждой ревизии релиза как Secret в namespace релиза. Статус лежит в лейбле: deployed, superseded, failed — или pending-install, pending-upgrade, pending-rollback. Ревизия в pending-* — это и есть lock Helm. Пока она существует, любой новый helm upgrade для этого релиза отказывается стартовать.

helm history показал ровно это: последняя ревизия обоих релизов была в pending-upgrade, и обе создались в одну и ту же минуту.

Таймстемп всё объяснил. Предыдущий деплой отменили (или он упёрся в таймаут) посреди helm upgrade --atomic. --atomic обещает автоматический откат при ошибке, но только если процесс Helm доживёт до этого отката. Убейте джобу на полпути — и отката не будет. Lock остаётся, и каждый следующий деплой в него упирается.

Решение

Lock снимается откатом на последнюю ревизию, которая действительно прошла успешно:

helm history <release> -n <ns>          # найти последнюю ревизию "deployed"
helm rollback <release> <rev> -n <ns>   # откат на неё снимает pending-lock

После отката повтор CI-джобы прошёл штатно. Раз два релиза замёрзли в одну минуту, чинить их по одному и пропустить третий мы не хотели. Один запрос показывает все зависшие релизы в namespace:

kubectl -n <ns> get secret -l owner=helm -o json \
  | jq -r '.items[] | select(.metadata.labels.status | test("pending"))
    | "\(.metadata.labels.name) rev=\(.metadata.labels.version) status=\(.metadata.labels.status)"'

Выводы

  • another operation is in progress почти всегда означает ревизию в pending-*. Начинайте с helm history, а не с сети.
  • --atomic — не гарантия. Он откатывает, только если Helm доработал до конца; отменённая джоба оставляет lock.
  • Несколько релизов, зависших с одинаковым таймстемпом, — это один инцидент: оборванный пакетный деплой или умерший раннер. Проверяйте весь namespace, а не чините релизы по одному.
  • Откатывайтесь на последнюю deployed-ревизию, а не удаляйте Secret’ы релиза руками: это обратимо и сохраняет историю Helm целостной.