В предыдущих статьях мы познакомились с Docker, научились создавать собственные образы, запускать контейнеры и объединять несколько сервисов с помощью Docker Compose. На этом этапе у многих возникает закономерный вопрос:
Зачем тогда нужен Kubernetes?
Ответ прост: Docker решает задачу запуска контейнера, а Kubernetes — задачу управления тысячами контейнеров.
Для небольшого проекта Docker и Docker Compose обычно более чем достаточны. Но когда приложение обслуживает миллионы пользователей, работает сразу на нескольких серверах и должно быть доступно круглосуточно, возникают задачи, которые Docker самостоятельно не решает.
Именно поэтому Kubernetes стал отраслевым стандартом для оркестрации контейнеров.
В этой статье разберёмся:
почему Docker недостаточно;
что такое Kubernetes;
какие задачи он решает;
из каких компонентов состоит кластер;
почему Kubernetes стал стандартом современной инфраструктуры.
Когда Docker перестаёт справляться?
Допустим вы открыли интернет-магазин. В начале его архитектура выглядит довольно просто:
Docker ├── Web ├── API ├── PostgreSQL └── Redis
Все контейнеры работают на одном сервере. Для небольшого проекта этого достаточно. Но со временем пользователей становится больше. Компания запускает мобильное приложение. Добавляются новые регионы. Возрастает нагрузка.
Один сервер уже не справляется.
Добавляется второй.
Потом третий. Через несколько месяцев приложение работает уже на десяти серверах.
Возникают новые препятствия. К примеру:
Если сервер вышел из строя?
Допустим, на одном сервере работают пять контейнеров. Сервер перестал отвечать.
Что делать? Как настроить автоматический запуск контейнеров на другом сервере?
Как масштабировать приложение?
Во время распродажи количество пользователей выросло в десять раз. Понадобилось увеличить число экземпляров веб-приложения. В Docker это придётся делать вручную.
В Kubernetes достаточно изменить количество реплик.
Как обновить приложение без простоя?
Предположим, необходимо обновить сервис. Если просто остановить контейнер и запустить новый, пользователи увидят ошибку. Нужно выполнять обновление постепенно:
запустить новую версию;
убедиться, что она работает;
перенаправить трафик;
удалить старую версию.
Такое обновление называется Rolling Update. Kubernetes выполняет его автоматически.
Как распределить нагрузку?
Если работает десять одинаковых контейнеров, кто определяет, какой из них обработает следующий запрос? Нужен балансировщик нагрузки.
Kubernetes делает это автоматически.
Как восстановить приложение после сбоя?
Теоретическая ситуация, контейнер неожиданно завершился. Kubernetes обнаружит это и автоматически создаст новый контейнер.
Этот механизм называется самовосстановлением (Self-healing).
Что такое Kubernetes?
Kubernetes (K8s) — это платформа для автоматического управления контейнерами. Само название часто сокращают до K8s: между буквами K и s находится восемь символов.
Kubernetes отвечает за:
запуск контейнеров;
масштабирование приложений;
распределение нагрузки;
обновления без простоя;
автоматическое восстановление после сбоев;
управление сетями и хранилищами;
работу приложений сразу на нескольких серверах.
Что такое оркестрация контейнеров?
Термин оркестрация звучит непривычно. Название термина произошло из музыки и сравнивает управление программами с работой дирижера оркестра. Представьте дирижёра симфонического оркестра. Именно дирижёр следит за тем, чтобы все начали одновременно, играли в одном темпе и вовремя завершили произведение.
Контейнеры похожи на музыкантов. Каждый из них умеет выполнять свою задачу. Kubernetes координирует их работу:
запускает;
останавливает;
заменяет;
масштабирует;
соединяет между собой.
Поэтому Kubernetes называют системой оркестрации контейнеров.
Docker и Kubernetes — конкуренты?
Один из самых распространённых мифов:
Kubernetes заменяет Docker.
На самом деле это не так.
Docker создаёт контейнеры.
Kubernetes управляет ими.
Исторически Kubernetes напрямую работал с Docker Engine, а сегодня использует стандарт Container Runtime Interface (CRI) и может взаимодействовать с различными средами выполнения контейнеров, например containerd или CRI-O.
Для начинающего инженера важно понимать главное:
Docker отвечает за создание контейнера, Kubernetes — за его жизненный цикл в кластере.
Где используется Kubernetes?
Сегодня Kubernetes применяют практически все крупные облачные платформы и технологические компании. Он лежит в основе множества сервисов, где требуется:
высокая доступность;
горизонтальное масштабирование;
автоматическое восстановление;
обновления без остановки сервиса.
Именно поэтому знание Kubernetes всё чаще встречается в вакансиях Junior DevOps.
Когда Kubernetes не нужен?
Новички часто считают Kubernetes обязательным для любого проекта. Это не так.
Для:
личных проектов;
небольших сайтов;
внутренних сервисов;
учебных приложений;
обычно достаточно Docker Compose. Использование Kubernetes в таких случаях лишь усложняет инфраструктуру. Хороший DevOps-инженер выбирает инструмент под задачу, а не использует самую сложную технологию только потому, что ее используют крупные компании.
Теперь пора разобраться, как устроен Kubernetes внутри.
На первый взгляд архитектура Kubernetes кажется сложной: появляются десятки новых терминов — Cluster, Node, Pod, Deployment, ReplicaSet, Control Plane. Однако если понять, какую задачу решает каждый компонент, общая картина становится гораздо понятнее.
Что такое Cluster?
Cluster (кластер) — это группа серверов, объединённых в единую систему и управляемых Kubernetes. Вместо того чтобы работать с каждым сервером отдельно, инженер взаимодействует с кластером как с одним логическим объектом.
Например, вместо пяти отдельных серверов:
Server(Node) 1 Server(Node) 2 Server(Node) 3 Server(Node) 4 Server(Node) 5
Kubernetes видит их их как:
Kubernetes Cluster │ ├── Server(Node)1 ├── Server(Node) 2 ├── Server(Node) 3 ├── Server(Node) 4 └── Server(Node) 5
Кластер самостоятельно распределяет нагрузку, следит за состоянием приложений и автоматически восстанавливает их при сбоях. Именно кластер является основной единицей работы в Kubernetes.
Из чего состоит кластер?
Любой Kubernetes-кластер включает две большие части:
Kubernetes Cluster │ ├── Control Plane │ └── Worker Nodes
У каждой из них своя роль.
Control Plane — «мозг» Kubernetes
Control Plane — это набор компонентов, которые принимают решения и управляют всем кластером. Control Plane отвечает за:
планирование размещения приложений;
контроль состояния кластера;
масштабирование;
обработку запросов пользователя;
хранение конфигурации.
В большинстве случаев начинающий DevOps напрямую работает с кластером через Control Plane, даже если этого не замечает.
Worker Node
Worker Node — это сервер, на котором фактически запускаются приложения.
Каждый Worker Node содержит:
среду выполнения контейнеров (например, containerd);
компонент
kubelet, который получает команды от Control Plane;сетевой компонент
kube-proxy, обеспечивающий работу сервисов.
Что такое Pod?
Часто думают, что Kubernetes управляет контейнерами. На самом деле основной объект Kubernetes — Pod.
Pod — это минимальная единица развёртывания в Kubernetes. В большинстве случаев Pod содержит один контейнер.
Например:
Pod │ └── Nginx Container
Однако иногда внутри одного Pod могут работать несколько тесно связанных контейнеров. Например:
Pod │ ├── Application └── Log Collector
Все контейнеры внутри Pod:
используют один IP-адрес;
разделяют сетевое пространство;
могут совместно использовать тома (Volumes).
Почему нельзя запускать контейнер напрямую?
Это один из самых популярных вопросов новичков. Docker может запускать отдельные контейнеры.
Но Kubernetes должен решать более сложные задачи:
автоматически заменять контейнеры;
масштабировать приложение;
переносить его между серверами;
объединять несколько контейнеров.
Для этого появилась дополнительная абстракция — Pod. Контейнер становится частью Pod, а уже Pod управляется Kubernetes.
ReplicaSet — поддержание нужного количества Pod
Предположим, что веб-приложение должно работать сразу в трёх экземплярах. Получается:
Pod Pod Pod
Если один Pod неожиданно завершится, количество экземпляров уменьшится. ReplicaSet постоянно сравнивает:
сколько Pod должно быть;
сколько работает сейчас.
Если один Pod исчезнет:
Было: Pod Pod Pod ↓ Один завершился ↓ Стало: Pod Pod
ReplicaSet автоматически создаст новый:
Pod Pod Pod
Поэтому Kubernetes обладает механизмом Self-healing — самовосстановления.
Deployment
Хотя ReplicaSet умеет поддерживать нужное количество Pod, напрямую его почти никогда не используют. Вместо этого применяется Deployment.
Deployment — это объект более высокого уровня, который управляет ReplicaSet. Именно Deployment отвечает за:
создание ReplicaSet;
обновление приложения;
откат к предыдущей версии;
изменение количества реплик.
На практике DevOps-инженеры чаще работают именно с Deployment.
Scheduler
Когда вы создаёте Deployment или Pod, Kubernetes не запускает контейнер сразу на первом попавшемся сервере. Сначала в работу вступает kube-scheduler — компонент Control Plane, который отвечает за выбор наиболее подходящего Worker Node.
Именно Scheduler принимает решение:
На каком сервере должен быть запущен новый Pod?
Сам Pod не знает, где ему работать, а Deployment лишь сообщает Kubernetes желаемое состояние — например, что должно быть запущено три экземпляра приложения. Затем Scheduler анализирует состояние всего кластера и выбирает наиболее подходящий узел.
По каким критериям Scheduler выбирает Worker Node?
При выборе узла Scheduler учитывает множество факторов.
Доступные ресурсы
Узел должен иметь достаточно свободных ресурсов для запуска нового Pod:
процессор (CPU);
оперативная память (RAM);
при необходимости — GPU или другие специальные ресурсы.
Если ресурсов недостаточно, Scheduler выберет другой узел.
Ограничения и требования Pod
Разработчик может указать, что приложение должно запускаться только на определённых узлах. Например:
только на серверах с SSD;
только на серверах с GPU;
только в определённой зоне доступности.
Распределение нагрузки
Scheduler старается не размещать все Pod на одном сервере. Если в кластере несколько свободных Worker Node, он распределяет нагрузку между ними, чтобы избежать перегрузки отдельных узлов и повысить отказоустойчивость.
Как всё связано между собой?
Рассмотрим цепочку объектов.
Deployment ▼ ReplicaSet ▼ Pod ▼ Container
Каждый уровень отвечает за свою задачу.
Deployment описывает желаемое состояние приложения.
ReplicaSet поддерживает нужное количество Pod.
Pod является минимальной единицей развёртывания.
Container выполняет само приложение.
Такая архитектура позволяет Kubernetes автоматически поддерживать инфраструктуру в нужном состоянии.
Что происходит при развёртывании приложения?
Предположим, инженер применяет конфигурацию:
kubectl apply -f deployment.yaml
Далее Kubernetes выполняет несколько шагов.
Control Plane получает описание приложения.
Создаётся Deployment.
Deployment создаёт ReplicaSet.
ReplicaSet определяет необходимое количество Pod.
Scheduler выбирает подходящий Worker Node.
kubeletполучает команду создать Pod.Среда выполнения контейнеров загружает образ.
Контейнер запускается.
В результате приложение начинает работать.
Что произойдёт при сбое?
Представим, один Worker Node отключился.
Если Pod находился только на этом сервере, Kubernetes обнаружит, что нужное количество реплик больше не обеспечивается. ReplicaSet сообщит об этом Deployment. После этого Scheduler выберет другой доступный Worker Node. На новом сервере автоматически создастся новый Pod. Для пользователя приложение продолжит работать практически незаметно.
Именно это делает Kubernetes удобным инструментом для высоко нагруженных систем.
Мы выяснили, что в Pod работают контейнеры с нашим приложением. Однако возникает новая проблема.
Представим, что вы развернули веб-приложение в Kubernetes. Оно успешно запустилось, пользователи готовы начать работу, но подключиться к нему невозможно. Почему? Ответ кроется в особенностях работы Pod.
Почему одного Pod недостаточно?
Напомним, что Pod — минимальная единица развёртывания в Kubernetes. Обычно внутри одного Pod находится один контейнер с приложением. Например:
Pod │ └── Nginx
После запуска Pod получает собственный IP-адрес. На первый взгляд кажется, что этого достаточно: можно обращаться к приложению по этому адресу. Но в Kubernetes всё устроено иначе.
Проблема №1. Pod может исчезнуть в любой момент
Главная особенность Kubernetes заключается в том, что Pod считается временным (ephemeral) объектом. Если контейнер завершится с ошибкой, сервер выйдет из строя или Deployment выполнит обновление приложения, Kubernetes удалит старый Pod и создаст новый.
Например:
Было Pod IP: 10.244.0.15 ↓ Pod завершился ↓ Создан новый Pod IP: 10.244.0.28
IP-адрес изменился. Если другие приложения использовали старый IP, связь будет потеряна. Поэтому обращаться к Pod напрямую практически никогда не рекомендуется.
Проблема №2. Масштабирование
Представим, что приложение нужно запустить сразу в трёх экземплярах. Теперь возникает новый вопрос. Как пользователь поймёт, к какому Pod подключаться?
Необходим объект, который будет предоставлять единый адрес и автоматически распределять запросы между всеми работающими Pod. Как раз эту задачу решает Service.
Что такое Service?
Service — это объект Kubernetes, который предоставляет стабильную точку доступа к одному или нескольким Pod. Можно представить Service как виртуальный адрес, который остаётся неизменным, даже если сами Pod постоянно создаются и удаляются.
Как Service находит нужные Pod?
Возникает логичный вопрос: если Pod постоянно создаются заново, откуда Service знает, куда отправлять трафик?
Для этого используются Labels и Selectors.
Каждый Pod может иметь набор меток. Например:
labels: app: nginx
Service содержит селектор:
selector: app: nginx
Kubernetes автоматически связывает Service со всеми Pod, у которых есть подходящая метка. Если Deployment создаст новый Pod с той же меткой, он сразу станет частью Service без дополнительной настройки. Labels являются одним из самых важных механизмов Kubernetes.
Балансировка нагрузки
Допустим, Deployment поддерживает три реплики приложения.
Когда приходит новый запрос, Service распределяет его между доступными Pod.
Например:
Запрос 1 → Pod1 Запрос 2 → Pod2 Запрос 3 → Pod3 Запрос 4 → Pod1
Таким образом достигается простейшая балансировка нагрузки.
Если один Pod завершится, Service автоматически исключит его из списка доступных и продолжит направлять запросы к оставшимся экземплярам. Для клиента этот процесс обычно остаётся незаметным.
Типы Service
Kubernetes поддерживает несколько типов Service. На практике чаще всего используются три:
ClusterIP;
NodePort;
LoadBalancer.
Каждый решает свою задачу.
ClusterIP
ClusterIP — тип Service, который создаётся по умолчанию. Он предоставляет постоянный IP-адрес, доступный только внутри Kubernetes-кластера.
Пользователь из Интернета обратиться к такому Service не сможет. Зато любые приложения внутри кластера могут использовать его имя или внутренний IP-адрес.
ClusterIP идеально подходит для внутренних сервисов:
PostgreSQL;
Redis;
RabbitMQ;
внутренние API;
микросервисы.
Например, веб-приложение может обращаться к базе данных просто по имени сервиса:
postgres
Не нужно знать IP-адрес конкретного Pod базы данных — Service сам направит запрос. Из-за этого ClusterIP является наиболее распространённым типом Service.
NodePort
Иногда приложение должно быть доступно извне, но полноценный балансировщик нагрузки ещё не используется. В этом случае применяется NodePort.
Kubernetes открывает определённый порт на каждом Worker Node.Схема выглядит так:
Пользователь ▼ Node:30080 ▼ Service ▼ Pods
Теперь приложение можно открыть по адресу:
http://IP\_узла:30080
NodePort часто используют:
в домашних лабораториях;
при изучении Kubernetes;
в Minikube;
в небольших тестовых окружениях.
Для производственных систем этот способ применяется значительно реже.
LoadBalancer
В облачных платформах используется тип LoadBalancer. После создания такого Service Kubernetes обращается к облачному провайдеру (например, AWS, Azure или Google Cloud) и автоматически создаёт внешний балансировщик нагрузки.
Схема становится следующей:
Интернет ▼ Load Balancer ▼ Service ┌────┼────┐ Pod1 Pod2 Pod3
Пользователь взаимодействует только с одним публичным адресом. Балансировщик самостоятельно распределяет запросы между всеми репликами приложения.
Этот тип Service чаще всего используется в облачных Kubernetes-кластерах.
Какой тип Service выбрать?
Выбор зависит от задачи.
Тип |
Когда используется |
|---|---|
ClusterIP |
Внутреннее взаимодействие сервисов внутри кластера. |
NodePort |
Тестирование, обучение, небольшие лаборатории. |
LoadBalancer |
Публикация приложения в Интернете через облачного провайдера. |
На практике большинство внутренних сервисов используют ClusterIP, а внешние веб-приложения публикуются через Ingress, который работает поверх Service. Поэтому с объектом LoadBalancer разработчики сталкиваются реже, чем может показаться на первый взгляд.
Теперь познакомившись с объектом Service и выяснив, что он предоставляет приложениям постоянный адрес внутри Kubernetes-кластера, распределяет запросы между Pod и скрывает от пользователей изменения их IP-адресов, можно перейти к Ingress
Представим, что в кластере работают сразу несколько веб-приложений:
интернет-магазин;
корпоративный портал;
блог;
API.
Для каждого можно создать отдельный Service типа LoadBalancer.Получится примерно такая схема:
Интернет ├── LoadBalancer → Shop Service ├── LoadBalancer → Blog Service ├── LoadBalancer → API Service └── LoadBalancer → Portal Service
Такой подход работает, но имеет серьёзные недостатки:
каждому приложению нужен собственный внешний IP-адрес;
в облаке за каждый балансировщик нагрузки обычно взимается отдельная плата;
становится сложнее управлять сертификатами HTTPS;
правила маршрутизации оказываются распределены между несколькими балансировщиками.
Для небольшого проекта это может быть приемлемо, но в крупных Kubernetes-кластерах такой подход быстро становится неудобным. Нужен единый компонент, который будет принимать весь входящий HTTP(S)-трафик и самостоятельно определять, какому приложению его передать.
Именно для этого существует Ingress.
Что такое Ingress?
Ingress — это объект Kubernetes, который описывает правила маршрутизации HTTP- и HTTPS-запросов к сервисам внутри кластера. Если Service отвечает на вопрос:
Как попасть к Pod?
то Ingress отвечает:
Как определить, к какому Service направить запрос?
Например, можно настроить следующие правила:
shop.example.com → Shop Service blog.example.com → Blog Service api.example.com → API Service
или использовать маршрутизацию по URL:
example.com/shop → Shop Service example.com/blog → Blog Service example.com/api → API Service
Пользователь видит один домен или один внешний IP-адрес, а Ingress автоматически перенаправляет запросы нужному сервису.
Что такое Ingress Controller?
Важно понимать одно из самых распространённых заблуждений новичков. Сам объект Ingress не принимает сетевые соединения и не умеет самостоятельно перенаправлять трафик.
Ingress — это только набор правил. За их выполнение отвечает специальное приложение — Ingress Controller. Именно он:
принимает входящие HTTP- и HTTPS-запросы;
анализирует правила Ingress;
определяет нужный Service;
пересылает запрос приложению.
Без установленного Ingress Controller, объект Ingress работать не будет.
Наиболее популярные реализации:
NGINX Ingress Controller — самый распространённый вариант;
Traefik — простой в настройке и популярный в небольших проектах;
HAProxy Ingress;
Kong Ingress Controller — часто используется как API Gateway.
Схематично взаимодействие выглядит следующим образом:
Интернет ▼ Ingress Controller ▼ Ingress ┌────┼─────────┐ ▼ ▼ ▼ Shop Blog API Service Service Service ▼ Pods
Практический пример маршрутизации по доменам
Предположим, в кластере работают два приложения:
интернет-магазин;
блог.
Пользователь открывает браузер и вводит адрес:
https://shop.example.com
Ingress Controller получает HTTP-запрос, сверяет его с правилами Ingress и направляет запрос в Shop Service, который затем распределяет его между Pod интернет-магазина. Если пользователь переходит по адресу:
https://blog.example.com
тот же Ingress Controller направляет запрос уже в Blog Service. При этом оба приложения могут использовать один внешний IP-адрес и один Ingress Controller. Пример простого правила Ingress:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress spec: rules: - host: shop.example.com http: paths: - path: / pathType: Prefix backend: service: name: shop-service port: number: 80 - host: blog.example.com http: paths: - path: / pathType: Prefix backend: service: name: blog-service port: number: 80
На практике подобные конфигурации могут содержать десятки или даже сотни правил маршрутизации. Кроме того, Ingress позволяет подключать HTTPS-сертификаты, выполнять перенаправление с HTTP на HTTPS, ограничивать доступ по IP-адресам и настраивать множество других параметров.
Типичные ошибки новичков
Забывать про Ingress Controller
Создать объект Ingress недостаточно. Если в кластере не установлен Ingress Controller, маршрутизация работать не будет.
Создавать отдельный LoadBalancer для каждого приложения
Новички нередко публикуют каждый Service через собственный LoadBalancer. Такой подход быстро увеличивает стоимость инфраструктуры и усложняет сопровождение. Во многих случаях достаточно одного Ingress Controller и одного внешнего балансировщика нагрузки.
Не использовать HTTPS
Даже для тестовых проектов полезно сразу привыкать публиковать приложения по HTTPS.
Во многих Kubernetes-кластерах сертификаты автоматически выпускаются и обновляются с помощью cert-manager и Let's Encrypt, поэтому поддержка HTTPS практически не требует ручного вмешательства.
Ресурсы для изучения
Официальная документация Kubernetes
Самый полный источник информации по Service, Ingress и другим объектам Kubernetes.
Kubernetes Basics
Небольшой официальный интерактивный курс, который помогает быстро познакомиться с основными объектами Kubernetes.
Ingress NGINX
Документация самого популярного Ingress Controller.
LabEx
Много практических задач по Kubernetes, с готовыми облачными окружениями. Также есть материал для подготовки к сертификациям Certified Kubernetes Administrator (CKA), Certified Kubernetes Application Developer (CKAD), Certified Kubernetes Security Specialist (CKS).
Killercoda Kubernetes Scenarios
Бесплатная платформа с интерактивными лабораторными работами. Позволяет выполнять практические задания по Kubernetes прямо в браузере без установки собственного кластера.
Заключение
Service решил первую важную задачу Kubernetes — предоставил приложениям постоянную точку доступа внутри кластера и научился распределять нагрузку между Pod. Ingress сделал следующий шаг: позволил публиковать сразу несколько веб-приложений через один внешний адрес, управлять маршрутизацией запросов и централизованно работать с HTTPS.
Однако для полноценной работы приложения этого всё ещё недостаточно. Любому сервису необходимы настройки: адрес базы данных, режим работы, номера портов, а также конфиденциальные данные — пароли, токены и API-ключи. Хранить их внутри Docker-образов или YAML-манифестов неудобно и небезопасно.
В следующей статье мы познакомимся с ConfigMap, Secret, Volumes, PersistentVolume и PersistentVolumeClaim, чтобы понять, как Kubernetes управляет конфигурацией приложений и обеспечивает постоянное хранение данных.
MPfromLINUX