Деплой и управление приложением в Kubernetes (pod, deployment, service и ingress)

Деплой и управление приложением в Kubernetes (pod, deployment, service и ingress)

В этом материале мы развернём простое веб-приложение на кластере Kubernetes и разберём, как взаимодействуют его ключевые абстракции — pod, deployment, service и ingress. Мы покажем, как эти компоненты обеспечивают контролируемый доступ, отказоустойчивость и масштабируемость приложения, а также как организовать подобное развертывание на VPS.

Как взаимодействуют компоненты Kubernetes

Компоненты Kubernetes работают по модели, построенной на принципе декларативного управления: вы описываете желаемое состояние в YAML-манифестах (например, «должно работать 3 копии пода с образом Nginx»), а система непрерывно стремится привести реальное состояние к этому описанию.

Взаимодействие ключевых объектов, которые мы будем использовать, можно представить в виде слоёв, каждый из которых решает свою конкретную задачу:

  • Pod (под). Объединяет один или несколько контейнеров с общим сетевым пространством (IP-адрес) и ресурсами хранилища. Однако поды в кластере смертны, их IP-адрес меняется при пересоздании, они не самовосстанавливаются и не масштабируются.
  • Deployment (развёртывание). Это следующий уровень абстракции, контроллер, который управляет жизненным циклом подов. Вы описываете ему желаемое состояние: какой образ использовать, сколько реплик пода должно работать постоянно, стратегию обновления (например, rolling-update). Deployment'ы непрерывно следят за состоянием подов через API-сервер. Если под умирает, deployment создаёт новый. Если вы меняете образ в конфигурации, deployment плавно разворачивает новую версию. Именно он обеспечивает отказоустойчивость и возможность легкого обновления приложения.
  • Service (сервис). Так как поды динамичны, нужно обеспечить стабильный сетевой доступ к ним — для этого используется service: он определяет логический набор подов (обычно через селектор меток) и правила доступа к ним. Сервис получает статический IP-адрес и DNS-имя, которые не меняются на протяжении всего его жизненного цикла. Его основная роль — быть постоянным сетевым эндпоинтом и балансировщиком нагрузки для всех подов, в данный момент входящих в этот набор.
  • Ingress (вход). Ingress управляет приходящим извне HTTP/HTTPS-трафиком. Он не является типом сервиса, а действует как маршрутизатор на прикладном уровне модели OSI. Вы определяете правила, например, трафик на домен my-app.test должен перенаправляться на сервис web, эти правила выполняет ingress controller — приложение (например, на основе Nginx или Traefik), работающее в кластере и постоянно следящее за изменениями объектов ingress.

Поток запроса выглядит так:

  1. Внешний пользователь делает запрос по адресу my-app.test.
  2. DNS направляет запрос на IP ingress controller'а.
  3. Ingress controller, проверяя правила всех ingress-ресурсов, определяет, что запрос для my-app.test нужно направить на определённый service, например, web.
  4. Service web, в свою очередь, принимает запрос и, действуя как внутренний балансировщик нагрузки, направляет его на один из здоровых подов, входящих в селектор.

Аренда VPS/VDS — от ₽219/месяц

Почему выбирают VPS от AdminVPS:

✓ Дешевле физического сервера

✓ Более гибкий и мощный, чем обычный хостинг

✓ Бесплатная защита от DDoS и техподдержка 24/7

✓ Масштабируется под любые задачи

Виртуальный сервер VPS/VDS — ваш личный сервер для сайтов, магазинов, ботов и других проектов.

popup12

Создание деплоймента для управления подами

Cоздавать под напрямую — табу в продакшене (единичный под не будет перезапущен при сбое и его невозможно масштабировать). Для этого используется деплоймент, который непрерывно следит за подами, поддерживает их количество и конфигурацию соответствующими описанному состоянию.

Создадим манифест deployment.yaml, который развернёт три реплики Nginx:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.25
        ports:
        - containerPort: 80

