сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Kubernetes

Архитектура кластера Kubernetes

Как устроен кластер

Кластер - это группа машин, которые работают как одна и сами раскладывают по себе приложения; каждая машина в нём называется узлом, а запущенное приложение живёт в поде. Поднял настоящий кластер и удалил из него под руками. Через 2125 миллисекунд рабочих подов снова стало два - никто ничего не запускал, кластер сам вернул описанное состояние. Имя у нового пода при этом другое: старый ушёл навсегда, вместо него появился новый.

Стержень: кластер это не запускалка контейнеров, а цикл сверки - он непрерывно сравнивает «что описано» с «что есть» и устраняет разницу.

// Формулировки: «из чего состоит кластер?», «что происходит после kubectl apply?», «зачем нужен под, если есть контейнер?»

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

Вы не говорите кластеру «запусти контейнер». Вы записываете желаемое состояние: должно быть два экземпляра такого-то образа (образ - это неизменяемая заготовка приложения со всем нужным внутри). Кластер принимает эту запись, хранит её и дальше сам следит, чтобы реальность ей соответствовала.

Отсюда и мой замер. Я удалил под, и через две секунды его место занял новый - потому что в записи по-прежнему стоит «два экземпляра», а по факту остался один. Ровно так же кластер поступает при падении узла, при вылете процесса, при любом расхождении. Никакой автоматики поверх писать не надо, это и есть его основная работа.

// Отсюда важное следствие для проектирования: поды одноразовы. Имя нового пода в моём замере отличалось от старого, адрес тоже сменился. Значит, нельзя ни привязываться к имени пода, ни хранить внутри него данные, ни считать его адрес постоянным.

желаемое состояние
запись о том, что должно быть; кластер приводит реальность к ней
цикл сверки
непрерывное сравнение описанного с фактическим и устранение разницы
одноразовый под
его в любой момент могут заменить новым с другим именем и адресом

Из чего кластер состоит

Управляющая часть отвечает за решения. Точка входа принимает все запросы, проверяет права и записывает изменения в хранилище - именно с ней разговаривает командная строка и все компоненты. Хранилище держит всё желаемое состояние кластера; потеря его означает потерю кластера. Планировщик решает, на какой узел поставить новый под. Набор контроллеров следит, чтобы фактическое совпадало с желаемым, - это те самые циклы сверки.

Рабочая часть исполняет. На каждом узле живёт агент, который получает задание и запускает контейнеры через среду выполнения, а также гоняет проверки состояния и докладывает результат наверх. Рядом - сетевая часть, которая раздаёт адреса и правила.

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

точка входа
единственный вход в кластер: принимает запросы, проверяет права, пишет в хранилище
планировщик
решает, на какой узел поставить под
агент узла
запускает контейнеры на своей машине и докладывает их состояние

Под и цепочка владения

Под - это группа контейнеров, которые всегда живут вместе: на одном узле, с общим сетевым адресом и общими томами (том - это хранилище данных, подключённое снаружи и живущее отдельно от контейнера). Чаще всего в нём один рабочий контейнер, иногда рядом ставят вспомогательный - сборщик логов или прокси. Обращаться к контейнеру напрямую нельзя, кластер оперирует подами.

Сам под никто не создаёт руками. Над ним стоит цепочка: развёртывание описывает желаемую версию и число экземпляров, оно создаёт набор реплик, а тот уже создаёт поды. В моём кластере это видно буквально: одно развёртывание, один набор реплик, два пода.

// Зачем промежуточный уровень: набор реплик привязан к КОНКРЕТНОЙ версии образа. При обновлении развёртывание создаёт новый набор и постепенно переводит поды в него, а старый оставляет пустым. Поэтому откат делается мгновенно - достаточно снова наполнить старый набор.

под
группа контейнеров с общим адресом и томами, всегда на одном узле
набор реплик
держит заданное число подов одной конкретной версии
развёртывание
управляет наборами реплик: обновляет версию и умеет откатывать

Как отвечать: «Что происходит после того, как вы применили описание?»

Описание уходит в точку входа кластера: там проверяются права и формат, после чего запись ложится в хранилище желаемого состояния. Дальше начинают работать контроллеры. Контроллер развёртывания видит новую запись и создаёт набор реплик, тот создаёт поды. Планировщик подбирает каждому поду узел по запросам ресурсов. Агент на этом узле забирает задание, тянет образ и запускает контейнер, а потом докладывает состояние наверх. И всё это - непрерывный цикл сверки, а не разовая команда: я специально удалял под руками, и через две секунды кластер поднял новый, потому что в записи по-прежнему требовалось два экземпляра. Поэтому и разбор поломок идёт по той же цепочке: под в ожидании - к планировщику, контейнер не стартует - к агенту узла и образу, ничего не произошло - к правам.

Ответ проходит весь путь и заканчивается тем, как эта же цепочка используется при разборе аварий. Замер с удалённым подом показывает, что человек это видел, а не читал.

