Kubernetes глазами скептика: главная ценность, контроллеры и Services

Автор блога (в тексте он не назван) много лет занимается системным администрированием и инфраструктурой, но с Kubernetes не сталкивался: его работа требовала очень жёсткого контроля над размещением нагрузки в физических точках. Скепсис к Kubernetes держался на смутных представлениях, «новый способ делать вещи» и «лишняя сложность». Чтобы опираться на факты, а не на ощущения, автор изучил систему и записал, что понял. Обычные туториалы его не устроили: они поверхностно описывают, что делают компоненты, но не объясняют причины и компромиссы.

Стандартное описание (Pod, Node, Cluster, Service, Namespace; запуск произвольной нагрузки, выбор хоста, самовосстановление, обнаружение сервисов по DNS; цена, упаковка в Docker-образ) автор считает малополезным: так выглядит множество инфраструктурных платформ. По его мнению, большая часть ценности Kubernetes держится на двух идеях.

Первая, циклы управления (контроллеры). Контроллер непрерывно действует через управляющий элемент, чтобы достичь желаемого состояния, наблюдая за переменными через датчик; при этом управляющий элемент не обязан напрямую влиять на то, что измеряет датчик. Примеры автора: очередь событий (желаемое состояние, пустая очередь, датчик, глубина очереди, управляющий элемент, число обработчиков); горизонтальное масштабирование под нагрузку (держать задержку P90 ниже заданного порога, датчик, метрики задержки, действие, запуск новых Pod); проверка здоровья (все Node исправны, датчик, метрики узлов, действие, вывод узлов из кластера).

Вторая, Service: сетевая абстракция со стабильным доступом к набору Pod. Она даёт неизменный виртуальный IP-адрес и DNS-запись, балансировку трафика и обнаружение сервисов. В «классическом» кластере это аналог связки из нескольких узлов с Keepalived и NGINX плюс CNAME-записи на виртуальный адрес. При создании Service ему назначается виртуальный IP, а каждый Node обновляет правила netfilter, перенаправляя пакеты на виртуальный адрес к нужным Pod. Это делает контроллер kube-proxy, работающий на каждом узле: он следит за всеми объектами Service и обновляет правила при каждом изменении. Следствия: все узлы работают балансировщиками, единой точки отказа в пересылке трафика нет, а пропускная способность растёт с размером кластера. Поскольку каждый узел получает правила для каждого сервиса, реализация kube-proxy очень проста, но правил может быть много, что проблемно для некоторых способов пересылки (iptables проверяет правила линейно). Трафик в ряде случаев пересылается дважды (например, при переносе Pod на другой узел, пока не истечёт старая DNS-запись), что повышает доступность ценой дополнительной нагрузки; при этом не нужно разбираться с инвалидацией кэша DNS на уровне kube-proxy, а клиенты, не пересчитывающие DNS перед переподключением, продолжают работать.

Далее автор разбирает управление нагрузкой. Вручную созданный Pod не будет перезапущен, если умер узел или Pod вытеснен из-за нехватки ресурсов, и нельзя просто сказать «хочу две копии». ReplicaSet, контроллер, который поддерживает нужное число реплик, но позволяет менять только их количество; чтобы обновить версию nginx или открыть другой порт, ресурс придётся удалить и создать заново. Deployment решает это: при обновлении он создаёт новый ReplicaSet и постепенно наращивает его, уменьшая старый, то есть даёт плавное обновление; слово «в итоге» (eventually) автор считает очень важным.

Про хранилище: по умолчанию контейнеры в одном Pod не делят файловую систему. Временные тома живут, пока жив Pod, и поначалу казались автору бесполезными, но годятся для отправки логов из sidecar-контейнера и для наполнения кэшей. Постоянные тома существуют независимо от Pod и подключаются через Claim (в примере запрос, 1Gi). Автор отмечает, что несколько Pod с одним Claim делят хранилище, что рискованно при нескольких писателях, а за томом могут стоять разные драйверы (NFS, SMB, iSCSI), поэтому Pod не может полагаться на их возможности, например на атомарное переименование. StatefulSet объединяет в одном ресурсе нагрузку, число реплик, монтирование и шаблон запроса тома; у Pod стабильные имена (nginx-0, nginx-1). Создание идёт по возрастанию номеров, удаление и обновление, по убыванию. Автору это кажется странным: объяснения «младшие номера, основные/стабильнее» он не понимает, ведь «падающий» Pod не получает новый номер.

