suchkov.tech

Kubernetes за 20 минут — быстрый старт

Денис Сучков

Что такое Kubernetes и зачем он нужен

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

Пока у нас один контейнер и стабильная нагрузка — хватает обычного docker run. Но когда серверов становится 10, а контейнеров 50 — появляются вопросы: кто следит за тем что все контейнеры работают? Кто перезапустит их при падении сервера? Как обновить приложение без простоя?

Kubernetes берёт это на себя. Мы говорим: «хочу 3 копии моего приложения, всегда работающих» — и Kubernetes гарантирует что так и будет. Упал контейнер — поднимет новый. Выросла нагрузка — добавит ещё копий. Нужно обновить версию — обновит по одному, без простоя.

Docker упаковывает приложения в контейнеры, а Kubernetes управляет этими контейнерами.

Ключевые компоненты

КомпонентЧто делаетАналогия
ClusterВся инфраструктура целикомСеть ресторанов
NodeОтдельный сервер (физический или виртуальный) со своими CPU и RAMРесторан
PodМинимальная единица запуска, обычно один контейнерПовар
DeploymentДекларативное описание желаемого состояния: «всегда 3 реплики»Приказ «5 поваров на бургеры»
ServiceСтабильная точка доступа к подам, балансировка нагрузкиВнутренний телефон кухни
Control PlaneМозг кластера — сверяет текущее состояние с желаемымУправляющий сетью
kubectlCLI для отправки команд кластеруТелефон управляющего

Установка

Для локальной разработки используем 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 тот же сервис при той же нагрузке:

  1. Один Pod перегружается
  2. HPA видит CPU > 50% и поднимает новые поды
  3. Через несколько секунд все запросы обрабатываются без ошибок
  4. После снятия нагрузки 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 разбираем балансировку, шардирование и отказоустойчивость.