Упаковка приложения в контейнер
Разбираем, из чего состоит сервис и что ему нужно для запуска, описываем сборку образа, выносим настройки в переменные окружения, отделяем данные от кода.
Данные живут в томах, чтобы обновление образа их не задело.
Выполняем настройку Docker и Docker Compose: упаковываем приложения в контейнеры, чтобы они одинаково запускались в тестовой и рабочей среде, поднимаем реестр образов и настраиваем развёртывание. Оркестрацию в Kubernetes предлагаем только там, где она решает реальную задачу, а не создаёт вторую систему для обслуживания.
Классическая история: приложение живёт прямо на сервере, вместе с нужными ему библиотеками, версией среды выполнения и десятком настроек, сделанных когда-то вручную. Стоит обновить систему или перенести сервис на другую машину — и всё разваливается, потому что где-то не та версия зависимости. Восстановить конфигурацию можно только по памяти того, кто её делал.
Контейнер решает именно эту проблему: приложение и его окружение описаны в одном файле и едут вместе. Что собрали, то и запустится — на сервере разработчика, в тестовом контуре и в рабочей системе. Дальше уже вопрос масштаба: одному сервису на одном сервере достаточно Docker Compose, а нескольким сервисам с меняющейся нагрузкой имеет смысл оркестрация.
Разбираем, из чего состоит сервис и что ему нужно для запуска, описываем сборку образа, выносим настройки в переменные окружения, отделяем данные от кода.
Данные живут в томах, чтобы обновление образа их не задело.
Поднимаем хранилище собранных образов в вашем контуре или используем внешний реестр. Версии помечаются, старые сохраняются — откат означает запуск предыдущего образа.
Именно наличие реестра делает откат быстрым.
Для одного приложения или небольшой связки сервисов описываем весь состав в одном файле: приложение, база, кэш, обратный прокси, сеть между ними.
Простое решение, которое понятно администратору без отдельного обучения.
Разворачиваем кластер, настраиваем узлы, сеть, хранилища, входящий трафик и правила размещения сервисов. Готовим описания развёртываний, чтобы состояние системы задавалось конфигурацией.
Берёмся, когда сервисов несколько и нагрузка действительно меняется.
Настраиваем поэтапную замену версий: новая поднимается и проверяется, старая выводится из работы только после этого. Если проверка не прошла, обновление отменяется.
Работает и в Compose, и в кластере — отличается только механикой.
Готовим серверы или виртуальные машины под контейнеры, настраиваем мониторинг состояния сервисов и сбор логов из контейнеров.
Логи контейнера исчезают вместе с ним, поэтому их собирают наружу.
Kubernetes — мощный инструмент, но он добавляет к вашей системе ещё одну, которую тоже нужно обслуживать и понимать. Для одного приложения на одном сервере это стрельба из пушки по воробьям.
| Задача | Docker Compose | Kubernetes |
|---|---|---|
| Одно приложение на одном сервере | Достаточно: весь состав описан в одном файле, запуск и обновление — простыми командами | Избыточно: обслуживание кластера окажется сложнее самого приложения |
| Несколько связанных сервисов | Работает, пока сервисы живут на одной машине | Оправдан, если сервисы нужно разносить по узлам и обновлять независимо |
| Меняющаяся нагрузка | Масштабирование ручное, в пределах одного сервера | Число экземпляров меняется автоматически по заданным правилам |
| Отказ узла | Сервис останавливается до восстановления сервера | Кластер перезапускает сервисы на оставшихся узлах |
| Кто будет обслуживать | Обычный системный администратор после короткого разбора | Нужны отдельные знания или внешнее сопровождение |
| Стоимость владения | Минимальная: ресурсы уходят на само приложение | Выше: узлы кластера, служебные компоненты, обучение команды |
Хорошая новость в том, что выбор не окончательный. Приложение, упакованное в контейнер, переезжает из Compose в кластер без переписывания — поэтому начинать почти всегда разумно с простого варианта.
Сервис работает прямо на сервере, и никто не помнит, как он был настроен. Разбираем состав, описываем сборку, поднимаем в контейнере и проверяем на тестовом контуре до переключения.
Из тех же образов поднимается вторая среда для проверки обновлений. Разница между «тестом» и «боем» перестаёт быть источником сюрпризов.
Когда сервисов становится несколько, а нагрузка неравномерна, разворачиваем Kubernetes: размещение по узлам, автоматический перезапуск, масштабирование и обновление без остановки.
Кластер настроил прежний подрядчик, а как он устроен — неизвестно. Составляем описание, наводим порядок в конфигурациях и решаем, что оставить, а что упростить.
Автоматическая сборка образов, выкладка на контуры и откат при неудаче.
Подробнее →Состояние сервисов, нагрузка и логи, собранные из контейнеров наружу.
Подробнее →Машины и хранилища, на которых работают контейнеры и узлы кластера.
Подробнее →Чаще всего нет. Kubernetes оправдан, когда сервисов несколько, нагрузка меняется и важно, чтобы отказ одного сервера не останавливал работу. Для одного приложения на одном сервере достаточно Docker Compose — и это не компромисс, а нормальное инженерное решение. Мы говорим об этом до начала работ, а не после.
Обычно да, если известно, из чего оно состоит и как запускается. Сложности возникают там, где приложение жёстко привязано к путям на диске, хранит состояние внутри себя или требует графической среды. Мы разбираем такие случаи отдельно: часть решается настройкой, часть — небольшой доработкой кода.
В реестре образов. Его можно поднять внутри вашей инфраструктуры — тогда сборки не покидают контур компании — или использовать внешний. Реестр важен не только для хранения: именно он делает возможным быстрый откат, потому что предыдущая версия остаётся готовой к запуску.
Ничего, если данные вынесены в отдельные тома или во внешнюю базу, — а это первое, что мы делаем при упаковке. Обновление заменяет только образ приложения. Файлы, база и загруженные документы остаются на месте и попадают в резервное копирование как обычные данные.
Возможны оба варианта. Мы передаём схему, описания конфигураций и обучаем вашего администратора работе с системой, либо берём эксплуатацию на себя в рамках сопровождения. Выбор влияет на решение об архитектуре: если поддерживать некому, сложную схему предлагать нечестно.
Сами по себе — не панацея. Изоляция процессов действительно снижает риск, но образ может содержать устаревшие библиотеки, а неаккуратно настроенный контейнер получает лишние права. Пользу даёт дисциплина: минимальные образы, регулярная пересборка, секреты вне кода и ограничение прав. Всё это мы настраиваем сразу.
Расскажите, что за сервис и как он сейчас работает. Посмотрим и предложим схему — от простой связки контейнеров до кластера, если он действительно нужен.
Контейнеризация — редкий случай технологии, которая почти всегда полезна, но легко превращается в самоцель. Ниже несколько мыслей, которые мы обычно проговариваем в начале проекта, чтобы ожидания совпадали с результатом.
Контейнер запускает процесс в изолированном окружении, но использует ядро того же сервера. Отсюда его достоинства: он лёгкий, стартует быстро, его образ можно передавать как файл. Отсюда же ограничения: контейнеры не заменяют виртуализацию там, где нужны разные операционные системы или полная изоляция. В большинстве проектов эти два уровня прекрасно уживаются: виртуальные машины делят железо, контейнеры — приложения внутри машины.
Контейнер устроен так, что его можно удалить и создать заново — в этом вся идея. Но база данных, загруженные файлы и журналы должны при этом уцелеть. Поэтому первое, что мы делаем при упаковке существующего приложения, — находим все места, где оно пишет на диск, и выносим их в отдельные тома. Заодно становится понятно, что именно нужно включать в резервное копирование: не образ, а данные.
Главная плата за кластер — не ресурсы, а знания. Отладка приложения в Kubernetes требует понимания того, как устроены сеть, хранилища, права и планировщик размещения. Если в компании один системный администратор, который занимается ещё почтой, сетью и рабочими местами, кластер станет для него постоянным источником вечерних приключений. В такой ситуации мы предлагаем либо остаться на Compose, либо взять эксплуатацию кластера на себя.
Механика простая: новая версия поднимается рядом со старой, проверяется, и только потом трафик переключается на неё. Но чтобы это работало, приложение должно уметь запускаться в нескольких экземплярах и корректно завершаться по сигналу, а изменения в базе — быть совместимыми с обеими версиями. Мы проверяем эти вещи заранее и, если приложение к ним не готово, честно говорим об этом: иногда правильнее сначала доработать сервис в рамках разработки.
Собранный образ фиксирует не только приложение, но и все его зависимости, включая системные библиотеки. Это удобно, пока не выходит очередное обновление безопасности: контейнер, собранный однажды и живущий год, накапливает известные уязвимости. Поэтому вместе с контейнеризацией мы настраиваем регулярную пересборку образов и включаем её в конвейер выкладки, а не оставляем на «когда-нибудь руками».