3

WebTech

Личный кабинет

Проекты, коммерческие предложения, документы и отчёты — в одном месте.

Войти Зарегистрироваться Забыли пароль?
Контейнеры и оркестрация

Одинаковая среда на ноутбуке, стенде и в продакшене

Переносим приложение в контейнеры, разворачиваем кластер, описываем выкат декларативно и включаем автомасштабирование. Отдельно занимаемся stateful-сервисами и бэкапами — там, где кластеры чаще всего ломаются.

Или сразу: +7 (962) 368-39-51 Telegram

multi-stage
образы на минимальной базе
GitOps
состояние кластера описано в git
HPA
масштабирование по нагрузке
PITR
восстановление данных на момент времени
Задачи

Что мешает жить до контейнеризации

Знакомый набор: сервер настроен руками, версии на машинах расходятся, а данные в volumes никто не проверял на восстановление.

Работает, потому что на сервере так настроено

Конфигурация живёт только в продакшене: правки в php.ini, расширения, cron и системные пакеты. Воспроизвести стенд невозможно, а переезд на новую машину превращается в проект.

Разные версии PHP и Node на серверах

Один узел на PHP 8.1, второй на 8.3, расширения отличаются. Ошибки, которые воспроизводятся только на одном из серверов, съедают дни на отладку.

Выкат по SSH с простоем

Файлы раскладываются по серверам вручную, кэш и очереди перезапускаются в полуручном режиме. Каждый релиз — короткий, но реальный простой для пользователей.

Нет лимитов: один процесс роняет соседей

У сервисов нет requests и limits по памяти и CPU. Разросшаяся очередь или тяжёлый отчёт выедают память узла, и падает всё, что на нём работает.

Внутри кластера всё доступно всем

Сетевых политик нет, секреты лежат в ConfigMap в base64, сервисные учётки имеют полные права. Компрометация одного пода открывает доступ ко всему окружению.

Данные в volume без проверенных бэкапов

Базы и Redis живут в PersistentVolume, но резервные копии снимаются дампом на тот же диск, а восстановление никто не пробовал. Реальная проверка происходит во время аварии.

Решения

Что мы настраиваем

От Dockerfile до политик сети и бэкапов: контейнеризация без оркестрации и оркестрация без работы с данными одинаково неполны.

Контейнеризация приложения

Собираем образ так, чтобы он одинаково вёл себя локально, на стенде и в продакшене, и не тянул за собой лишние пакеты.

  • Multi-stage Dockerfile: сборка зависимостей отделена от рантайма
  • Минимальная база, запуск от непривилегированного пользователя
  • Корректные healthcheck-и, логи в stdout, конфигурация через переменные окружения
  • Кэш слоёв и локальный docker-compose для воспроизводимой разработки

Кластер и его безопасность

Разворачиваем кластер — управляемый или собственный — и сразу закрываем типовые дыры: избыточные права, открытую внутреннюю сеть, секреты в открытом виде.

  • Namespaces, RBAC и разграничение доступа по командам и окружениям
  • Network policies: сервис видит только тех, с кем ему положено общаться
  • Requests и limits по памяти и CPU, приоритеты и Pod Disruption Budget
  • Секреты в защищённом хранилище со синхронизацией в кластер, а не в ConfigMap

Декларативный выкат и GitOps

Состояние кластера описывается в git, изменения проходят ревью, а расхождение между репозиторием и кластером видно сразу.

  • Helm-чарты или Kustomize: одно описание для всех окружений
  • GitOps через Argo CD: синхронизация, откат и история изменений
  • Rolling update с readiness-пробами, canary и blue-green через Argo Rollouts
  • HPA и cluster autoscaler: масштабирование по нагрузке в сезонные пики

Stateful-сервисы и данные

Самая недооценённая часть миграции. Проектируем хранение данных и проверяем восстановление до того, как оно понадобится в бою.

  • StatefulSet, PersistentVolume и StorageClass с понятной политикой хранения
  • Операторы для PostgreSQL, Redis и очередей либо осознанно внешние managed-сервисы
  • Резервное копирование с проверкой восстановления и восстановлением на момент времени
  • Учения по отказу узла и зоны: приложение действительно переживает потерю ноды
Процесс

Как проходит миграция в контейнеры

