Пример отладки экземпляра Deployment в Kubernetes
Не так давно я просматривал список багрепортов в репозитории
Kubernetes. Искал что бы такое починить в целях повышения собственной
заметности в сообществе. И наткнулся
на отчёт,
который следовало бы озаглавить как «Таинственное обновление
ReplicaSet
в Deployment
, которое его ломает».
Сейчас причина сбоя видится тривиальной, если подумать, а не использовать накопившиеся условные рефлексы. Но в тот момент задача показалась не столь простой, а от того - интересной. И я решил ею заняться.
Раз отчёт об ошибке появился на багтрекере Кубернетиса, то и проблема скорее всего в самом Кубернетисе, наивно подумал я. Но как вообще люди решают подобные задачи? Нет ли уже готовой методологии для этого? Лично я ничего подобного не встречал, но, похоже, не я один задаюсь такими вопросами. А потому я решил скопировать свой комментарий на эту тему из обсуждения отчёта сюда. Так мне его потом проще будет найти. И, может быть, кому-то ещё пригодится.
Мой способ отладки это путь проб и ошибок прежде всего, слегка направляемый некоторым моим прошлым опытом. Но общий алгоритм таков:
-
Воспроизвести проблему локально. Как правило этот шаг занимает больше всего времени.
-
Посмотреть во все доступные логи на предмет странного. К сожалению, у всех людей разное представление о странном, сильно зависящее от опыта. Чем больше опыт, тем очевиднее странное. Мой крохотный опыт не позволил найти ничего странного на этом шаге.
-
Попробовать собрать старую версию Кубернетиса. Чем старее, тем лучше. Если проблема не воспроизводится, то дальнейшие шаги сводятся к последовательным запусками
git bisect
с целью найти коммит, который привносит проблему. Но в данном случае проблема воспроизводилась даже в Kubernetes v1.8.0, а значит это не обычная регрессия, и надо копать дальше. -
Изучить содержимое проблемных объектов (
ReplicaSet
) посредством коммандыkubectl describe ...
. Как объекты одного и того же типа отличаются друг от друга? Если какой-то объект меняется с течением времени, то следует присмотреться, что именно в нём меняется. На этом шаге обнаружилось, что изменяется объектDeployment
- в нём исчезают “tolerations”. -
Найти код, который исполняется в время изменения
Deployment
и сделай логгирование по-многословнее. Тут оказалось, что искомый код находится вkube-contoller-manager
, а установка вот такой переменной окружения повышает словоохотливость логовLOG_SPEC=deployment_controller*=5,replica_set*=5,sync*=5,recreate*=5
Однако единственным результатом этого шага стало подтверждение, что объект
Deployment
действительно кем-то изменяется. -
Изменить обработчик обновления объектов
Deployment
, чтобы в логах было видно, что конкретно изменяется помимо “tolerations” (например, с помощью в этой библиотеки). Тут могут быть сюрпризы… Но не в этот раз. -
Поискать код, который непосредственно меняет объекты
Deployment
черезapiserver
при помощи вот такой команды.$ git grep Deployments | grep "Update("
В коде Кубернетиса есть всего несколько мест, где
Deployment
обновляются, но ни одно из них не выглядит подозрительным. Это, наконец-то, приводит нас к давно напрашивающемуся выводу о том, что источник изменений объекта находится где-то за пределами кода самого Кубернетиса. -
Посмотреть на YAML-файлы. Нет ли там чего-нибудь интересного. Однако в этих файлах интересного слишком много - глаза разбегаются. А значит следует
-
Попробовать найти минимальную конфигурацию, при которой проблема всё ещё воспроизводится. Здесь обнаружилось, что простые маленькие изменения в разных местах файлов конфигураций приводят к тому, что проблема исчезает, как, впрочем, и работа конфигурации.
-
Тогда ничего не остаётся кроме как изучить файлы конфигураций строчку за строчкой в надежде найти хоть какую-то зацепку. Хоть какая-то зацепка оказалась тем, что сервис работает под учётной записью
kube-state-metrics
, которая запрашивает разрешение на изменения объектов типаDeployment
. -
Логично попробовать запретить этой учётной записи изменять
Deployment
‘ы. Это подтвердит, что объектыDeployment
больше не изменяются. -
Заглянуть в логи изучаемого пода. Вот оно! В логах контейнера
addon-resizer
есть сообщение о невозможности изменитьDeployment
. -
Найти исходники для образа
addon-resizer:1.0
. Это оказалось непростой задачей, поскольку версия 1.0 ну очень уж старая и даже недоступна в текущем репозитории исходников, из которых строится этот образ. Очевидно причина проблем в том, что Kubernetes API эволюционировал слишком сильно со времён версии 1.0. Беглый взгляд наPodSpec
, который используется вaddon-resizer:1.0
подтверждает эту гипотезу.
Итак, проблема в слишком старом образе контейнера данной конфигурации -
quay.io/coreos/addon-resizer:1.0
.
Внутри этого контейнера запускается клиент, который по каким-то своим
соображениям изменяет конфигурацию сервиса, но делает это используя
устаревший API, в котором нет поля Tolerations
в определении PodSpec
.
В итоге наше “развёртывание” теряет “tolerations” в шаблоне пода. Такая
потеря приводит к необходимости контроллеру “развёртываний”
(deployment controller) обновить объект Deployment
, а значит и
пересоздать ReplicaSet
. Управляемый новым объектом ReplicaSet
под
не имеет установленных “tolerations”, а потому не может стартовать
на узле, помеченном как мастер-узел.