Vault Secrets Operator замолчал после seal — и рестарт его не разбудил
38 из 43 VaultStaticSecret два дня висели с замёрзшей ошибкой. Unseal Vault и рестарт оператора ничего не дали; помогло изменение одного поля в spec.
В Optimacros bare-metal кластер Kubernetes получает секреты приложений из Vault через Vault Secrets Operator (VSO). Однажды я заметил, что 38 из 43 объектов VaultStaticSecret примерно двое суток показывают SecretSynced=False.
Замёрзшая ошибка — это не повторяющаяся ошибка
В условии стояло 503 Vault is sealed и back-off horizon 4,939 секунды. Я опросил его несколько раз. Horizon каждый раз был одинаковым до наносекунды. Контроллер, который действительно повторяет попытки, пересчитывает это значение при каждой. Этот не повторял вообще.
Логи оператора это подтверждали: с момента seal — ни строчки. Под был жив, продлевал leader lease и потреблял несколько милликор CPU, но ничего не реконсилил.
Слой первый: один запечатанный узел за Service
У самой 503 причина была простая. Vault работает как Raft-кластер из трёх узлов, и один узел был запечатан. Service vault балансирует на все поды, так что примерно треть чтений VSO попадала на запечатанный узел. Это объясняло и странную смесь: одни секреты синкались, другие нет, чисто по везению round-robin.
Я распечатал узел, все три пода Vault стали ready. Объекты VaultStaticSecret остались False.
Слой второй: умер цикл реконсиляции
Дальше я попробовал два официальных средства: rollout restart оператора и аннотацию force-sync на застрявших объектах. Ни то, ни другое ничего не изменило.
Оказалось, это известный баг VSO, hashicorp/vault-secrets-operator#840. После seal и unseal умирают lifetime watcher’ы отдельных секретов, и ни периодический таймер refreshAfter, ни force-sync не возвращают объекты в очередь. Informer жив, но ничто ничего не ставит в очередь заново.
Будильник: изменить spec
Informer по-прежнему реагирует на изменения spec. Поэтому я поменял spec.refreshAfter у каждого застрявшего объекта. Это порождает watch-событие, запускается реконсиляция, и объект уходит в True. Успешные синки VSO на уровне info не логирует, так что логи молчали и тогда, когда всё сработало; единственным сигналом были условия. Когда всё засинкалось, я вернул исходный refreshAfter вторым патчем.
Это было безопасно, потому что у секретов стоял overwrite: false: будильник починил статус и не переписал существующие данные.
Настоящее исправление в другом месте
Изменение spec — это обходной путь. В этом кластере Vault распечатывался по Shamir без auto-unseal, поэтому каждый рестарт пода Vault запечатывал узел, и каждый seal снова останавливал бы VSO. Настоящие лекарства — обновить VSO до версии с исправлением бага и перевести Vault на auto-unseal, чтобы seal вообще перестал случаться.
Что вынести
- Сообщение условия, которое не меняется между опросами вплоть до таймингов back-off, — отпечаток мёртвой очереди, а не медленного повтора.
- Service перед Raft-кластером шлёт трафик и на запечатанные узлы. Смешанный успех на одинаковых объектах часто значит, что часть бэкендов плохая.
- Если рестарты и аннотации force-sync не помогают, безобидное изменение spec проходит через informer и возвращает объект в очередь.
- Чини источник: auto-unseal убирает seal, обновление убирает зависание.