Cloud и инфраструктура

Обновлено 5 мин чтения

Containers: почему одинаковая упаковка приложения снижает цену изменений

Проверили один комплект приложения, выпустили другой — и снова ищем разницу между средами. Разбираемся, что должен фиксировать контейнерный образ и что всё равно придётся проверять отдельно.

В тестовой среде приложение аккуратно формирует коммерческое предложение, а на рабочем сервере съезжают таблицы и пропадает часть символов. Код одинаковый. Разница обнаруживается в шрифтах и библиотеке, которая создаёт PDF. Релиз приходится задерживать из-за вещей, не попавших в описание поставки.

Контейнеры помогают сделать такие зависимости явными. Команда готовит образ — пакет с приложением, средой выполнения и нужными файлами — и запускает из него контейнеры. Через проверку и выпуск проходит один определённый пакет. Для руководителя здесь полезна возможность установить, что именно проверили и что затем оказалось у пользователей.

Одинаковый рецепт ещё не означает одинаковую поставку

Есть два разных действия: повторить сборку по инструкции и запустить уже собранный образ. Если инструкция скачивает «последнюю версию» библиотеки, завтра результат может измениться без единой правки в коде продукта. Даже именованный тег образа может указывать на другую версию. Поэтому для поставки важен неизменяемый идентификатор содержимого — digest. Различие между тегом и таким идентификатором объясняет документация Docker.

Практическое правило простое: собрать артефакт, проверить его и продвинуть именно его в рабочую среду. Не собирать «то же самое» заново перед установкой. Конфигурация при этом может отличаться: адрес тестовой базы не должен попасть в production вместе с образом.

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

Что останется снаружи

Обычные Linux-контейнеры используют ядро хоста. Это изолированные процессы, а не полноценные виртуальные машины с собственным ядром. Потребуются совместимые операционная среда и архитектура процессора; отдельные приложения зависят и от оборудования. Базовое различие описано в объяснении контейнеров Docker.

База, сеть, сертификаты, хранилище документов и доступ к внешним системам тоже никуда не исчезают. Один образ может работать на двух площадках, но быть полезным только на одной: например, на второй нет нужного маршрута к корпоративной базе.

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

Документы не должны исчезать вместе с контейнером

У запущенного контейнера есть изменяемая файловая система. Данные в ней можно потерять при удалении и замене контейнера. Это не то же самое, что обычный перезапуск того же экземпляра. Проверка «мы перезапустили, файл остался» ещё не доказывает, что он переживёт обновление.

Долговечные результаты сохраняют отдельно: в подходящем томе, базе или объектном хранилище. У такого хранения должны быть свои правила доступа, резервного копирования и восстановления. Сам по себе том, переживающий удаление контейнера, не защищает от потери диска или ошибочного удаления. Жизненный цикл томов описан в руководстве Docker.

У сервиса предложений полезно отдельно проверить временные файлы и готовые документы. Первые можно создать повторно. Вторые уже могли стать обязательством перед клиентом. Общий каталог «куда приложение пишет всё» скрывает это различие до первой замены экземпляра.

Возврат старого образа не откатывает данные

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

Ещё надо определить, как приложение заканчивает работу. Оно должно перестать брать новые задания и корректно завершить текущие либо оставить возможность безопасного повторения. Принудительная остановка посреди формирования документа не должна выглядеть в системе как успешно выполненная заявка.

Несколько копий контейнера также могут одновременно запускать одну фоновую задачу. До увеличения их числа нужно выяснить, кто распределяет работу и как распознаются повторы. Упаковка не исправляет эти свойства приложения автоматически.

Кто обновляет то, что мы зафиксировали

Фиксация зависимостей защищает от неожиданного изменения, но оставляет внутри образа старые уязвимости. Нужен владелец базового образа и понятный путь обновления: новая сборка, проверка приложения, выпуск и вывод прежней версии. Регулярную пересборку и минимальный состав образа рекомендует руководство по сборке Docker.

Пароли и ключи не стоит включать в образ. Удаление файла на позднем шаге не гарантирует его исчезновения из предыдущего слоя. Для секретов сборки предусмотрены специальные механизмы, а рабочие секреты передаются при запуске через выбранную систему управления доступом. Это разные этапы; их не следует смешивать. Ограничения обычных переменных сборки разобраны в документации Build secrets.

Сам реестр образов тоже становится зависимостью выпуска. Пока старые экземпляры работают, его недоступность может быть незаметна. При замене сервера внезапно выяснится, что скачать нужную версию невозможно. Нужны хранение используемых артефактов, проверка происхождения и доступы для восстановления.

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

Проверка без покупки большой платформы

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

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