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

Я Tech Lead и руководитель направления Java | Kotlin разработки в FinTech & E-commerce, преподаю на курсах разработки и архитектуры в OTUS. Через мои руки прошли десятки проектов, и везде, где появлялся Kubernetes, возникал один и тот же парадокс: инструмент называют стандартом, но реальное понимание его механик встречается редко.

Давайте разбираться.

Рис. 1 Стилизованная визуализация идеи оркестрации: Kubernetes наводит порядок в хаосе контейнеров
Рис. 1 Стилизованная визуализация идеи оркестрации: Kubernetes наводит порядок в хаосе контейнеров

Почему Kubernetes — это не «ещё один Docker»

Бытует мнение, что Kubernetes — это просто «запускатор контейнеров». Заблуждение дорогое. Когда говорят «контейнеры», чаще всего подразумевают Docker. Но Docker отвечает за упаковку и запуск одного контейнера на одной машине. Kubernetes — про другое: про оркестрацию тысяч контейнеров на сотнях машин как единой системы.

Помню, как в одном проекте мы честно пытались жить на голом Docker Swarm. Пока сервисов было 15-20, ручное управление ещё работало. Когда перевалили за полсотни, начались ночные звонки: «падает балансировка», «отжирает память на третьем хосте», «мы не можем понять, кто кого зовёт». Kubernetes решает ровно эти проблемы — и делает это автоматически.

Архитектура: что под капотом

Кластер Kubernetes состоит из двух логических частей: Control Plane (мозг) и Worker Nodes(руки). Визуально это выглядит так:

Рис. 2 Схема высокоуровневой архитектуры Kubernetes-кластера
Рис. 2 Схема высокоуровневой архитектуры Kubernetes-кластера

API Server — единственная точка входа. Всё, что вы делаете через kubectl или через CI/CD-пайплайн, проходит через него. Scheduler решает, на каком узле запускать новый под, анализируя доступные ресурсы. Controller Manager — непрерывно сверяет текущее состояние кластера с желаемым: если вы заявили три реплики сервиса, а упала одна, контроллер мгновенно запустит новую. etcd — распределённое key-value хранилище, где хранится всё состояние кластера. Потеряете etcd без бэкапа — потеряете кластер.

На стороне Worker Nodes работает kubelet — агент на ноде, который отслеживает объекты Pod в API Server и приводит запущенные контейнеры к описанному состоянию. kube-proxy реализует сетевую модель Service (iptables/ipvs), обеспечивая маршрутизацию трафика к подам.

Спросите любого SRE, который поднимал прод-кластер с нуля: самая болезненная точка — это не приложения, а настройка Control Plane под высокую доступность. Три мастер-ноды, распределённый etcd, правильный load balancing перед API Server — без этого 99.9% uptime остаются фантазией.

Абстракции, в которых стоит разобраться раньше, чем случится прод

Документация Kubernetes огромна. Но есть несколько абстракций, без которых не получится даже стартануть. Вот мой «прожиточный минимум»:

Pod — минимальная единица развёртывания в Kubernetes: группа из одного или нескольких контейнеров, которые работают в рамках одной ноды и разделяют сеть и тома (volumes). Если вам кажется, что «один контейнер на под» — это избыточно, вспомните sidecar-паттерн: контейнер с приложением и рядом контейнер с прокси Envoy для service mesh. Вот тут pod раскрывается по-настоящему.

Service — стабильный сетевой endpoint для группы подов. Под может умереть и возродиться с новым IP, но Service предоставляет стабильный ClusterIP и DNS-имя на время своего существования. Без этого микросервисы просто не смогли бы найти друг друга. В моей практике был случай, когда команда разработки пыталась хардкодить IP подов в конфигах. После третьего перезапуска кластера они пришли к нам со словами «у нас всё сломалось». Service — это не опция, это базовая гигиена.

Deployment — декларативное описание желаемого состояния приложения: сколько реплик, какой образ, какие ресурсы. Вы говорите: «Хочу три пода с версией 1.2.0», и Kubernetes делает всё, чтобы это держалось, даже если ноды выходят из строя. Именно через Deployment работает механизм rolling update — постепенная замена старых подов новыми без даунтайма.

Namespace — логическая изоляция внутри кластера. Не путать с аппаратной изоляцией — это скорее organisational unit. Прод, стейджинг, дев должны жить в разных неймспейсах как минимум. Видел проекты, где всё валилось в default, а потом удивлялись, почему тестовый скрипт положил продовую базу.

Вот как выглядит типичный процесс от подачи команды до запуска пода (рис. 3):

Рис. 3 Процесс развёртывания: от команды до запуска пода
Рис. 3 Процесс развёртывания: от команды до запуска пода

Из этой диаграммы видно, что Kubernetes работает не по командам «сделай то-то», а по декларативному принципу. Разработчик или CI/CD-пайплайн заявляет желаемое состояние (три реплики Deployment), а дальше кластер сам распределяет ответственность: Scheduler выбирает подходящую ноду, kubelet через container runtime скачивает образ из реестра и запускает контейнер. Главная мысль: пользователь не указывает, на какой именно ноде запускать поды — Kubernetes берёт это на себя, постоянно сверяя реальное состояние с желаемым.