Разберём основные параметры:

  • apiVersion: apps/v1 — указывает на версию API Kubernetes для работы с деплойментом;
  • kind: Deployment — определяет тип ресурса;
  • replicas: 3 — количество идентичных копий нашего приложения;
  • selector.matchLabels — метки, по ним деплоймент находит поды, которыми он должен управлять;
  • spec.template — шаблон по которому будут создаваться поды; именно здесь описываются сами контейнеры;
  • image: nginx:1.25 — указывается конкретная версия образа для стабильности; не указывайте образ без тега (например, nginx без 1.25) и не используйте тег latest — это может привести к незапланированному обновлению.
  • containerPort: 80 — порт контейнера.

Применим и проверим результат:

kubectl apply -f deployment.yaml
kubectl get deployment web-app
kubectl get pods -l app=web-app -o wide

Последняя команда покажет, как поды распределены по worker-нодам, демонстрируя работу scheduler'а (компонента, отвечающего за распределение подов по узлам кластера).

Создание service для стабильного доступа

Поды, управляемые деплойментом, могут быть убиты и пересозданы при обновлении или сбое, и их IP изменятся. Для предоставления стабильной точки доступа к динамически меняющимся подам используется service. Он предоставляет постоянный виртуальный IP и DNS-имя внутри кластера, направляя запросы на здоровые поды, соответствующие его селекторам.

Создадим манифест service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

Объяснение директив:

  • app: web-app — параметр, связывающий этот сервис с подами, у которых есть указанная метка;
  • port: 80 — порт сервиса внутри кластера;
  • targetPort: 80 — порт контейнера, куда будет перенаправлен трафик.

Развернём сервис и протестируем его:

kubectl apply -f service.yaml
kubectl get svc web

Теперь мы можем получить доступ к приложению изнутри кластера по внутреннему IP сервиса или по его DNS-имени web.default.svc.cluster.local. Протестировать это можно, запустив временный под с утилитой curl:

kubectl run curl-test --image=curlimages/curl --rm -it -- curl -s http://web.default.svc.cluster.local

Эта команда создаст под, выполнит запрос к сервису и выведет HTML-код главной страницы Nginx, после чего удалит под (--rm).

Обеспечение внешнего доступа через ingress

Созданный сервис не доступен извне кластера. Для организации контролируемого входящего HTTP/HTTPS-трафика используется ресурс ingress. Однако для его работы требуется ingress controller — приложение, которое развёрнуто в кластере и отслеживает создание объектов ingress для настройки балансировщика нагрузки.

Установим популярный Nginx Ingress Controller через Helm (менеджер пакетов Kubernetes; предполагается, что он установлен).

Добавление репозитория и установка контроллера:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx --set controller.publishService.enabled=true

Дождёмся, пока статус пода контроллера не станет Running, проверка:

kubectl get pods -n default -l app.kubernetes.io/name=ingress-nginx --watch

Создадим ingress.yaml, который будет перенаправлять трафик с любого доменного имени (в нашем тестовом окружении) на сервис web:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80

Применим и узнаем внешний IP, полученный ingress controller'ом:

kubectl apply -f ingress.yaml
kubectl get ingress web-ingress

Если контроллер работает в среде без поддержки LoadBalancer (например, в локальном кластере), статус может быть <pending>. В этом случае можно использовать NodePort, который открывает порт на всех нодах. Однако способ с NodePort — это доступ в обход Ingress Controller, который лишает всех его преимуществ (роутинг по доменам, SSL и т. д.). Порт можно указать (из диапазона 30000–32767), но если не указывать, NodePort выберет случайный:

kubectl get svc ingress-nginx-controller -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}'

Теперь приложение доступно по адресу любой ноды и этому порту, например:

http://k8s-worker01:30752

Чтобы использовать доменное имя для теста, добавим запись в локальный файл hosts. Выполните на вашей рабочей машине (не в кластере), подставив актуальный IP ноды:

echo "192.168.1.101 my-app.test" | sudo tee -a /etc/hosts

