Гид по технологиям

Finalizers в Kubernetes: как работают, почему блокируют удаление и что с этим делать

6 min read Kubernetes Обновлено 04 Dec 2025
Finalizers в Kubernetes: решение проблем удаления
Finalizers в Kubernetes: решение проблем удаления

Графика с логотипом Kubernetes

Быстрые ссылки

  • Что такое Finalizers?

  • Проблемы с Finalizers

  • Владельцы (Owners) и политики распространения удаления

  • Реализация Finalizers в контроллере

  • Заключение

Что такое Finalizers?

Finalizer — это запись в поле объекта Kubernetes metadata.finalizers, которая даёт внешнему контроллеру или встроенному механизму шанс выполнить работу перед окончательным удалением ресурса. Проще: Finalizer говорит «не удалять объект, пока я не закончу свою работу».

Краткое определение: Finalizer — маркер в объекте, который откладывает окончательное удаление до завершения связанных действий.

Типичная последовательность удаления:

  1. Вы вызываете команду удаления, например:
kubectl delete namespace/example
  1. Kubernetes выставляет объект в состояние «Terminating» и оставляет его доступным для чтения, пока metadata.finalizers не станет пуст.
  2. Каждый прикреплённый Finalizer получает шанс выполнить свои действия (освобождение ресурсов, уведомления, удаление зависимостей).
  3. Когда контроллер завершил работу, он удаляет со списка свой finalizer. Как только список пуст — объект окончательно удаляется.

Finalizers часто применяются для:

  • Корректной очистки внешних ресурсов (объекты облака, хранилища, DNS).
  • Предотвращения удаления ресурсов в активном использовании (напр., PersistentVolume с kubernetes.io/pv-protection).
  • Уведомления других контроллеров о готовящемся удалении.

Пример: PersistentVolume имеет finalizer kubernetes.io/pv-protection, который не даёт удалять том, пока на нём смонтированы Pod’ы. Если удалить PV при активном Pod, ресурс попадёт в состояние Terminating и будет ждать освобождения тома.

Почему Finalizers могут вызывать проблемы

Длительные Finalizers, зависящие от других ресурсов (например, от удаления внешних объектов или ожидания статуса), приводят к тому, что объект «застревает» в Terminating. Типичные причины:

  • Контроллер, который должен убрать finalizer, не запущен или падает.
  • Контроллер не может завершить требуемые операции (сеть, доступ к API провайдера, права).
  • Циклы зависимостей: объект A ждёт удаления B, а B ждёт удаления A.
  • OwnerReferences и политика распространения удаления заставляют ждать множество дочерних finalizer’ов.

Важно: принудительное удаление finalizer’а может оставить «сиротские» внешние ресурсы или нарушить согласованность.

Как посмотреть finalizers и связанные события

  1. Проверить YAML и поле metadata.finalizers:
kubectl get pod example-pod --namespace example -o yaml

Или для удобства с jq:

kubectl get pod example-pod --namespace example -o json | jq .metadata.finalizers
  1. Посмотреть события и статус условий:
kubectl describe pod example-pod --namespace example

В YAML условия находятся в status.conditions (или status у некоторых CRD), а события видны в выводе kubectl describe.

Скриншот поля finalizers в определении объекта Kubernetes

Важно: внимательно читайте логи контроллеров, управляющих ресурсом. Они часто содержат причину, по которой finalizer не удаляется.

Как аккуратно убрать Finalizer (инструменты и команды)

Если вы уверены, что удаление безопасно, есть несколько методов:

  • Обычный путь — дождаться, пока контроллер выполнит очистку и сам удалит finalizer.
  • Если контроллер недоступен, можно вручную удалить finalizer, но только после проверки последствий.

Примеры команд (корректные и безопасные варианты):

  1. Установить finalizers пустым массивом (merge patch):
kubectl patch pod example-pod -n example -p '{"metadata":{"finalizers":[]}}' --type=merge
  1. JSON Patch вариант (удаление всей секции finalizers):
kubectl patch pod example-pod -n example --type=json -p '[{"op":"remove","path":"/metadata/finalizers"}]'
  1. Редактирование через kubectl edit (ручное и интерактивное):
kubectl edit pod example-pod -n example

и удалить секцию metadata.finalizers вручную.

ПРИМЕЧАНИЕ: некоторые API-серверы/версии не разрешают присваивать null; рекомендуется использовать пустой массив или JSON Patch.

Владельцы (OwnerReferences) и политики распространения удаления