История, которая отрезвляет: миграция Tinder на Kubernetes

Ничто так не учит, как чужой production-опыт. В 2018–2019 годах инженерная команда Tinder провела полную миграцию платформы на Kubernetes, и это не был безболезненный переезд.

Исходная ситуация: более 200 микросервисов, написанных на Node.js, Java, Scala и Go, работали на EC2-инстансах с ручным масштабированием. Каждый новый инстанс поднимался минутами; при всплесках трафика команда физически не успевала реагировать. Деплой требовал координации нескольких человек и занимал часы.

Решение: контейнеризация всех сервисов, развёртывание Kubernetes-кластера с использованием инструментов автоматизации для AWS, переход на полностью автоматизированные деплой-пайплайны. Результат — кластер из 1 000 узлов, 15 000 подов и 48 000 запущенных контейнеров. Платформа Tinder теперь работает исключительно на Kubernetes.

Но дьявол в деталях. Когда кластер достиг «критической массы» в начале 2019 года, начались проблемы с DNS. CoreDNS в базовой конфигурации не справлялся с пиковыми DNS-запросами при массовом масштабировании подов, что потребовало тюнинга кеширования и масштабирования DNS-компонента. Инженерам пришлось внедрять кеширование на уровне нод и пересматривать архитектуру Service-объектов. Ещё один неочевидный момент: для 30+ репозиториев с разными языками команда построила универсальную систему сборки с паттерном «Builder Container», которая гарантировала идентичность окружения на дев-стендах и в проде.

Важно понимать: Tinder не просто «включил Kubernetes и всё поехало». Потребовался почти год методичного переноса сервисов и постоянного мониторинга. Зато теперь кластер держит нагрузку в десятки миллионов активных пользователей, а время деплоя сократилось.

Вывод, который я вынес для себя: Kubernetes не прощает «старта по-быстрому». Он требует инвестиций в компетенции команды до того, как вы выкатите первый под в прод!

Немного практики в тему — пройдите вступительный тест по Kubernetes и узнаете, есть ли пробелы в знаниях.

Best Practices: что работает в реальных командах

На основе опыта команд вроде Tinder, а также рекомендаций CNCF и ведущих провайдеров, вот практики, которые я считаю обязательными:

  1. Ресурсные requests и limits — не опция, а must. Без них один «прожорливый» под может положить всю ноду. В FinTech я видел, как отсутствие limits на Java-сервис вызывало каскадное вытеснение других подов при пиковой нагрузке. Правило простое: requests = гарантированный минимум, limits = «дальше не лезь».

  2. Liveness и Readiness probes. Kubernetes должен знать, жив ли ваш контейнер (liveness) и готов ли он принимать трафик (readiness). Без readiness-пробы трафик льётся на ещё не стартовавшее приложение; без liveness-пробы подвисший контейнер висит вечно. В одном из проектов мы потратили два дня, выясняя, почему балансировщик шлёт запросы на полумёртвые поды — ответ был в отсутствии readinessProbe.

  3. Строгий RBAC и Network Policies. Минимальные привилегии для каждого сервисного аккаунта. Согласно опросам CNCF, лишь 9% организаций имеют документированные процессы безопасности для cloud-native, а 85% требуют более безопасных значений по умолчанию в Kubernetes. Wildcard-доступы («*») должны вызывать аллергию, как пароли в открытом виде.

  4. GitOps как единственный источник истины. Весь desired state кластера — в Git. Никаких ручных правок через kubectl edit в проде. ArgoCD или Flux синхронизируют репозиторий с кластером автоматически. Это спасает от ситуации «я поправил, но забыл записать».

  5. Метрики, алерты, трейсы. Минимальный стек: Prometheus + Grafana для метрик, Loki для логов, Tempo или Jaeger для распределённой трассировки. Без этого вы летите вслепую.

Что остаётся за кадром и о чём поговорим на открытом уроке

Я сознательно не касаюсь в этой статье таких тем, как настройка автомасштабирования (HPA/VPA), service mesh на базе Istio, управление секретами через External Secrets Operator и построение инфраструктурной платформы на базе Kubernetes. Это те темы, где «дьявол в деталях» проявляется особенно остро, и именно их мы разберём на открытом уроке OTUS.

Если вы дочитали до этого места и чувствуете, что хотите не просто «знать, что такое под», а уметь проектировать платформу, которая выдержит прод — приходите. Урок бесплатный, нужно только зарегистрироваться. Он пройдёт 18 мая в 20:00 в рамках курса «Инфраструктурная платформа на основе Kubernetes», где мы вместе с практикующими инженерами разбираем реальные кейсы — от настройки кластера до эксплуатации под нагрузкой.

Хороший инженер не тот, кто знает все команды kubectl наизусть. Хороший инженер — тот, кто понимает, почему Kubernetes поступает так, а не иначе, и может спроектировать систему, которая не развалится в три часа ночи. Если этот разбор показался вам полезным — буду рад видеть вас на уроке.

Полный список бесплатных уроков мая смотрите в дайджесте.

Комментарии (0)