Итог: понятия, по мнению автора, во многом разумны, Services (вместе с сетевой моделью и kube-proxy) он называет «фантастическими», а контроллеры как движок управления ресурсами, верным подходом. Свой вывод он оценивает как «менее необоснованный», добавляя, что кластером так и не пользовался. Остались вопросы: почему не важно, что состояние кластера может никогда не стабилизироваться (так сказано в документации по контроллерам), если оператору хотелось бы знать о нестабильности сразу; почему при паттерне контроллеров нет поддержки «облачно-нативных» архитектур; он хотел бы ReplicaSet, масштабируемый по простой формуле вроде «глубина очереди / 16 = число реплик» (по сути, Horizontal Pod Autoscaler с датчиками не только по CPU); почему сетевые и дисковые реализации вынесены из основного кода (CNI / CSI) и тогда зачем явная поддержка облачных провайдеров вроде AWS, GCP, Azure. Последний раздел, гневная заметка про «строковые типы» (Stringy types), в доступном тексте обрывается на первой фразе.

Ключевые факты

  • Автор, инфраструктурный инженер, годами избегавший Kubernetes; изучил его по материалам и признаёт, что кластер так и не эксплуатировал и не использовал.
  • Его мнение: большая часть ценности Kubernetes держится на двух идеях, циклах управления (контроллерах) и Service.
  • Service с kube-proxy на каждом узле: все узлы, балансировщики, единой точки отказа в пересылке трафика нет, пропускная способность растёт с кластером; цена, большое число правил (iptables проверяет их линейно).
  • Цепочка Pod → ReplicaSet → Deployment: ReplicaSet меняет только число реплик, Deployment обеспечивает плавное обновление через новый ReplicaSet.
  • Вопросы без ответа: порядок обновления в StatefulSet, ручной осмотр постоянного тома, масштабирование не только по CPU, вынос CNI/CSI за пределы основного кода.

Почему это важно

Текст показывает, как опытный инфраструктурный инженер, не имевший дела с Kubernetes, раскладывает его по причинам и компромиссам, а не по перечню компонентов. Его главный тезис, ценность системы в контроллерах и Service, а остальное типично для инфраструктурных платформ. Заголовок поста датирован 2024 годом, это не новый релиз и не исследование, а личное эссе.

Кому это важно

Администраторам и инфраструктурным инженерам, которые ещё не работали с Kubernetes и хотят понять его логику через знакомые аналоги (Keepalived + NGINX, DNS-записи, netfilter). Также тем, кто выбирает, стоит ли переходить на Kubernetes, и хочет услышать взгляд скептика.

Как это применить

Текст, обзор понятий, а не инструкция: в нём есть короткие YAML-примеры Pod, ReplicaSet и PersistentVolumeClaim (образ nginx:1.14.2, 3 реплики, запрос 1Gi). Полезно прочитать его как карту концепций: сначала контроллеры и Service, затем Pod → ReplicaSet → Deployment, потом тома и StatefulSet. Проверять выводы автора придётся на реальном кластере.

Можно ли доверять

Это мнение одного автора, не названного в тексте. Он прямо оговаривает, что кластером не пользовался, а его вывод лишь «менее необоснованный». Измерений, бенчмарков и цифр по размеру кластеров нет, версия Kubernetes не указана. Доступный текст обрывается в начале раздела «Stringy types», поэтому претензии автора по этой теме не видны.

Риски и подводные камни

Выводы построены на чтении документации и размышлениях, без практики эксплуатации; часть вопросов автора может иметь ответы, которых он не нашёл. Сам он называет открытыми вопросы о ручном осмотре постоянного тома (что делать, если в контейнере нет оболочки), о порядке работы StatefulSet и о том, как проектируется система, которая может никогда не достичь стабильного состояния. Многочисленные правила Service могут быть проблемой для некоторых способов пересылки трафика.

«Ваш кластер может меняться в любой момент по мере выполнения работы, а циклы управления автоматически исправляют сбои. Это означает, что кластер потенциально никогда не достигает стабильного состояния.»

— Документация Kubernetes о контроллерах, в цитате автора поста