OwnerReferences связывают объекты в дерево владения. Если вы удаляете родителя, Kubernetes по умолчанию проводит каскадное удаление дочерних объектов (cascading delete). Политики распространения определяют порядок удаления:

  • Foreground (по умолчанию для многих операций): Kubernetes удалит детей до родителя. Родитель остаётся в состоянии удаления, пока у детей не исчезнут finalizers.
  • Background: родитель удаляется сразу, дети удаляются асинхронно после.
  • Orphan: дети не удаляются (останутся в кластере), ownerReferences игнорируются.

kubectl delete напрямую не даёт задать политику; для точного управления используйте прямой API-запрос. Пример curl (пример доступа к API-серверу локально):

curl -k -X DELETE "https://localhost/apis/apps/v1/namespaces/default/deployments/example" -H "Content-Type: application/json" -d '{"apiVersion":"v1","kind":"DeleteOptions","propagationPolicy":"Background"}'

(Обратите внимание: в боевом окружении нужно корректно настраивать аутентификацию и адрес API-сервера.)

Finalizers у дочерних объектов остаются действующими при каскадном удалении. При Foreground политике все finalizers детей должны завершиться до удаления родителя.

Реализация Finalizers в контроллере (шаблон на Go)

Finalizers обычно реализуют в логике контроллера (Reconcile). Общая методика:

  1. Проверить поле metadata.deletionTimestamp — если не пустое, объект помечен на удаление.
  2. Если finalizer присутствует и нужно выполнить работу — выполнить очистку.
  3. По окончании — удалить имя finalizer из metadata.finalizers и обновить объект.

Пример упрощённого кода на Go (kubebuilder-style):

// Пример псевдокода внутри Reconcile
obj := &YourCRD{}
if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
    return ctrl.Result{}, client.IgnoreNotFound(err)
}

finalizerName := "example.com/my-finalizer"

// Если DeletionTimestamp не установлен — обычный путь
if obj.ObjectMeta.DeletionTimestamp.IsZero() {
    if !containsString(obj.ObjectMeta.Finalizers, finalizerName) {
        obj.ObjectMeta.Finalizers = append(obj.ObjectMeta.Finalizers, finalizerName)
        if err := r.Update(ctx, obj); err != nil {
            return ctrl.Result{}, err
        }
    }
    // обычная логика reconcile
} else {
    // объект пометили на удаление — выполнить очистку
    if containsString(obj.ObjectMeta.Finalizers, finalizerName) {
        // выполнить необходимые операции очистки (освобождение внешних ресурсов и т.д.)

        // по завершении удалить финализатор
        obj.ObjectMeta.Finalizers = removeString(obj.ObjectMeta.Finalizers, finalizerName)
        if err := r.Update(ctx, obj); err != nil {
            return ctrl.Result{}, err
        }
    }
}

Однострочные вспомогательные функции containsString и removeString — стандартная утилита при работе с метаданными.

Пошаговая методика безопасного разблокирования Terminating объекта

Mini-methodology (шаги):

  1. Соберите контекст: kubectl get -o yaml, kubectl describe, логи соответствующих контроллеров.
  2. Определите finalizer’ы в metadata.finalizers и владельцев в metadata.ownerReferences.
  3. Проверьте, запущены ли контроллеры, отвечающие за очистку. Посмотрите их логи.
  4. Убедитесь, что внешние зависимости (облачные API, сети, IAM) доступны.
  5. Если контроллер восстановим — запустите/перезапустите его и дождитесь, пока он сам завершит работу.
  6. Если контроллер недоступен и вы уверены в безопасности операции — примените безопасный патч (finalizers: [] или JSON Patch).
  7. После принудительного удаления проверьте, не остались ли внешние ресурсы-«сироты».

Плейбук для инцидента: объект stuck в Terminating

SOP: Быстрая проверка и устранение

  1. Идентификация
  • kubectl get -o yaml
  • kubectl describe
  1. Контекст
  • Какие finalizers перечислены?
  • Какие ownerReferences есть у объекта?
  • Какие внешние ресурсы задействованы?
  1. Диагностика контроллеров
  • kubectl get pods -n
  • kubectl logs
  1. Корректное действие
  • Перезапустить контроллер, дождаться удаления finalizer.
  1. Крайняя мера
  • Применить патч для удаления finalizer и задокументировать причину.
  1. Постфактум
  • Проверить, не остались внешние ресурсы; уведомить владельцев.

