Kubernetes за 20 минут — быстрый старт
Денис Сучков
Что такое Kubernetes и зачем он нужен
Kubernetes — это система для автоматического управления контейнерами. Она решает вопросы запуска, масштабирования, обновления и восстановления контейнерных приложений.
Пока у нас один контейнер и стабильная нагрузка — хватает обычного docker run. Но когда серверов становится 10, а контейнеров 50 — появляются вопросы: кто следит за тем что все контейнеры работают? Кто перезапустит их при падении сервера? Как обновить приложение без простоя?
Kubernetes берёт это на себя. Мы говорим: «хочу 3 копии моего приложения, всегда работающих» — и Kubernetes гарантирует что так и будет. Упал контейнер — поднимет новый. Выросла нагрузка — добавит ещё копий. Нужно обновить версию — обновит по одному, без простоя.
Docker упаковывает приложения в контейнеры, а Kubernetes управляет этими контейнерами.
Ключевые компоненты
| Компонент | Что делает | Аналогия |
|---|---|---|
| Cluster | Вся инфраструктура целиком | Сеть ресторанов |
| Node | Отдельный сервер (физический или виртуальный) со своими CPU и RAM | Ресторан |
| Pod | Минимальная единица запуска, обычно один контейнер | Повар |
| Deployment | Декларативное описание желаемого состояния: «всегда 3 реплики» | Приказ «5 поваров на бургеры» |
| Service | Стабильная точка доступа к подам, балансировка нагрузки | Внутренний телефон кухни |
| Control Plane | Мозг кластера — сверяет текущее состояние с желаемым | Управляющий сетью |
| kubectl | CLI для отправки команд кластеру | Телефон управляющего |
Установка
Для локальной разработки используем minikube — он запускает кластер Kubernetes из одного узла прямо на компьютере.
# Mac
brew install minikube
# Запуск кластера
minikube start
# Проверка
kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 34s v1.35.1
Один узел со статусом Ready — кластер готов к работе.
Pods — базовая единица
Pod — обёртка вокруг контейнера. Создадим Pod с nginx:
kubectl run my-nginx --image=nginx
kubectl get pods
NAME READY STATUS RESTARTS AGE
my-nginx 1/1 Running 0 21s
Но создавать поды напрямую — плохая практика. Если Pod упадёт — никто его не перезапустит.
kubectl delete pod my-nginx
Deployments — правильный подход
Deployment гарантирует что указанное количество подов всегда будет работать.
kubectl create deployment nginx-app --image=nginx --replicas=3
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-app-574b8c4d9c-27wgg 1/1 Running 0 13s
nginx-app-574b8c4d9c-c59pv 1/1 Running 0 13s
nginx-app-574b8c4d9c-lm4fp 1/1 Running 0 13s
Удалим один Pod и посмотрим что произойдёт:
kubectl delete pod nginx-app-574b8c4d9c-27wgg
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-app-574b8c4d9c-c59pv 1/1 Running 0 27s
nginx-app-574b8c4d9c-gt46h 1/1 Running 0 5s
nginx-app-574b8c4d9c-lm4fp 1/1 Running 0 48s
По-прежнему 3 пода — Kubernetes мгновенно создал новый (gt46h) вместо удалённого.
Services — доступ к подам
Поды живут внутри кластера и снаружи недоступны. Service даёт стабильный адрес для доступа:
kubectl expose deployment nginx-app --port=80 --target-port=80 --type=NodePort
minikube service nginx-app --url
http://192.168.49.2:31234
Мы обращаемся на один адрес, а Kubernetes сам решает какой из подов обработает запрос.
# Очистка
kubectl delete service nginx-app
kubectl delete deployment nginx-app
YAML-конфигурации
В реальности всё описывают в YAML-файлах вместо набора команд. Файл можно хранить в git, ревьюить, откатывать.
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
replicas: 3
selector:
matchLabels:
app: nginx-app
template:
metadata:
labels:
app: nginx-app
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-app
spec:
type: NodePort
selector:
app: nginx-app
ports:
- port: 80
targetPort: 80
Применяем одной командой:
kubectl apply -f deployment.yaml -f service.yaml
Автоскейлинг — HorizontalPodAutoscaler
HPA автоматически увеличивает и уменьшает количество подов в зависимости от нагрузки.
hpa.yaml:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: demo-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-app
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- scaleTargetRef — за каким Deployment следить
- minReplicas / maxReplicas — границы масштабирования (от 1 до 10 подов)
- averageUtilization: 50 — если средняя загрузка CPU выше 50%, добавить поды; ниже — убрать лишние
Демонстрация
Сервис на Go с ограниченными ресурсами (0.2 CPU, 128Mi RAM). При 40 параллельных запросах один контейнер захлёбывается — ошибки 503 и таймауты.
С Kubernetes + HPA тот же сервис при той же нагрузке:
- Один Pod перегружается
- HPA видит CPU > 50% и поднимает новые поды
- Через несколько секунд все запросы обрабатываются без ошибок
- После снятия нагрузки Kubernetes убирает лишние поды обратно до одного
Шпаргалка по командам
# Кластер
minikube start # запустить локальный кластер
minikube stop # остановить кластер
kubectl get nodes # список узлов
# Развёртывание
kubectl create deployment NAME --image=IMAGE # создать deployment
kubectl get deployments # список deployments
kubectl get pods # список подов
kubectl apply -f file.yaml # применить конфигурацию
# Доступ
kubectl expose deployment NAME --port=PORT --type=NodePort # создать сервис
kubectl get services # список сервисов
minikube service --url NAME # URL сервиса
# Масштабирование
kubectl scale --replicas=N deployment/NAME # ручное
kubectl get hpa # статус автоскейлера
# Обновления
kubectl set image deployment/NAME CONTAINER=IMAGE:TAG # rolling update
kubectl rollout status deployment/NAME # статус обновления
kubectl rollout undo deployment/NAME # откат
# Утилиты
minikube addons enable metrics-server # включить метрики
kubectl logs POD_NAME # логи пода
kubectl exec POD_NAME -- COMMAND # выполнить команду в поде
kubectl delete deployment NAME # удалить deployment
Хотите глубже в архитектуру и масштабирование? В курсе System Design разбираем балансировку, шардирование и отказоустойчивость.