Русский
Русский
English
Статистика
Реклама

Перевод Контролируем удаление с финализаторами

image


В Kubernetes не так-то просто что-то удалить вы уверены, что удалили объект, но оказывается, что он все еще присутствует в кластере. Вы, конечно, можете выполнять команду kubectl delete в повседневных операциях и надеяться на лучшее, но знание принципов работы delete команд в Kubernetes поможет вам понять, почему некоторые объекты остаются после удаления.


В этой статье мы рассмотрим:


  • Какие свойства ресурса влияют на удаление.
  • Как финализаторы и ссылки на родителя-владельца управляют удалением объектов.
  • Как можно использовать propagationPolicy, чтобы изменить порядок удаления.
  • Как работает удаление, с примерами.

Для простоты во всех примерах мы используем ConfigMaps и базовые команды kubectl. Мы увидим, как работают эти команды, и обсудим результаты их использования на практике.


Базовая команда delete


В Kubernetes есть несколько команд для создания, чтения, обновления и удаления объектов. Здесь мы поговорим о четырех командах kubectl: create, get, patch и delete.
Примеры базовой команды kubectl delete:


kubectl create configmap mymapconfigmap/mymap created

kubectl get configmap/mymapNAME    DATA   AGEmymap   0      12s

kubectl delete configmap/mymapconfigmap "mymap" deleted

kubectl get configmap/mymapError from server (NotFound): configmaps "mymap" not found

Перед командой стоит знак $, далее следует ее результат. Как видите, мы начали с kubectl create configmap mymap, чтобы создать пустой configmap mymap. Теперь нужно выполнить get и убедиться, что он существует. Затем мы удалили configmap. Если снова сделать get, получим ошибку HTTP 404, потому что configmap не найден.


У команды deleteочень простая диаграмма состояний:


image
Диаграмма состояний для delete


Операция незамысловатая, но ей могут помешать некоторые факторы, включая финализаторы и ссылки на родителя-владельца.


Как работают финализаторы


Чтобы понять, как удаляются ресурсы в Kubernetes и почему они иногда все-таки не удаляются, полезно разобраться с финализаторами.


Финализаторы это ключи в манифесте ресурса, отвечающие за операции, которые надо выполнить до удаления объекта. Они контролируют сборку мусора для ресурсов и сообщают контроллерам, какие операции очистки нужно выполнить до удаления ресурса. Они не обязательно обозначают код, который нужно выполнить. По сути, это просто списки ключей, вроде аннотаций. Как и аннотациями, ими также можно управлять.


Скорее всего, вы встречали следующие финализаторы:


  • kubernetes.io/pv-protection
  • kubernetes.io/pvc-protection

Они используются для постоянных томов и не дают случайно удалить их. Точно так же некоторые финализаторы могут использоваться для предотвращения удаления любого ресурса.


Ниже приводится configmap без свойств, но с финализатором:


cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap  finalizers:  - kubernetesEOF

Контроллер ресурса configmap не понимает, что делать с ключом финализатора kubernetes. Такие финализаторы для configmap я называю мертвыми, и обычно они используются с неймспейсами. Вот что происходит при попытке удалить configmap:


kubectl delete configmap/mymap &configmap "mymap" deletedjobs[1]+  Running kubectl delete configmap/mymap

Kubernetes сообщает, что объект удален, но на самом деле, в традиционном понимании, никуда он не удален. Скорее он находится в процессе удаления. Если мы снова выполним get, то узнаем, что объект изменен и теперь содержит временную метку удаления deletionTimestamp.


kubectl get configmap/mymap -o yamlapiVersion: v1kind: ConfigMapmetadata:  creationTimestamp: "2020-10-22T21:30:18Z"  deletionGracePeriodSeconds: 0  deletionTimestamp: "2020-10-22T21:30:34Z"  finalizers:  - kubernetes  name: mymap  namespace: default  resourceVersion: "311456"  selfLink: /api/v1/namespaces/default/configmaps/mymap  uid: 93a37fed-23e3-45e8-b6ee-b2521db81638

Если в двух словах, объект был изменен, но не удален. Все потому, что Kubernetes увидел, что у объекта есть финализаторы, и поместил его в состояние read-only. Временная метка удаления показывает, что объект можно только читать а еще из него можно удалить апдейты ключа финализатора. Другими словами, удаление будет завершено, только когда мы удалим из объекта финализатор.


Удалить финализаторы можно с помощью команды patch. Фоновое удаление завершится, и объект будет удален. Если мы опять выполним get configmap, то ничего не увидим.


kubectl patch configmap/mymap \    --type json \    --patch='[ { "op": "remove", "path": "/metadata/finalizers" } ]'configmap/mymap patched[1]+  Done  kubectl delete configmap/mymapkubectl get configmap/mymap -o yamlError from server (NotFound): configmaps "mymap" not found

Диаграмма состояния для финализации выглядит так:


image
Диаграмма состояний для финализации


Если мы попытаемся удалить объект с финализатором, он останется на этапе финализации, пока контроллер не удалит ключи финализаторов или финализаторы не будут удалены через Kubectl. Когда список финализаторов будет пуст, Kubernetes поместит его в очередь на удаление из реестра.


Ссылки на владельца


Ссылки на владельца (owner references) описывают отношения между группами объектов. Это свойства ресурсов, которые указывают, как они связаны друг с другом, чтобы можно было удалять целые деревья ресурсов.


