О билд системах, часть вторая
В продолжение предыдущей части, предлагаю посмотреть как подобная же система организуется на базе bsd.
Здесь есть значительные отличия - во-первых сама система - source-based. Пакеты по дефолту собираются на самой целевой машине. Бинарные пакеты - не более чем опция, до последнего времени прилепленная достаточно сбоку.
Во-вторых, нет 2х одинаковых систем. Прежде чем переходить на обновление бинарниками, требуется привести настройки, версии системы и расположение файлов более-менее к одному виду.
В-третьих - немного другая цель. Под дебиан дефолт тебя как правило устраивает, пересобираешь выборочно и своё. Под бзд ты это делаешь, чтобы ХОТЯ БЫ ЧАСТИЧНО избавиться от гемора с обновлением и от затрат времени на него. Примеры - кольцевая зависимость apr <=> svn, perl <=> exim, icu, lzo <=> bacula-fd. Всё это при сборке руками периодически ломается.
Теория
Примерное движение пакетов и исходников показано на схеме. Обозначения:
- .txz -- бинарники
- .tar.gz -- оригинальные исходники
Программы:
- poudriere -- непосредственно сборка пакетов
- ts -- очередь заданий на замену atd/batch
- pkg -- управление пакетами
- cron -- автоматизация обслуживания
Реализация
Потребуется ~40-80 гб места на всё, прайс-лист ниже:
- дерево портов -- 3Гб за штуку, (+1 системное)
- дистфайлы -- если периодически чистить - 2Гб минимум
- отдельный jail на каждую ветку и архитектуру -- 2,5Гб за штуку
- кэш для объектных файлов -- 5-15Гб
- зеркало svn'а портов -- 20Гб (не wc, а именно зеркало, если хотим его раздавать дальше)
- зеркало svn'а системы -- 8Гб (если не хотите дождаться второго пришествия в процессе обновления jail'ов)
Также потребуется > 2Гб памяти, сборка некоторых пакетов жрёт немеряно памяти. Например что-либо с использованием boost'а.
Развёртывание с нуля всей системы происходит примерно в такой последовательности:
- ставится хост-система в конфигурации «по минимуму»
- ставится необходимый софт, (poudriere, ts, cron, mail, <…>)
- генерятся ключи для подписи пакетов/метаданных, настраивается конфиг poudriere
- выделяется достаточно места под сборку и хранение пакетов (минимум 50-60 гигов суммарно в /usr/obj, /usr/ports, /usr/local/poudriere, /usr/local/www - лучше вынести на отдельный раздел и понаставить симлинков)
- скачивается отдельное дерево портов (poudriere ports -c <…>)
- определяются необходимые наборы софта (точнее количество наборов), и наборы архитектур/версий системы, под которые будет собираться софт
- для каждого набора софта составляется make.conf с набором
OPTIONS_SET/UNSET
, делаются симлинки вида $jailname-make.conf с нужного make.conf - строятся сборочные jail'ы (${softwareset}-${branch}x${arch}) (это легко займёт 2-3 дня)
- составляются возможно более полные списки пакетов для каждого набора софта pourdiere.d/lists
- проводится тестовый билды для каждого из наборов до полного устранения видимых косяков
- при необходимости дополнительно настраиваются опции портов через
poudriere options
- проводится полномастабные билды (опять же - легко займёт 2-3 дня)
- публикуются пакеты через вебсервер, раскидываются конфиги/ключи на нужные хосты
Список граблей
Вынесен отдельным пунктом, потому что их много и половина -- show-stopper'ов.
- одновременное подключение 2х репозиториев, например "официального" и своего вызывает весёлый расколбас в обновлениях. Один день, когда прилетает новая версия из "официальной" репы хочет обновится 66 пакетов, следующий день, когда билдсервер соберёт свою версию - 2 пакета. (ибо "direct dependency changed", и посрать, что там отличие в установке примеров для конфигов, html-доков или ещё какой херни)
- в силу предыдущего пункта - в репе придётся держать все пакеты, которые используются, и обновлять их своими силами.
- разрешение зависимостей при сборке - примитивно до тупости. Обновился perl 5.16.3_10 -> 5.16.3_11. Удаляем из репы всё что от него зависит, прямо или косвенно. Хуяк, от репы в 300 пакетов - осталась треть, всё остальное собирается заново. Особенно забавно это в свете 2х предыдущих пунктов.
- обновление пакетов из сорцов никуда не девается, portmaster радостно скажет "а у тебя есть обновление для перлового модуля с xs, давай-ка я тебе заново СОБЕРУ ещё 15 пакетов, включая autocrap, m4, bison, cmake и прочее", которые ты любовно выкорчёвывал из системы, ибо заебут обновлениями каждый день.
- обновления системы из сорцов тоже никуда не девается, фактически это единственный способ обновления системы при использовании кастомного ядра. А использовать кастомное приходится, потому что GENERIC нихера не умеет. Обновление системы по времени - это примерно столько же, сколько обновление портов за то же время. От 2х до 5 часов в месяц. На каждую машину.
- нет никакой возможности узнать, какого художника вот этот пакет тянет половину иксов ДО его установки. Выглядит это так: "обновился пакет X, размер 300кб, устанавливается 64 пакета по зависимостям, размер 300Мб"
Итого
Билд-система получается намного проще и логичнее устроенной, чем в случае с debian'ом, но вышеуказанные грабли сводят это преимущество к нулю. Окей, будешь ты тратить не 5 часов на обновление каждой машины, а только 3. Сильно полегчало?