После этого приложение будет доступно в браузере по адресу http://my-app.test.

Основные операции управления и проверка работоспособности

Масштабирование. Увеличим количество реплик приложения до пяти командой, не редактируя исходный манифест:

kubectl scale deployment/web-app --replicas=5

Сразу же проверим, как Kubernetes запускает новые поды:

kubectl get pods -l app=web-app --watch

Обновление. Сымитируем процесс деплоя новой версии приложения. Обновим версию образа Nginx в деплойменте:

kubectl set image deployment/web-app nginx-container=nginx:1.26

Начнётся плавное rolling-update: Kubernetes поочерёдно создаст поды с новой версией и, после их успешного запуска, удалит старые. Это гарантирует нулевое время простоя. Процесс можно наблюдать:

kubectl rollout status deployment/web-app

Отказоустойчивость. Симулируем сбой, просто удалив один под:

kubectl delete pod/web-app-<RANDOM-ID>

Деплоймент немедленно зафиксирует, что текущее состояние (4 пода) не соответствует желаемому (5 подов), и создаст новый под взамен удалённого. Это также можно наблюдать в реальном времени:

kubectl get pods -l app=web-app

Что делать, если ingress не работает

Если Ingress возвращает ошибки (например, 504 Gateway Timeout или 404):

Проверьте логи ingress controller'а. В них содержится подробная информация о том, куда и почему маршрутизируется (или не маршрутизируется) трафик. Найдите под с контроллером и посмотрите его логи:

kubectl get pods -l app.kubernetes.io/name=ingress-nginx
kubectl logs <ingress-controller-pod-name>

Проверьте аннотации ingress. Для расширенной конфигурации (например, настройки SSL-редиректа или кастомных размеров буфера) используются аннотации. Если вы ими пользуетесь, то убедитесь, что в ingress-ресурсе они указаны корректно:

kubectl describe ingress web-ingress

Проверьте эндпоинты сервиса и убедитесь, что он правильно находит свои поды. Колонка ENDPOINTS должна содержать IP-адреса работающих подов:

kubectl describe svc web

Или:

kubectl get ep web

Если эта колонка пуста, значит, селектор сервиса не совпадает с метками на подах, или поды не готовы.

Заключение

Теперь приложение развёрнуто и готово к работе, но для продакшена этого недостаточно. Что ещё нужно сделать:

  • Установите приложения для наблюдения за состоянием кластера. Можно начать с kube-prometheus-stack — это готовое решение, включающее в себя Prometheus (сбор метрик) и Grafana (их визуализация). Для агрегации логов рассмотрите связку Loki и Promtail.
  • Настройте Liveness и Readiness Probes для ваших контейнеров в манифесте деплоймента. Они укажут Kubernetes, как проверить, здоров ли контейнер и готов ли он принимать трафик. Без них работа механизмов самовосстановления и обновлений не будет полноценной.
  • Освойте работу с объектами ConfigMap и Secret для хранения конфигурации и чувствительных данных отдельно от образов приложений.
  • Для stateful-приложений (базы данных, кеши) изучите механизмы PersistentVolume (PV) и PersistentVolumeClaim (PVC). Настройте динамическое выделение дискового пространства (provisioning), чтобы поды могли автоматически запрашивать нужный объем памяти.
  • Изучите концепции ServiceAccount, Role и RoleBinding для настройки ролевой модели доступа (RBAC) внутри кластера, и ограничьте права служб и пользователей в соответствии с принципом наименьших привилегий.
  • Настройте автоматизированный пайплайн развертывания приложений в кластер. Для этого можно использовать связку GitLab CI + Argo CD или Jenkins + Spinnaker, которые позволяют реализовать практики GitOps и непрерывной доставки.

Читайте в блоге:

Loading spinner
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Нужен VPS сервер?

Арендуйте мощный VPS сервер для ваших проектов! Быстрая настройка, высокая производительность и надежная поддержка 24/7. Начните прямо сейчас!

Что будем искать? Например,VPS-сервер

Мы в социальных сетях