Сейчас многие компании работают без возможности прямого управления составом пакетов внешних репозиториев, даже если применяют зеркалирование, проксирование и кэширование. Это приводит к тому, что окружение выполнения постоянно меняется, в частности состав докер-образов меняется чаще, чем требуется производству.
Возможны ситуации, когда в состав разрабатываемого продукта могут попадать нежелательные изменения, которые содержатся во внешних зависимостях. Это особенно актуально во время сертификации продукта. Как следствие — затягивание сертификаций, сбои ночных тестов и интеграционного тестирования, поломки on-premise production (производственной среды, расположенной на собственных ресурсах организации) при накатывании хотфикса и прочее. В новой статье мы описали подход, который позволит избежать таких проблем.
Чего мы хотели добиться
Прежде чем приступать к описанию подхода, пара слов о задачах, которые мы хотели решить:
- Получить полный контроль над составом внешних пакетов в релизе (предсказуемость).
- Зафиксировать составы внешних репозиториев для быстрой выкатки хотфиксов с минимальным дополнительным тестированием (скорость).
- Обеспечить продуктовые стенды QA повторяемым предсказуемым фиксированным окружением (повторяемость).
- Независимость от наличия внешнего канала связи (автономность).
- Моментальное переключение на официальные репозитории при аварии (отказоустойчивость).
- Гарантированная проверка ключей внешних репозиториев в сборочных конвейерах (доверие).
- И самое главное, передать управление и контроль над составом внешних пакетов в руки продуктовых команд и релиз-менеджеров (самоуправление).
Анализ жизненного цикла feature-сборок
Наш подход решает задачу фиксации состава внешних репозиториев на конкретную дату, под релиз или фичу. Следующая схема наглядно показывает управление жизненным циклом релиза, feature-сборки и хотфикса.
Для примера возьмем условный репозиторий Debian Stretch. Данный подход применим и для репозиториев Docker, SaltStack и т. п. На временной шкале зафиксировали три среза на даты T1, T2 и T3.
T1 | T2 | T3 | |
---|---|---|---|
stretch | 20200305 | 20200420 | 20200615 |
Feature1 | 20200304 | 20200304 | 20200501 |
Feature2 | 20200304 | 20200304 | 20200601 |
Feature3 | 20200301 | 20200406 | 20200406 |
Мы свели в таблицу состав внешнего репозитория Debian Stretch для сборки дистрибутивов Feature1, Feature2 и Feature3. Из таблицы видно, что состав внешнего репозитория контролируется каждой веткой независимо. Мы приняли соглашение для себя фиксировать ветку master для Debian Stretch ежедневно и давать метки каждому срезу в формате YYYYMMDD, например 2020304 для среза на 4 марта 2020 года. Итого в таблице приведены используемые для дистрибутива в каждой ветке срезы внешнего репозитория в трех разных моментах времени и состав в мастере для Debian Stretch. Команда для каждой фичи или для каждого релиза обновляет состав внешних репозиториев по своему усмотрению и согласно своему циклу разработки.
На примере Feature1: продуктовая команда приступает к разработке новой фичи и фиксирует в конфигурационных файлах состав внешнего репозитория на дату 20200228 (см. на схеме выше).
Переключаем на 20200228
deb http://repository.co/debian-stretch-20200228 stretch main contrib non-free
В процессе разработки в связи с появлением новых пакетов возникает необходимость обновить пакетную базу до даты 20200304. Переключаем рабочий репозиторий на нужную дату.
Переключаем на 20200304
deb http://repository.co/debian-stretch-20200304 stretch main contrib non-free
Далее происходит еще одно переключение пакетной базы на дату 20200501.
Переключаем на 20200501
deb http://repository.co/debian-stretch-20200501 stretch main contrib non-free
Если теперь мы проведем временные срезы, то увидим, что в моменты времени T1 и Т2 разработка Feature1 идет на пакетной базе, «замороженной» 4 марта 2020 года. А в срезе T3 разработка идет уже на новой пакетной базе за 1 мая 2020 года.
Продуктовое мультирелизное управление зависимостями
Теперь рассмотрим управление зависимостями нескольких активных релизов продукта. На поддержке представлены три релиза 2.5, 2.6 и 2.7.
В таблице мы видим соответствие релизов и дат, на которые сделан слепок репозитория. В ней показано, какой срез состава внешнего репозитория использовался для построения конкретной версии дистрибутива.
Релиз | Состав |
---|---|
2.5.128, 2.5.135, 2.5.207 | 20200301 |
2.6.201, 2.6.215, 2.6.315 | 20200301 |
2.7.210, 2.7.217, 2.7.305 | 20200404 |
Вместо именования срезов по датам YYYYMMDD мы также используем именование тегами в формате <ProjectName.ReleaseVersion> (название_релиза.версия_релиза продукта, например name.2.2) или <ProjectName-FeatureNumber> (добавляем номер фичи, например 3).
Снапшот для 2.5 по состоянию на 20200301
deb http://repository.co/debian-stretch-projectname-2.5 stretch main contrib non-free # 20200301
Таким образом в процессе разработки релиза 2.5 команда фиксирует состав зависимых репозиториев на дату 20200301. Где-то в апреле команда начинает новый релиз 2.6 и решает использовать состав пакетов внешнего репозитория от 2.5. Создаем новый снапшот для 2.6 из снапшота для 2.5. В будущем составы репозиториев для релизов 2.5 и 2.6 могут легко разойтись. Мы сделали для 2.6 свой тег debian-stretch-projectname-2.6.
Снапшот для 2.6 по состоянию на 20200301
deb http://repository.co/debian-stretch-projectname-2.6 stretch main contrib non-free # 20200301
В случае релиза 2.7 команда может начать разработку с ветки master — ежедневного снапшота оригинального репозитория.
Снапшот для 2.7 по состоянию на 20200404
deb http://repository.co/debian-stretch-projectname-2.7 stretch main contrib non-free # 20200404
Мультипродуктовое управление зависимостями
Рассмотрим мультипродуктовое управление зависимостями на примере двух продуктов с разными релизными циклами и своими продуктовыми командами: Stealth и Infiniti.
Прокомментируем таблицу, что и когда происходит.
Продукт | Релиз | Состав |
---|---|---|
stealth2.2 | r2.2.124 | 20200301 |
stealth2.2 | r2.2.131, r2.2.162 | 20200305 |
infiniti4.0 | r4.0.235, r4.0.241 | 20200303 |
infiniti4.0 | r4.0.250 | 20200308 |
1. Пусть с 1 марта 2020 года стартовала разработка версии 2.2 проекта Stealth, для этого был создан снапшот состава пакетной базы на текущую дату. Выпуск релиза 2.2.124 выполнен с пакетной базой внешнего репозитория от 20200301.
Stealth 2.2
deb http://repository.co/debian-stretch-stealth-2.2 stretch main contrib non-free # 20200301
2. Пятого числа производится обновление пакетной базы. Рабочий репозиторий debian-stretch-stealth-2.2 одномоментно переключается на нужную дату, выпуск релизов 2.2.131 и 2.2.162 выполнен с составом пакетов внешнего репозитория от 20200305. Без дополнительных манипуляций в окружении все 100500 микросервисов продукта одномоментно получили в сборочном конвейере новое окружение 20200305.
Stealth 2.2
deb http://repository.co/debian-stretch-stealth-2.2 stretch main contrib non-free # 20200305
3. Параллельно третьего числа стартует разработка проекта Infiniti версии 4.0 и для нее создается срез состава репозитория на дату 20200303. Версии 4.0.235 и 4.0.241 выпускаются с составом пакетов внешнего репозитория на 20200303.
Infiniti 4.0
deb http://repository.co/debian-stretch-infiniti-4.0 stretch main contrib non-free # 20200303
4. После выпуска версии 4.0.241 команда решает обновить состав репозитория до 20200308 и выпустить новый релиз с новым составом внешних пакетов. Версия 4.0.250 выходит с составом пакетов на 20200308.
Infiniti 4.0
deb http://repository.co/debian-stretch-infiniti-4.0 stretch main contrib non-free # 20200308
Два варианта переключения между состояниями репозиториев позволяют выбрать удобный для процесса разработки подход. В первом случае мы переключаемся в нужное состояние путем указания снапшота репозиториев на конкретную дату. Во втором случае для многокомпонентных продуктов используем именованный срез и двигаем его на нужную дату. Такой механизм обеспечивает единовременное переключение среза во всех 100500 компонентах продукта.
Управление срезами каждого внешнего репозитория мы ведем в отдельном Docker-контейнере, поэтому в любой момент можем переключить конкретный репозиторий на скачивание с внешней сети в случае каких-то аварий.
Скачать список всех репозиториев
# For example
curl repository.co/info/sources.list | grep $(lsb_release -cs) > /etc/apt/sources.list
Автоматическое создание срезов внешних репозиториев
Обновление репозиториев происходит каждую ночь по планировщику GitLab. При добавлении нового репозитория изменения автоматически применяются на сервере.
В момент фиксации нового среза внешнего репозитория проверяется его сертификат, если он отличается от сохраненного у нас, то обновления не происходит, а нам поступает сообщение об ошибке.
Итоги
- Подготовка новой версии дистрибутива к сертификации больше не является головной болью. На период сертификации мы фиксируем состав дистрибутива, и если нужно что-то пофиксить оперативно, то с большой вероятностью в выпущенном хотфиксе не будет ошибок из-за изменения окружения.
- Все feature-сборки получают управляемое состояние внешних репозиториев.
- Ускоряются выкатка хотфиксов и проверка через QA с предсказуемым, быстрым и успешным результатом.
- Feature-стенды получают после развертывания заранее определенную, неизменяемую среду выполнения.
- Продуктовые команды получили полностью самостоятельный контроль над составом внешних репозиториев для любых задач.
Отметим, что у Debian есть официальный ресурс snapshot.debian.org с ежедневными срезами и большой глубиной хранения. Для определенных задач этого достаточно.
Благодарим Сергея Смирнова и сообщество за прекрасный инструмент для управления составом внешних репозиториев Aptly. От нас — небольшой вклад в лучшие практики использования этого полезного инструмента в производственных конвейерах.
В следующих статьях расскажем про связку Aptly + Simple-CDD для подготовки ISO-образов дистрибутивов, делегирование управления внешними зависимостями в продуктовые команды и проблемы применения Aptly в процессе управления внешними зависимостями.
Авторы: Никита Драчёв, Александр Паздников, Тимур Гильмуллин
anonymous
Спасибо за статью. Можете поподробнее рассказать как устроен ваш репозиторий на aptly? Полное зеркало официального + снэпшоты? Делаете ли deb пакеты со своими разработками или собираете бинарь в докере? Фиксируете ли версии того, что сами пишите в Dockerfile? Кто дергает API? curl в недрах CI или что-то другое?
ptsecurity Автор
Спасибо за комментарий!
Полное зеркало официального + снэпшоты? Из официальных репозиториев мы забираем только установочные файлы, udeb и deb пакеты.
Делаем свои пакеты и выкладываем в свой артефакторий, аптли для этого не используется. Докер контейнеры так же выкладываются в артефакторий после сборки из внешних пакетов с aptly и наших пакетов с артифактория.
В докер файлах релизных контейнеров фиксируем снепшот аптли для данного релиза.
Работа с аптли реализована через GitLab CI и командно строчный интерфейс, это связано с рядом причин, например необходимостью запуска встроенного в аптли web сервера и проблемами обработки слеша. github.com/aptly-dev/aptly/issues/115 github.com/aptly-dev/aptly/issues/561