Сначала контейнеры и предсказуемая сборка, затем кластер. Переезд идёт с работающим продакшеном, без «большого взрыва» в выходные.

  1. 01 1 неделя

    Аудит приложения и состояния

    Находим точки хранения состояния: загруженные файлы, сессии, кэш, cron, локальные очереди. Решаем, что выносится из контейнера, а что остаётся.

  2. 02 1–2 недели

    Контейнеризация

    Пишем Dockerfile, docker-compose для локального запуска, выносим конфигурацию в переменные окружения. Добиваемся, чтобы вся команда поднимала проект одной командой.

  3. 03 2–4 недели

    Кластер и GitOps

    Разворачиваем кластер, описываем чарты, подключаем Argo CD, настраиваем сети, ресурсы, автомасштабирование и сбор метрик с подов.

  4. 04 2–3 недели

    Перевод нагрузки и передача

    Переносим трафик частями, проверяем отказоустойчивость и восстановление данных, обучаем команду работе с кластером и передаём runbook.

Контейнер — не виртуальная машина

Типичная ошибка первого переезда — перенести в образ весь сервер: cron, nginx, php-fpm и базу данных в одном контейнере с супервизором. Такой контейнер теряет главные свойства: он не масштабируется частями, не имеет внятного жизненного цикла и ломается при обновлении любой из частей.

Контейнер решает одну задачу: приложение пишет логи в stdout, конфигурацию получает из переменных окружения, состояние хранит вне себя, а фоновые задачи вынесены в отдельный процесс, который можно масштабировать независимо. Web-процессы, воркеры очередей, планировщик и сборщик фронтенда — это разные контейнеры из одного образа, каждый со своим масштабом и своими ресурсами.

Когда stateful-нагрузку не стоит тащить в Kubernetes

Кластер отлично управляет stateless-сервисами: их можно перезапускать, дублировать и перемещать между узлами без последствий. С базами данных всё иначе: цена ошибки в конфигурации хранилища или в политике репликации — потерянные данные, а не пара минут недоступности.

Мы исходим из того, что команде выгоднее не эксплуатировать базу самостоятельно, если есть управляемый сервис с репликацией, бэкапами и восстановлением на момент времени. Если требования — размещение данных в вашем контуре, отсутствие управляемых сервисов у провайдера или особая конфигурация — разворачиваем StatefulSet с оператором, но обязательно с проверенным восстановлением и учениями по отказу узла. Утверждение «бэкапы делаются» без проверки восстановления мы не принимаем как готовность.

Стоимость владения кластером

Kubernetes — это не только узлы и управляющая панель. Это обновление версий каждые несколько месяцев, сопровождение чартов, разбор сетевых проблем, обновление операторов, дежурство и обучение новых инженеров. Для парка из трёх-четырёх сервисов такая инфраструктура часто дороже, чем пара виртуальных машин с контейнерами под systemd.

Кластер окупается, когда сервисов и окружений много, нужны частые релизы, изоляция команд, автомасштабирование под пиковую нагрузку и единый способ описывать выкат. В остальных случаях мы честно говорим об этом и предлагаем более простой вариант, оставляя путь к кластеру открытым: контейнеры и декларативные описания, подготовленные сейчас, переносятся в Kubernetes почти без изменений.

Частые вопросы

Обычно нет. Для одного-двух приложений достаточно контейнеров на двух-трёх виртуальных машинах с балансировщиком и декларативным выкатом: это даёт воспроизводимость, отсутствие простоя и откат, но не требует сопровождения кластера, обновления его версий и отдельного дежурства. Кластер стоит разворачивать, когда растёт число сервисов и окружений или нужны автомасштабирование и изоляция команд.

Управляемый вариант снимает с команды работу с управляющей панелью, её обновления и отказоустойчивость — платите за узлы и, как правило, за панель. Собственный кластер имеет смысл, когда есть требования размещать всё в своём контуре, когда нужна нестандартная конфигурация сети или когда у команды уже есть опыт эксплуатации kubeadm-кластеров и дежурства. Мы разворачиваем оба варианта и помогаем посчитать совокупную стоимость владения, включая часы инженеров.

Мы оцениваем три варианта: оставить базу на отдельной виртуальной машине, перейти на управляемый сервис провайдера или развернуть её в кластере через оператор. Выбор зависит от требований к размещению данных, нагрузке и наличию компетенций. В любом случае до переезда настраиваем резервное копирование с восстановлением на момент времени и проверяем восстановление на отдельном контуре — вслепую такую миграцию делать нельзя.

Технически это readiness-пробы, корректная стратегия rolling update, lifecycles для аккуратного завершения обработки запросов, Pod Disruption Budget и достаточное число реплик. Для критичных релизов добавляем blue-green или canary с автоматическим откатом по метрике ошибок. Важное условие — совместимые миграции базы данных по схеме expand/contract, иначе простой возникает не из-за кластера, а из-за изменения схемы.

Планируете переезд в контейнеры или кластер?

Опишите приложение и текущую инфраструктуру — предложим этапы миграции без остановки продукта.