Kubernetes: что это, как устроен кластер и как запустить первое приложение

Kubernetes (K8s) - это открытая платформа для оркестрации контейнеров: вы описываете желаемое состояние приложения, а контроллеры кластера постоянно сравнивают его с фактическим и сами исправляют расхождения. Контроллеры поддерживают заданное число экземпляров, заменяют упавшие и выкатывают новую версию без остановки сервиса. Откат на прошлую версию запускает человек одной командой, а автоматическое масштабирование под нагрузку настраивают отдельно.
В конце статьи вы запустите первое приложение в локальном кластере и своими руками проверите, как Kubernetes восстанавливает экземпляры и откатывает версию. Если захочется повторить эти шаги вместе с преподавателем и задать вопросы по ходу, посмотрите расписание бесплатных открытых уроков Otus по DevOps и выберите подходящую тему.
Содержание:
- Что такое Kubernetes и какие задачи он решает
- Как устроен кластер: control plane и рабочие узлы
- etcd и кворум: почему узлов управления три, а не два
- Объекты Kubernetes: Pod, ReplicaSet, Deployment, Service
- Как трафик попадает в приложение: Ingress и Gateway API
- Практика: первое приложение в Minikube
- Выводы
Что такое Kubernetes и какие задачи он решает
Представьте сервис, который работает в двух экземплярах. Один упал - процесс завершился с ошибкой, а заодно нужно выкатить новую версию, не останавливая сервис. Без оркестратора человек заходит на сервер, перезапускает упавший экземпляр и по очереди меняет версии вручную. Зависший процесс, который не завершился, а просто перестал отвечать, Kubernetes сам не распознает - для этого в манифест добавляют проверки живости (liveness probe), о них - в конце практики. Kubernetes берет такие действия на себя:
- развертывание - запустить нужное число экземпляров приложения без ручного входа на сервер;
- самовосстановление - заметить упавший экземпляр и поднять замену;
- обновление - выкатить новую версию без простоя и по команде вернуть предыдущую;
- масштабирование - изменить число экземпляров командой, а при настройке автомасштабирования - по нагрузке;
- балансировка и связь сервисов - дать сервисам находить друг друга и распределять запросы между экземплярами;
- конфигурация и хранилища - передать настройки снаружи без пересборки образа и подключить постоянные тома.
Что из этого работать будет само, а что нужно настроить, зависит от манифестов: число экземпляров и стратегию обновления вы задаете, проверки работоспособности и автомасштабирование описываете отдельно.
Проект начат в Google в 2014 году, сейчас его развивает сообщество в CNCF.
Kubernetes - не готовая платформа (не PaaS), а конструктор. Из коробки в нем нет сборки и доставки кода (CI/CD), сбора логов, баз данных и очередей: их подключают отдельно, и это стоит учесть, когда оцениваете, сколько работы займет переезд.
Как устроен кластер: control plane и рабочие узлы
Кластер Kubernetes делится на две части. Control plane (управляющая плоскость, раньше говорили «мастер») принимает решения: где запустить Pod, сколько экземпляров должно работать, что изменилось. Рабочие узлы (worker nodes) - физические или виртуальные машины, на которых работают контейнеры приложения.
Pod - группа из одного или нескольких контейнеров приложения, которую Kubernetes запускает как одно целое (подробнее - в разделе про объекты). Описание того, сколько Pod нужно и из какого образа, хранится в кластере. Рабочий узел сам ничего не решает: он запускает Pod, которые назначил ему control plane. На примере одного сервиса: планировщик в control plane выбирает узел, а kubelet на этом узле запускает контейнеры.
Компоненты и их роли:
| Компонент | Где работает | Что делает |
|---|---|---|
| kube-apiserver | control plane | Единая точка входа: принимает запросы, проверяет права и объект, сохраняет его в etcd |
| etcd | control plane или отдельные машины | Согласованное хранилище «ключ - значение» для всех данных кластера |
| kube-scheduler | control plane | Находит Pod без узла и выбирает подходящий узел. Сам Pod не запускает |
| kube-controller-manager | control plane | Запускает контроллеры, которые приводят фактическое состояние к желаемому |
| cloud-controller-manager | control plane, необязателен | Связывает кластер с облаком: балансировщики, диски |
| kubelet | каждый узел | Следит, чтобы Pod, назначенные узлу, работали, и сообщает их статус |
| kube-proxy | каждый узел, необязателен | Поддерживает сетевые правила, через которые работают Service |
| Среда запуска контейнеров | каждый узел | Запускает контейнеры: containerd, CRI-O и другие совместимые с CRI |
Компоненты работают с состоянием кластера через API-сервер: планировщик и контроллеры не вызывают друг друга, а читают и меняют объекты через него. Сам API-сервер пишет в etcd, kubelet передает команды среде запуска контейнеров, а сетевой трафик приложений идет своим путем, не через API. Вот что происходит после команды «запусти три экземпляра приложения»:
- kubectl отправляет манифест Deployment в API-сервер, тот записывает его в etcd.
- Контроллер Deployment создает ReplicaSet, контроллер ReplicaSet - три объекта Pod.
- Планировщик назначает каждому Pod узел, где хватает ресурсов.
- kubelet на этом узле через среду запуска стартует контейнеры.
- Если упал контейнер, kubelet перезапускает его внутри того же Pod. Если Pod удалили или отказал весь узел, Pod становится меньше трех, и контроллер ReplicaSet создает замену.
Docker на узле больше не обязателен: Kubernetes работает со средой запуска через интерфейс CRI, а встроенную прослойку для Docker Engine удалили в версии 1.24. Образы, собранные через
etcd и кворум: почему узлов управления три, а не два
etcd - отдельный open-source проект, распределенное хранилище. Запись в нем подтверждает большинство узлов (кворум), поэтому данные согласованы даже при отказе части машин. Без кворума etcd не принимает изменений, и кластер не может менять состояние: например, новые Pod не назначаются на узлы.
Почему не два узла, видно из таблицы отказоустойчивости etcd:
| Узлов etcd | Нужно для кворума | Сколько можно потерять |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
Второй узел не добавляет устойчивости: кворум из двух требует обоих, и отказ любого останавливает запись. Поэтому etcd собирают из нечетного числа узлов: три переживают отказ одного, пять - двух. Документация Kubernetes для продакшена рекомендует кластер etcd из пяти узлов и регулярные резервные копии. Если etcd работает на самих узлах control plane (частая схема), это и есть число узлов управления. У некоторых облегченных дистрибутивов Kubernetes хранилище может быть другим, но в стандартной сборке это etcd.
Объекты Kubernetes: Pod, ReplicaSet, Deployment, Service
Приложение в Kubernetes описывают объектами в YAML-манифестах. Связывают объекты метки (labels) - пары «ключ - значение» - и селекторы, которые выбирают объекты по меткам. В примере из практики ниже это выглядит так: на каждом Pod стоит метка
Основные объекты, с которых начинают:
| Объект | Что делает |
|---|---|
| Pod | Минимальная единица запуска: один или несколько контейнеров с общей сетью и томами. Обычно его создает контроллер, а не человек |
| ReplicaSet | Поддерживает заданное число одинаковых Pod |
| Deployment | Описывает желаемое состояние (образ, число реплик, стратегию обновления) и управляет ReplicaSet. Основной объект для приложений без состояния |
| Service | Дает группе Pod постоянное имя и адрес и распределяет запросы между ними |
| ConfigMap, Secret | Хранят настройки и чувствительные данные отдельно от образа |
Получается матрешка: Deployment управляет ReplicaSet, ReplicaSet - Pod. При обновлении образа Deployment создает новый ReplicaSet и постепенно переносит на него Pod, а старый оставляет для отката. В старых материалах можно встретить объект Replication Controller - это предшественник ReplicaSet; сейчас приложения описывают через Deployment, потому что он умеет обновлять и откатывать версии.
Pod при каждом пересоздании получает новый IP-адрес, поэтому обращаются не к нему, а к Service. Тип Service по умолчанию - ClusterIP: адрес доступен только внутри кластера, другим сервисам. В практике ниже нужен доступ к приложению с вашего компьютера, поэтому там выбран NodePort: он дополнительно открывает порт на узле кластера, а команда
Чувствительные данные в Secret тоже стоит понимать правильно. В манифесте и в ответах API поле
Как трафик попадает в приложение: Ingress и Gateway API
Адрес ClusterIP доступен только внутри кластера. Запрос пользователя из интернета приходит на домен, например
Такой точкой входа для HTTP долго был Ingress - объект с правилами маршрутизации по домену и пути. Сам по себе он ничего не делает: нужен Ingress-контроллер, который читает правила и принимает трафик. API Ingress заморожен: он стабилен и удалять его не планируют, но развивать не будут, и проект Kubernetes рекомендует вместо него Gateway API. Популярный контроллер ingress-nginx больше не получает исправлений, в том числе исправлений безопасности, поэтому для новой установки выбирают поддерживаемую реализацию Gateway API.
Gateway API делит ответственность по ролям: GatewayClass описывает тип балансировщика, Gateway - точку входа с портами и сертификатами, HTTPRoute - маршруты к Service. Команда платформы владеет точкой входа, разработчики меняют свои маршруты.
Практика: первое приложение в Minikube
Для первого запуска подойдет Minikube - локальный кластер из одного узла, где совмещены control plane и рабочая роль. Что нужно до начала:
- установленные Minikube и kubectl - по официальной инструкции Minikube для вашей ОС;
- запущенный Docker (на macOS и Windows - Docker Desktop): с драйвером docker Minikube работает внутри контейнера.
Шаг 1. Поднять кластер и убедиться, что kubectl смотрит на него.
minikube start --driver=docker kubectl config current-context # ожидаем: minikube kubectl get nodes # один узел minikube в статусе Ready
Проверка контекста - не формальность: если kubectl раньше смотрел на рабочий кластер, команды ниже, включая удаление Pod, ушли бы туда. Если отдельного kubectl нет, подойдет встроенный:
Шаг 2. Описать приложение. Это учебный пример: Deployment из двух реплик тестового эхо-сервера из документации Minikube и Service типа NodePort. Создайте папку для манифестов:
mkdir hello
Скопируйте первый блок ниже в файл
apiVersion: apps/v1 kind: Deployment metadata: name: hello labels: app: hello spec: replicas: 2 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - name: echo image: kicbase/echo-server:1.0 ports: - containerPort: 8080 resources: requests: cpu: 50m memory: 32Mi limits: memory: 128Mi
Второй блок - в файл
apiVersion: v1 kind: Service metadata: name: hello spec: type: NodePort selector: app: hello ports: - port: 8080 targetPort: 8080
Главное в манифестах - метки. Селектор Deployment (
Шаг 3. Проверить и применить.
kubectl apply -f hello/ --dry-run=server # проверка на сервере, без изменений kubectl apply -f hello/ kubectl rollout status deployment/hello kubectl get deployments,replicasets,pods -l app=hello
Последняя команда показывает всю вложенность: один Deployment, один ReplicaSet с суффиксом в имени и два Pod в статусе Running.
Шаг 4. Открыть приложение.
minikube service hello --url
Команда выведет адрес приложения - какой именно, зависит от ОС и драйвера Minikube. Откройте именно его в браузере или выполните
Шаг 5. Посмотреть самовосстановление, масштабирование и откат.
Сначала самовосстановление. Удалите Pod и сразу понаблюдайте за списком:
kubectl delete pod -l app=hello --wait=false # удалить Pod (только в учебном кластере) kubectl get pods -l app=hello -w # наблюдать за списком; выход - Ctrl+C
Удаление идет в фоне, поэтому список сначала покажет старые Pod в статусе Terminating, а затем Error, рядом с новыми в ContainerCreating. Дождитесь, пока появятся два Pod с новыми именами в статусе Running, и остановите наблюдение сочетанием Ctrl+C. Это и есть самовосстановление: Pod удалили, ReplicaSet создал замену. Если процесс в контейнере просто завершится с ошибкой, Pod останется тем же, а контейнер в нем перезапустит kubelet - в колонке RESTARTS вырастет счетчик.
Теперь масштабирование и откат. Увеличьте число реплик, посмотрите переменные окружения в шаблоне Pod, измените шаблон и откатите изменение:
kubectl scale deployment/hello --replicas=3 kubectl set env deployment/hello --list # переменные шаблона: пока пусто kubectl set env deployment/hello GREETING=v2 # изменение шаблона = новая ревизия kubectl rollout status deployment/hello kubectl set env deployment/hello --list # GREETING=v2 kubectl rollout history deployment/hello # ревизии 1 и 2 kubectl rollout undo deployment/hello # вернуть предыдущую ревизию kubectl rollout status deployment/hello kubectl set env deployment/hello --list # снова пусто kubectl get pods -l app=hello # три Pod
Команда
Шаг 6. Посмотреть кластер в веб-интерфейсе (по желанию). Pod и Deployment, которые вы только что запустили, удобно посмотреть в браузере. Для этого подойдет Headlamp, в Minikube он ставится как аддон:
minikube addons enable metrics-server # графики потребления ресурсов minikube addons enable headlamp minikube service headlamp -n headlamp
Последняя команда откроет страницу входа. Headlamp попросит токен - длинную строку, по которой кластер узнает пользователя. Получите его во втором терминале:
kubectl create token headlamp --duration 24h -n headlamp
Скопируйте выведенную строку целиком и вставьте в форму входа. Команда запрашивает временный токен сроком на сутки, фактический срок задает API-сервер. Токен дает права администратора учебного кластера, поэтому никуда его не пересылайте. Об аддоне есть страница Headlamp в документации Minikube, но способ получения токена там старый и с текущей версией аддона не работает - берите команду выше. Старый Kubernetes Dashboard (
Шаг 7. Свое приложение (по желанию). Если у вас уже есть свое приложение с Dockerfile, его можно запустить так же. Соберите образ
Шаг 8. Уборка.
kubectl delete -f hello/ minikube stop minikube delete # удаляет кластер и все его данные
Если не получилось
Типовые симптомы и что проверить:
| Симптом | Вероятная причина | Что сделать |
|---|---|---|
| Docker не запущен | Запустить Docker и повторить | |
| Pod в |
Кластер не может получить образ: опечатка в имени или теге, нет доступа к реестру, нужны учетные данные, нет сети; для своего образа - он не загружен в Minikube | Сначала |
| Pod в |
Не хватает ресурсов узла | |
| Pod в |
Приложение падает при старте |
Чего этому примеру не хватает до продакшена. Для рабочего сервиса подбирают по его задачам проверки готовности и живости (probes), права RBAC, способ хранения секретов и мониторинг. Шаблона «для любого сервиса» здесь нет: liveness-проверка бывает не нужна, если процесс сам завершается при сбое, а плохо настроенная проверка способна сама вызвать каскадные перезапуски; секреты нужны не каждому приложению. Отдельный выбор архитектуры и процесса - как принимать внешний трафик (например, через Gateway API) и как доставлять изменения в кластер (например, через GitOps): решение зависит от команды и инфраструктуры.
Если хотите настроить для своего сервиса доступ снаружи, права и выкладку, разберите это на курсе «Инфраструктурная платформа на основе Kubernetes».
Для учебы есть и другие локальные кластеры, например kind - он удобен для нескольких узлов на одной машине и для CI. В продакшене берут управляемый Kubernetes облака или платформу для своих серверов. Команды kubectl и манифесты из практики работают везде одинаково.
Выводы
- Вы запустили приложение в кластере: Deployment поддерживает заданное число Pod, ReplicaSet заменяет удаленные, Service по меткам находит их и отдает запросы.
- Kubernetes сам держит заданное состояние, но решения остаются за вами: откат запускает человек, а число реплик после отката остается таким, каким его задали.
- Перед продакшеном для своего сервиса подбирают проверки работоспособности, права, хранение секретов и мониторинг по его задачам, а также выбирают, как принимать трафик и доставлять изменения.
Как перейти от учебного кластера к рабочему
Kubernetes берут там, где сервисов много и их обновляют без простоя: продуктовые команды, внутренние платформы для разработчиков, облачные сервисы. Его устройство нужно знать DevOps- и SRE-инженерам, а все чаще и бэкенд-разработчикам.
Если хотите пройти путь от первого деплоя до рабочей платформы - с GitOps, секретами и защитой кластера, - записывайтесь на курс «Инфраструктурная платформа на основе Kubernetes».
Смежные темы: Docker для начинающих: образ, контейнер, Dockerfile и Compose, CI/CD: что это и как устроено развертывание приложения, Observability: что это и чем наблюдаемость отличается от мониторинга, Рекомендуемая литература по Kubernetes.
FAQ
Чем Kubernetes отличается от Docker Compose?
Различие в способе управления. Compose описывает набор сервисов в файле и запускает их на одной машине; с политикой
Когда Kubernetes не нужен? Задайте себе четыре вопроса. Нужно ли обновлять сервис без простоя? Нужно ли автоматически восстанавливать упавшие экземпляры? Есть ли несколько окружений, например тестовое и рабочее, которые должны быть устроены одинаково? Есть ли в команде человек, который будет поддерживать кластер? Если на все ответ «нет», Compose или обычный сервер проще и дешевле в сопровождении.
Почему Kubernetes называют K8s? Это сокращение-нумероним: между первой буквой K и последней s в слове Kubernetes восемь букв. В русскоязычной среде также говорят «кубер».