Правила финализатора обрабатываются, если есть ссылки на владельца. Ссылки на владельца состоят из имени и UID. Они связывают ресурсы в одном неймспейсе и им нужен UID. Ссылки на владельца для подов обычно указывают на replica set, которому они принадлежат. Если удалить deploy или stateful set, дочерние replica set и pod тоже удалятся.


Посмотрим на примере, как работают ссылки на владельца. В первом примере мы сначала создаем родительский объект, а потом дочерний. В результате получаем простейший configmap со ссылками на владельца, то есть родителя:


cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap-parentEOFCM_UID=$(kubectl get configmap mymap-parent -o jsonpath="{.metadata.uid}")cat <<EOF | kubectl create -f -apiVersion: v1kind: ConfigMapmetadata:  name: mymap-child  ownerReferences:  - apiVersion: v1    kind: ConfigMap    name: mymap-parent    uid: $CM_UIDEOF

Если мы удалим дочерний объект, в котором есть ссылка на владельца, родитель никуда не денется:


kubectl get configmapNAME           DATA   AGEmymap-child    0      12m4smymap-parent   0      12m4skubectl delete configmap/mymap-childconfigmap "mymap-child" deletedkubectl get configmapNAME           DATA   AGEmymap-parent   0      12m10s

В следующем случае мы воссоздали configmap из примера выше. Если мы удалим родителя, а не дочерний объект, в котором есть ссылка на него, а потом сделаем get для configmap, то увидим, что все configmap пропали:


kubectl get configmapNAME           DATA   AGEmymap-child    0      10m2smymap-parent   0      10m2skubectl delete configmap/mymap-parentconfigmap "mymap-parent" deletedkubectl get configmapNo resources found in default namespace.

Получается, что если в дочернем объекте есть ссылка на родителя, он автоматически удаляется при удалении родителя. Это называется cascade. По умолчанию cascade имеет значение true, но можно указать --cascade=false в kubectl delete, чтобы удалить родительский объект, не трогая дочерние.


В следующем примере у нас есть родительский и дочерний объекты, а еще ссылки на владельца. Если мы удалим родителя, указав --cascade=false, дочерние объекты сохранятся:


kubectl get configmapNAME           DATA   AGEmymap-child    0      13m8smymap-parent   0      13m8skubectl delete --cascade=false configmap/mymap-parentconfigmap "mymap-parent" deletedkubectl get configmapNAME          DATA   AGEmymap-child   0      13m21s

Параметр --cascade указывает на политику распространения в API, которая позволяет менять порядок объектов удаления в дереве. В следующем примере используется отправка запроса к API через curl для удаления с фоновой политикой распространения (propagation policy):


kubectl proxy --port=8080 &Starting to serve on 127.0.0.1:8080curl -X DELETE \  localhost:8080/api/v1/namespaces/default/configmaps/mymap-parent \  -d '{ "kind":"DeleteOptions", "apiVersion":"v1", "propagationPolicy":"Background" }' \  -H "Content-Type: application/json"{  "kind": "Status",  "apiVersion": "v1",  "metadata": {},  "status": "Success",  "details": { ... }}

Политику распространения нельзя указать в командной строке с помощью kubectl только при прямом вызове API. Просто создайте прокси, чтобы иметь доступ к серверу API со своего компьютера, и выполните команду curl с одним URL, чтобы послать команду delete.


Есть три варианта политики распространения:


  • Foreground: дочерние объекты удаляются до родительского (обратный порядок).
  • Background: родительский объект удаляется до дочерних (прямой порядок).
  • Orphan: ссылки на владельца игнорируются.

Если вы удаляете объект, в котором есть ссылки на владельца, то финализаторы также будут учитываться. В результаты деревья объектов могут сохраняться, и удаление будет частичным. В этом случае изучите имеющиеся ссылки на владельца и финализаторы, чтобы понять, что происходит.


Принудительное удаление неймспейса


В некоторых случаях для удаления неймспейсов может потребоваться принудительная финализация: если вы удалили неймспейс и очистили все объекты в нем, но неймспейс по-прежнему существует, его можно удалить принудительно, обновив его подресурс, finalize. Так контроллер неймспейса поймет, что нужно удалить финализатор и выполнить очистку:


cat <<EOF | curl -X PUT \  localhost:8080/api/v1/namespaces/test/finalize \  -H "Content-Type: application/json" \  --data-binary @-{  "kind": "Namespace",  "apiVersion": "v1",  "metadata": {    "name": "test"  },  "spec": {    "finalizers": null  }}EOF

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


Итоги


Как показывают примеры, финализаторы могут помешать удалению ресурсов в Kubernetes, особенно если речь о родительских и дочерних объектах. Обычно финализаторы добавляются в код не просто так, поэтому нужно все проверить, прежде чем удалять их вручную. С помощью ссылок на владельца можно указывать и удалять деревья ресурсов, хотя и в этом случае будут учитываться финализаторы. Наконец, можно использовать политику распространения, чтобы указывать порядок удаления в прямых вызовах API и контролировать процесс удаления объектов. Теперь вы чуть больше знаете о том, как работает удаление в Kubernetes, и можете поэкспериментировать самостоятельно в продакшен-кластере.


Видео от автора:


Источник: habr.com
К списку статей
Опубликовано: 18.06.2021 08:07:31
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании southbridge

Системное администрирование

Серверное администрирование

Devops

Kubernetes

Finalizers

K8s

Kubectl

Категории

Последние комментарии

© 2006-2021, personeltest.ru