Чек-листы по ролям

Developer:

  • Понимает назначение finalizer в своём CRD.
  • Реализует безопасное удаление во Reconcile.
  • Логирует шаги при выполнении finalizer’а.

Operator/SRE:

  • Мониторит контроллеры и их рестарт-процессы.
  • Проверяет события и логи при «залипаниях» объектов.
  • Выполняет SOP и документирует ручные исправления.

Security/Cloud Admin:

  • Проверяет права доступа контроллеров к внешним API.
  • Убеждается, что удаление ресурса не оставит доступных секретов или внешних точек.

Когда Finalizers не работают как ожидается (контрпримеры)

  • Контроллер завершает очистку, но не может обновить объект (недостаточно прав) — finalizer остаётся.
  • Внешний API возвращает латентную ошибку; контроллер ретраит операцию бесконечно.
  • OwnerReferences настроены циклично: A ownerOf B и B ownerOf A — ни одна сторона не завершит удаление.

Быстрый чек-лист перед принудительным удалением finalizer

  1. Проверить, какие внешние ресурсы освободит finalizer.
  2. Наличие бэкапа/снапшота, если это важно (volume, DB).
  3. Наличие ответственного лица/команды.
  4. Документировать команду и причину вмешательства.

Decision flowchart (Mermaid)

flowchart TD
  A[Объект помечен как Terminating] --> B{Есть finalizers?}
  B -- Нет --> C[Ожидаем удаление]
  B -- Да --> D{Какие finalizers?}
  D --> E[Встроенные 'kubernetes.io/...']
  D --> F[Пользовательские 'example.com/...']
  E --> G{Работает контроллер?}
  F --> G
  G -- Да --> H[Мониторим логи и ждём завершения]
  G -- Нет --> I[Проверяем права и доступы контроллера]
  I --> J{Можно восстановить контроллер?}
  J -- Да --> H
  J -- Нет --> K[Оценка риска: принудительное удаление finalizer]
  K --> L[Документировать и применить патч]
  L --> M[Проверить последствия и закрыть инцидент]

Примеры и сниппеты (cheat sheet)

Просмотр finalizers:

kubectl get   -n  -o json | jq .metadata.finalizers

Удаление finalizer (merge):

kubectl patch   -n  -p '{"metadata":{"finalizers":[]}}' --type=merge

Удаление секции finalizers (JSON Patch):

kubectl patch   -n  --type=json -p '[{"op":"remove","path":"/metadata/finalizers"}]'

Прямой вызов API для задания политики удаления (пример):

curl -k -X DELETE "https:///apis/apps/v1/namespaces//deployments/" -H "Content-Type: application/json" -d '{"apiVersion":"v1","kind":"DeleteOptions","propagationPolicy":"Background"}'

Краткий глоссарий (1 строка на термин)

  • Finalizer — маркер в metadata, откладывающий удаление до выполнения очистки.
  • DeletionTimestamp — метка, означающая, что объект помечен на удаление.
  • OwnerReference — ссылка на родительский объект, управляющая каскадным удалением.
  • PropagationPolicy — политика порядка удаления родителя/детей (Foreground/Background/Orphan).

Заключение

Finalizers — мощный механизм обеспечения корректного удаления ресурсов в Kubernetes, но при неправильном управлении они часто становятся причиной «залипания» объектов. Всегда начинайте с диагностики: просмотров finalizers, событий, логов контроллеров и ownerReferences. Принудительное удаление должно быть крайней мерой и документироваться.

Важно: настройте наблюдаемость и мониторинг контроллеров, чтобы минимизировать необходимость ручного вмешательства.


[Внешняя справка и ресурсы]

  • Официальная документация Kubernetes: управление удалением и Finalizers
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Подписать PowerShell-скрипт и убрать ошибку «не подписан»
PowerShell

Подписать PowerShell-скрипт и убрать ошибку «не подписан»

Руководство по ошибкам OAuth2: причины и решения
Безопасность

Руководство по ошибкам OAuth2: причины и решения

Calibration в Lightroom — полное руководство
Редактирование фото

Calibration в Lightroom — полное руководство

Как отключить тактильную отдачу на Android
Android.

Как отключить тактильную отдачу на Android

Steam Deck: как работать в офлайн‑режиме
Гайды

Steam Deck: как работать в офлайн‑режиме

Как настроить повторяющиеся встречи в Zoom
Инструкции

Как настроить повторяющиеся встречи в Zoom