На чём валятся

  • Считают кластер запускалкой контейнеров и не понимают, почему удалённый под возвращается.
  • Создают поды напрямую вместо развёртывания и лишаются и перезапуска, и обновления.
  • Привязываются к имени или адресу пода: они меняются при каждой замене.
  • Хранят данные внутри пода и теряют их при первом пересоздании.
  • Не знают про хранилище желаемого состояния и не делают его копий.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 8, остальные разбираются в тренажёре.

  1. #dvo_k8s_arch1 / 5
    Control plane недоступен: api-server не отвечает. Что происходит с уже работающими подами?
    A)Kubelet останавливает поды: без связи с мастером они считаются осиротевшими
    B)Поды переезжают на ноды, которые ещё видят мастер
    C)Поды продолжают работать, но пропадает балансировка через сервисы
    D)Продолжают работать: kubelet держит их, а изменения и новые выкатки встают
    показать ответ и разбор
    +D)Продолжают работать: kubelet держит их, а изменения и новые выкатки встают

    // разбор: Рабочая нагрузка живёт на нодах: kubelet перезапускает упавшие контейнеры по локально известной спецификации, kube-proxy держит уже настроенные правила, трафик ходит. Ломается управление — новые деплои, масштабирование, реакция на падение ноды, kubectl. Потому отказ control plane тяжёлый, но не мгновенно фатальный: главное успеть починить до первой аварии на нодах.

  2. #dvo_k8s_arch2 / 5
    В кластере из трёх узлов etcd два вышли из строя. Что будет с кластером?
    A)Кворум потерян: запись невозможна, состояние замирает
    B)Оставшийся узел станет лидером и продолжит принимать записи
    C)Кластер перейдёт в режим кэша и синхронизируется после возврата узлов
    D)Ничего: api-server держит состояние у себя и работает автономно
    показать ответ и разбор
    +A)Кворум потерян: запись невозможна, состояние замирает

    // разбор: etcd — хранилище всего состояния кластера с алгоритмом консенсуса: для записи нужен кворум, то есть большинство узлов. Из трёх переживают потерю одного; два выпавших узла означают отсутствие большинства — запись отвергается, а api-server остаётся с доступом на чтение. Отсюда правила: нечётное число узлов, разнос по зонам и регулярный снапшот, потому что бэкап etcd и есть бэкап кластера.

  3. #dvo_k8s_arch3 / 5
    Кто в Kubernetes решает, на какую ноду поедет под, а кто его там запускает?
    A)Scheduler и выбирает ноду, и сам запускает под на ней
    B)Scheduler назначает ноду, kubelet на ней запускает под
    C)kubelet выбирает ноду, а scheduler уже запускает контейнеры
    D)api-server напрямую раскидывает поды по нодам сам
    показать ответ и разбор
    +B)Scheduler назначает ноду, kubelet на ней запускает под

    // разбор: kube-scheduler подбирает ноду для Pending-пода (пишет nodeName в спеку) по requests, affinity и taints. kubelet на этой ноде тянет образы, запускает контейнеры и репортит статус. api-server лишь хранит желаемое состояние в etcd и не занимается размещением. Разделение ответственности: scheduler решает «где», kubelet делает «запустить».

  4. #dvo_k8s_arch4 / 5
    Ноды и приложения работают, но потеряли данные etcd, а бэкапа нет. Насколько это критично?
    A)Потеряно всё состояние кластера — по сути это его потеря
    B)Некритично: kubelet на каждой ноде хранит копию состояния
    C)api-server восстановит состояние из логов запущенных подов
    D)Потеряются только метрики, рабочие нагрузки не пострадают
    показать ответ и разбор
    +A)Потеряно всё состояние кластера — по сути это его потеря

    // разбор: etcd хранит всё состояние кластера: объекты, спеки, RBAC, секреты. Ноды какое-то время крутят поды по локальному виду, но желаемое состояние и все определения есть только в etcd. Потеря etcd без бэкапа = невозможность восстановить кластер, даже если нагрузки ещё работают. Отсюда правило: регулярные снапшоты etcd (etcdctl snapshot save).

  5. #dvo_k8s_arch5 / 5
    Задеплоили валидирующий admission-webhook. Он лёг — и кластер перестал создавать поды. Почему и как избежать?
    A)Вебхук занял все соединения api-server, и тот перестал отвечать
    B)Упавший вебхук каскадом удалил уже существующие поды кластера
    C)При failurePolicy=Fail упавший вебхук отклоняет create-операции
    D)Поды не создаются, потому что вебхук держал их манифесты у себя
    показать ответ и разбор
    +C)При failurePolicy=Fail упавший вебхук отклоняет create-операции

    // разбор: Admission-вебхуки вызывает api-server на матчащих create/update. При failurePolicy: Fail, если эндпоинт вебхука недоступен, api-server отклоняет операцию — мёртвый вебхук блокирует все подходящие create. Смягчение: сузить namespaceSelector/objectSelector, исключить kube-system, задать разумный timeoutSeconds, поднять вебхук в HA, а где допустимо — failurePolicy: Ignore.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.