From: Елсуков Андрей <bu7cher@yandex.ru.>
Date: Mon, 8 Apr 2005 14:31:37 +0000 (UTC)
Subject: Создание релиза FreeBSD
Впервые опубликовано в журнале "Системный Администратор" (http://samag.ru)
Версия текста: 1.0
Введение
В этой статье я хочу обобщить свой опыт по сборке релиза операционной
системы FreeBSD. Создание релиза, в принципе - не такая уж сложная
задача, но достаточно длительная и при некоторых обстоятельствах может
длиться дольше, чем ей необходимо. Да и к тому же, описание этого
процесса на русском языке мне найти не удалось. Надеюсь, что статья
поможет желающим собрать свой релиз и обойти те проблемы, с которыми
столкнулся когда-то я.
Для чего это нужно?
Я вижу несколько причин, для чего может понадобиться создать релиз ОС
FreeBSD в "домашних" условиях:
* не всегда есть время, средства, возможность покупать свежий релиз
системы, чтобы иметь его на CD для более быстрой установки
"свежей" системы;
* хочется иметь под рукой загрузочный инсталляционный диск системы
со специфическими настройками: установочный диск STABLE ветки;
диск с обновленными драйверами, например, для RAID контроллеров; с
определенным набором скомпилированных пакетов; с архивами исходных
файлов некоторых программ для компиляции из <<портов>>;
* хочется всё знать и уметь.
Кто-то, возможно, предложит свои причины, для меня достаточно и этих.
Что нам необходимо для начала?
Как это ни банально, нужна машинка под управлением ОС FreeBSD. Причём,
желательно, чтобы версия системы была из той же ветки, что и версия
будущего релиза (почему <<желательно>> - расскажу позднее). Если ваша
машинка подключена к Internet и проблемы с ценой трафика для вас не
существует, то следующие компоненты для вас не важны, если же нет то,
по пунктам:
CVS репозитарий
Эта "свалка файлов" в архиве, на данный момент, у меня занимает
порядка 500 Мбайт. Чтобы получить репозитарий - проще всего
воспользоваться CVSup'ом. У меня по крону раз в сутки запускается
следующая команда для обновления репозитария:
# cvsup -g -L 2 /mnt/cvs/cvs-supfile
где конфигурационный файл CVSup'а выглядит следующим образом:
Лучше всего, если вы достанете архив репозитария, пусть даже старый у
своего знакомого или ещё где-то - сэкономите кучу времени и трафика.
Поддержание репозитария в "свежем" состоянии уже не так накладно,
так что, сделав один раз, использую и сейчас.
Архивы исходных файлов для сборки портов
Не пугайтесь, дистрибутивы для всех портов нам не понадобятся. Но и
перечислять каждый порт довольно утомительное занятие, да и от релиза
к релизу этот список может различаться, поэтому я немного обобщу:
* для сборки проекта документации понадобятся исходные файлы для
портов, список которых можно посмотреть в файле
src/release/Makefile.inc.docports;
* для создания ISO образов дисков нужен порт
ports/sysutils/cdrtools;
* для создания полноценного miniinst-диска нужны исходные файлы Perl
и X.org, либо XFree (в зависимости от версии системы).
В общем-то, вот, вроде, и всё. Недостающие компоненты можно будет
скачать во время сборки (если есть доступ к Internet, то они скачаются
автоматически).
Как это происходит?
Весь процесс сборки я условно разделил на несколько этапов. Отчасти,
моя классификация перекрывает ту, что описана в мануале release(7).
Итак, по-порядку:
Подготовка к сборке
Кроме выше перечисленного, я отнёс сюда следующие действия:
* получение исходных файлов системы для будущего релиза;
* выбор раздела, на котором достаточно свободного места.
К слову сказать, для сборки релиза может понадобиться от двух до
четырёх с небольшим гигабайт свободного места.
Сборка мира
Собственно, сборка мира точно такая же, как и при обновлении системы,
за подробностями - в handbook.
Создание chroot-окружения
Весь процесс сборки релиза, сразу после компиляции мира, происходит в
chroot-окружении. Сначала туда инсталлируется собранный мир, затем там
происходит дальнейшая компиляция системных библиотек, ядер, портов,
проекта документации и т.п.
Создание дистрибутива
Это заключительная стадия и включает в себя компиляцию указанных ядер,
создание структуры каталогов дистрибутива, размещение архивов бинарных
файлов и установочных скриптов, создание каталога для инсталляции с
FTP, создание ISO образов дисков.
На что следует обратить внимание?
Рекомендую прочитать Makefile в каталоге src/release. Из него можно
почерпнуть довольно много полезной информации. Так же обязательно
прочитать мануал release(7) и желательно просмотреть все файлы, на
которые он ссылается.
make.conf
При сборке мира используются установки из /etc/make.conf текущей
системы. Рекомендую просмотреть их и подумать - нужны ли они вам. К
примеру, некоторые настройки могут запрещать сборку отдельных частей
системы, отсутствие которых может фатально сказаться на дальнейшей
сборке релиза, например Perl. Так что, если не хотите терять время,
лучше, на первый раз, закомментировать все опции в make.conf или
переименовать этот файл. Возможно, наоборот, вы хотите использовать
какие-то специфически опции, например дополнительную оптимизацию -
дело ваше.
Переменные окружения
Часть переменных окружения описана в мануале release(7). Часть можно
найти в make скриптах, используемых при сборке (в папке src/release).
Хочу обратить внимание на некоторые из них:
* DOC_LANG - в ней можно перечислить через пробел языки, для которых
вы хотите собрать документацию, например,
DOC_LANG="en_US.ISO8859-1 ru_RU.KOI8-R". Если вы не укажете языки,
то будут собираться все возможные, а это довольно долго.
* NOPORTREADMES - при включении в дистрибутив дерева портов не будут
генерироваться README.html с описанием портов, что существенно
ускорит процесс сборки релиза.
* RELEASENOUPDATE - если при сборке у вас возникнет ошибка, эта
переменная совместно с целью make rerelease освободит вас от
повторного обновления исходных файлов системы из CVS репозитария.
* BUILDNAME - имя релиза. Если не зададите, то получите в результате
что-то подобное FreeBSD-4.11-20050131-STABLE. Ещё рекомендую
задавать имя в стандартном виде, как это делается в оригинальных
дистрибутивах, например, 5.3-STABLE. Не нужно называть релиз своим
именем, если не хотите в дальнейшем иметь проблемы, например, при
установке или обновлении портов.
* MAKE_ISOS - если задать, то при завершении всех этапов сборки,
автоматически будут созданы ISO-образы дисков дистрибутива.
Советую не спешить с указанием этой переменной, создать образы
никогда не поздно.
* hostname - это не переменная окружения, но я отнёс её сюда. Когда
вы соберёте релиз, при его установке, в выводе команды uname будет
фигурировать имя хоста, на котором происходила сборка. Из
эстетических соображений, на время сборки можно сменить имя хоста,
командой hostname.
"distfiles" для портов
Как я уже говорил, для сборки релиза понадобятся дистрибутивы
некоторых портов. Если у вас уже есть скаченные дистрибутивы, вы
можете указать скриптам их местоположение, и они не будут скачиваться
снова. Для этого используется переменная окружения RELEASEDISTFILES.
Если вы пользуетесь системой портов, и в вашем дереве есть каталог
ports/distfiles, то переменную можно не определять, этот каталог будет
скопирован в chroot-окружение (наверное, стоит задуматься о том,
сколько места он занимает).
Когда что-то пошло не так
Если с машины, где происходит сборка релиза, нет прямого доступа к
Internet, то есть большая вероятность того, что на каком-нибудь этапе
сборка прервётся с ошибкой. Хотя, практика показывает, что они могут
возникать и при наличии доступа в Internet. Ошибки, препятствующие
сборке релиза, могут быть разными. Начиная от простых - нехватки
каких-нибудь дистрибутивов для сборки из портов и заканчивая
различными ошибками при компиляции.
Не нужно начинать всё сначала
Чтобы не начинать всё заново, расскажу как с <<минимальными потерями>>
продолжить сборку релиза. Итак, предположим, что процесс сборки
прервался по какой-то причине. Решив проблему, вы хотите продолжить
сборку. Для этого нужно указать утилите make цель <<rerelease>>. И
если нет необходимости в обновлении исходных файлов системы из
репозитария, желательно определить переменную RELEASENOUPDATE.
Теперь, предположим, что вы хотите повторить какой-то этап сборки,
например, пересобрать ISO-образы системы. Предыдущая схема здесь не
сработает. Если ISO-образы уже были созданы, то повторного создания
таким методом не добиться, даже если предварительно их удалить. По той
простой причине, что при завершении этапов сборки (они описаны в
мануале release(7)), скриптами сохраняются <<пометки>> об их
завершении. Пометки - это обычные файлы, созданные командой touch.
Имена файлов соответствуют названию завершившегося этапа. Файлы
находятся в каталоге ${CHROOTDIR}/usr/obj/usr/src/release. Для того
чтобы вновь пересобрать ISO образы, нужно удалит файл <<iso.1>> и уже
тогда запускать make rerelease.
Не хватает дистрибутивов для установки порта
Если есть доступ в Интернет, то возникновение такой ошибки мало
вероятно. Если же доступа нет, то можно вручную скачать дистрибутив
для установки порта с машины, где есть доступ, и поместить его в папку
${CHROOTDIR}/usr/ports/distfiles, конечно, нужно не забывать, что
некоторые дистрибутивы могут располагаться в отдельных каталогах.
Чтобы узнать, должен ли дистрибутив порта располагаться в отдельном
каталоге, нужно выполнить в каталоге порта команду grep DIST_SUBDIR
Makefile. После этого можно продолжить сборку, как это описано выше.
Ошибки компиляции
Однозначный ответ на вопрос: <<что делать при ошибках компиляции?>> -
пожалуй, дать довольно сложно. Опять же, могу направить к чтению
handbook'а, в котором есть несколько советов на эту тему. Приведу
несколько примеров ошибок и возможных путей их решения:
* При сборке порта выводится ошибка о нехватке какой-либо
библиотеки, вместо установки её как зависимости. Возможно, у вас
отсутствует индексный файл портов - ports/INDEX или ports/INDEX-5
(для 5-ой ветки FreeBSD), ports/INDEX-6 (для 6-ой ветки FreeBSD).
Можно скачать индексный файл с сайта -
http://www.freebsd.org/ports/INDEX.bz2, INDEX-5.bz2 или
INDEX-6.bz2. Или просто перейти в ${CHROOTDIR} и собрать требуемый
порт руками, устанавливая каждую зависимость, а затем продолжить
сборку. Переходить в ${CHROOTDIR} нужно с помощью команды chroot,
чтобы порты устанавливались и регистрировались в окружении той
системы, релиз которой вы собираете.
* Какой-то определённый порт не собирается, даже если выполнить
предыдущие рекомендации. Некоторые порты во время сборки
определяют версию системы и в зависимости от неё выбирают
соответствующие параметры сборки приложения, либо по версии
системы выбирается, какие зависимости имеет порт. Система портов
определяет версию через переменные ядра. Поэтому, хоть сборка
порта и происходит в chroot-окружении, где все бинарные файлы и
исходные коды от нужной версии ОС, для системы портов версия ОС
будет той, в которой вы собираете релиз. Это следует помнить, так
как версия системы влияет и на выбор индексного файла, и на то,
какой файл будет скачиваться при выполнении make fetchindex, и
какой файл будет генерироваться при выполнении make index . Это
ограничение можно обойти, если определить переменные OSVERSION и
OSREL. Формат OSVERSION можно посмотреть в переменной ядра
kern.osreldate, OSREL - определяется по первым цифрам вывода
<<uname -r>>. Подробнее всё это можно узнать, просмотрев скрипты в
каталоге ports/Mk. Эти переменные можно поместить в
${CHROOTDIR}/etc/make.conf, тогда они будут использоваться при
каждом запуске make в chroot-окружении.
Прочие ошибки
Искать решение других ошибок вам придётся, видимо, самим... Можно
попытаться обратится в один из списков рассылки или форум, посвящённый
FreeBSD. Расскажу только об одной ошибке, не относящейся к предыдущим
пунктам. Я столкнулся с ней, когда попытался собрать релиз 4-ой ветки,
находясь в 5-ой. Ошибка возникает, когда система пытается создать
загрузочную область и образы загрузочных дискет. В 5-ой версии было
убрано псевдоустройство vn(4) и утилита vnconfig(8), их функционал
перенесён в драйвер md(4) и mdconfig(8). Да, и ещё в 5-ой версии
используется devfs.
Итак, как решить проблему по созданию релиза 4-ой версии FreeBSD в
окружении 5-ой? Не скажу, что способ правильный, но он рабочий, по
пунктам:
* Нужно определить в make.conf переменные OSVERSION и OSREL в
значение, которое они должны иметь в создаваемом релизе.
* Собираем мир, устанавливаем его и после завершения этапа release.2
прерываем сборку. Добавляем аналогичные опции в
${CHROOTDIR}/etc/make.conf. Это необходимо для корректной сборки
портов. Продолжаем сборку релиза.
* После завершения этапа release.7 сборка должна прерваться с
ошибкой в скрипте doFS.sh. Теперь нужно статически собрать утилиту
mdconfig, чтобы исключить все зависимости от разделяемых
библиотек. Для этого понадобятся исходные файлы текущей системы
(той в которой происходит сборка релиза), переходим в каталог
src/sbin/mdconfig и запускаем команду <<make -DNOSHARED depend
all>>. В каталоге obj/usr/src/sbin/mdconfig будет статически
скомпилированная утилита mdconfig. Копируем её в
${CHROOTDIR}/sbin/. Монтируем файловую систему devfs -
<<mount_devfs devfs ${CHROOTDIR}/dev>>. Теперь можно продолжить
сборку релиза.
Я не проверял, будет ли этот способ работать при сборке релиза 5-ой
версии FreeBSD, находясь в окружении 4-ой, но не вижу причин, по
которым сборка может не удастся. Различие только в том, что собирать
нужно будет не mdconfig, а vnconfig и вместо монтирования devfs
создавать файлы устройств с помощью скрипта /dev/MAKEDEV.
Приступим к сборке
Процесс сборки релиза опишу именно так, как делаю его я. Начальные
данные:
* Рабочий сервер, у которого есть доступ в Интернет, на нём
находится CVS-репозитарий и каталог distfiles с дистрибутивами для
сборки портов.
* Ещё один сервер, на котором я ставлю эксперименты, он находится
внутри локальной сети без доступа в Интернет.
* Доступ к CVS-репозитарию осуществляется по NFS.
* Собирать буду FreeBSD 5.3-STABLE, т.е. с CVS-тэгом RELENG_5.
Подготовка
# cd /usr/home
# mkdir release
# mount_nfs -o rdonly server:/usr/home/cvs /mnt
# cvs -Rd /mnt/ncvs co -Pr RELENG_5 src
# cd src/
# mv /etc/make.conf /etc/make.conf.old
# make -j8 buildworld
# cd release/
# vim start.sh
После сборки мира я создаю скрипт, примерно со следующим содержанием:
-j8 -максмальное количество make процессов, которое может работать
параллельно (сервер у меня двухпроцессорный, со SCSI RAID-5);
RELEASENOUPDATE - это на будущее (чтобы не забыть), для цели
"release" эта переменная не используется. NFS каталог
server:/usr/ports/distfiles можно примонтировать сейчас в
/usr/ports/distfiles, но можно и потом.
Сборка релиза
Теперь можно запускать сборку релиза: sh start.sh. После получения
исходных файлов системы и дерева портов из CVS, можно прервать сборку
и примонтировать distfiles:
# mount_nfs -o rdonly server:/usr/ports/distfiles /usr/home/release/usr/ports/distfiles
# vim start.sh
В файле start.sh исправляем цель release на rerelease и запускаем sh
start.sh. Теперь можно заняться своими делами, но переодически
посматривать за процессом сборки. Если каких-то портов не будет
хватать, я запускаю на server'е make fetch-recursive для нужного порта
и после завершения снова запускаю start.sh. Когда процесс завершится,
вы увидите надпись "make rerelease for i386 finished ...".
Перед сборкой ISO образов в 5-ой версии FreeBSD необходимо создать
пакеты xorg и perl5. Если делать всё "по правилам", то для создания
пакетов должен использоваться отдельный сервер, так как других лишних
серверов у меня в наличии нет, я использую этот же. Технология такая:
* В chroot-окружении создаются необходимые пакеты вместе со всеми
зависимостями, при помощи make package-recursive.
* По имеющимся пакетам создаётся файл INDEX.
* Каталог packages копируется в ${CHROOTDIR}/R/cdrom/disc1/.
По первым двум пунктам вроде вопросов быть не должно, а вот о создании
файла INDEX расскажу подробнее. Я использовал для его создания свой
скрипт, поэтому не заметил, как в версии 5.3 появился скрипт
src/release/scripts/mkpkgindex.sh. Мой скрипт выглядит так:
Итак, для минимального дистрибутива нужны пакеты perl и xorg, создаём
их и копируем на <<будущий>> диск:
# mkdir /usr/home/release/usr/ports/packages
# cp mkindex.pl /usr/ports/packages
# chroot /usr/home/release
# cd /usr/ports/lang/perl5.8 && make package-recursive
# cd /usr/ports/x11/xorg && make package-recursive
# cd /usr/ports/x11/xorg-manpages && make package-recursive
# cd /usr/ports/packages
# ./mkindex.pl
# rm mkindex.pl
# cp -PRv /usr/ports/packages /R/cdrom/disc1/
# exit
Теперь можно создавать ISO образы, исправляем файл start.sh, добавив
переменную MAKE_ISOS=yes, и запускаем start.sh. Установится порт
cdrtools и создадутся два образа диска. На этом всё.
Заключение
В заключение хотелось бы упомянуть о возможностях создания
нестандартного дистрибутива, имеющихся в сборочных скриптах релиза
системы. В первую очередь - это настройка sysinstall при помощи
конфигурационного файла install.cfg. На эту тему в Интернете можно
найти множество статей, ну и конечно же не надо забывать про мануал
sysinstall(8).
Так же, есть возможность применения сторонних патчей к
исходным файлам системы во время создания релиза. Обратите внимание на
переменные LOCAL_PATCHES, PATCH_FLAGS и LOCAL_SCRIPT в мануале release(7).
Ну и если вам необходимо что-то действительно необычное,
обратите внимание на сборочные скрипты таких проектов, как Frenzy,
FreeSBIE, LiveBSD.
Материал не может быть воспроизведен в какой бы то ни было форме и
какими бы то ни было средствами без письменного разрешения автора.