понедельник, мая 14, 2007

Как сделать маленький LiveCD "вручную"

Я сделал уже второй livecd, правда этот - уже совсем специального назначения - для развертывания системы из образа. Так что у меня выработалась некая технология изготовления таких микро-дистрибутивов.
Пакеты я беру из своего debian etch (а шо? много уже скомпилированного софта). Но я считаю, что на liveCD система управления пакетами вроде apt совершенно ни к чему. Поэтому перед установкой в создаваемую систему я конвертирую deb-пакеты в обычные тарболлы (.tar.gz), благо это совсем просто (вот скрипт).
Далее, из идеи о минимальном дистрибутиве сразу следует, что на диске должно быть только то, что необходимо в данном случае. Поэтому начинаем создание livecd с установки самых нужных пакетов. Например, в последнем случае у меня был скрипт-инсталятор, написанный на bash+dialog. Значит, на диске нужны: bash, dialog и их (жесткие) зависимости. Скрипт использует cp с компанией - значит, нужен пакет coreutils.
Зависимости надо как-то отслеживать, не вручную же? В качестве внешней (по отношению к создаваемой системе) базы данных зависимостей я использую базу apt-cache моей рабочей системы.
Все это делается, естественно, скриптами. Вот скрипт, устанавливающий tar.gz в директорию с создаваемой системой. Этот скрипт находит deb-пакет, конвертирует его в tar.gz (используя вышеприведенный deb2targz), и устанавливает его. Наконец, этот скрипт устанавливает сначала зависимости пакета, а потом и сам пакет. Таким образом, пакеты ставятся в систему командой install-depends <имя-пакета>.
Замечание 1: скрипт install-depends устанавливает только непосредственные зависимости пакета. Т.е. если пакет A зависит от B, а B зависит от C, то команда install-depends A поставит пакеты A и B, но не поставит пакет C. Это пока приходится отслеживать вручную. Благо, в маленьких системах таких случаев мало. А для большой системы можно и скрипт поправить (а можно и нормальный пакетный менеджер поставить).
Замечание 2: всем скриптам нужна директория, выделенная под новую систему, и в ней директория с именем packages. Там будут складываться установленные пакеты (deb и tar.gz), и там же будет храниться файл installed.list со списком установленных пакетов - чтобы не устанавливать одно и то же два раза.
Замечание 3: во всех приводимых скриптах перед использованием нужно везде прописать правильные директории, по контексту вроде понятно, какие. Если непонятно - спросите в комментах.
Таким образом, по кусочкам, в выделенной директории оказывается более-менее рабочий вариант системы (по вопросам, какие пакеты надо ставить для того, чтобы работало то или другое, например login, загляните в LFS - полезная книжка). После того, как поставлен bash с зависимостями, в созданную систему можно chroot'нуться (chroot /path/to/live /bin/bash), и работать уже "изнутри".
После установки пакетов понадобится еще кое-какая доводка, чтобы система стала совсем рабочей - написание /etc/fstab, /etc/inittab и еще чего понадобится (в инсталяторе, например, мне ни inittab, ни fstab не понадобились). Сюда же относится написание startup сценариев - тут у вас полная свобода, пишите что вам надо. Для совсем простых систем можно вообще не ставить sysvinit, а в качестве init использовать самописный скрипт на bash.
Таким образом получается система, в которой можно работать как в chroot-среде. Теперь нужно обеспечить ее загрузку. Для этого, прежде всего, нужно ядро.
Можно взять дистрибутивное ядро. Оно сконфигурировано так, чтобы загружаться на чем угодно. Есть у него недостаток - оно модульное, и нужность тех или иных модулей определяется скриптами при каждой загрузке. Скрипты а) выполняются относительно долго и б) сложные, захочешь чего-то сделать по-своему - скорее всего сломаешь. Однако пару "дистрибутивное ядро + скрипты из рабочей системы" я посоветую для тех livecd, которые должны загружаться на совсем разных конфигурациях железа.
Если круг оборудования более определен, можно собрать для него свое ядро. Это окажется необходимо, если загружаться надо на самом распоследнем железе - дистрибутивное ядро его не поддерживает. Это также необходимо, если вы хотите применить к ядру патчи, которых нет в дистрибутивном ядре. Например, в LiveIDE я использую SquashFS, чтоб впихнуть всего побольше.
Для маленьких систем можно собрать монолитное ядро. Это хорошо тем, что ядро само определит все оборудование, какое оно знает, т.е. скрипты для определения оборудования не нужны. Конечно, эта идея не пройдет, если поддерживать нужно очень широкий круг оборудования. Но, например, из ядра для инсталятора я выкинул поддержку звуковых карт, сети и еще много чего - оно в момент установки не нужно.
Для загрузки нужен загрузчик. Я использую isolinux. Настроить его совсем несложно, все описано в документации. В качестве примера настройки можете взять содержимое директории isolinux/ на установочном CD вашего дистрибутива.
Загрузчик загрузит ядро. А ядро, по идее, должно запустить /sbin/init. Но для этого оно должно примонтировать корневую ФС. А где у нас будет корень? CD-ROM не подходит из-за того, что на разных машинах он подключен по-разному - то он /dev/hdb, а то вовсе /dev/scd0. Поэтому на LiveCD в качестве корневой ФС (по крайней мере, на первом этапе загрузки) традиционно используют initrd.
initrd - это файл образа любой ФС, понимаемой ядром (поддержка этой ФС должна быть вкомпилирована в ядро намертво, т.е. не модулем). Можно этот образ пожать при помощи gzip, получив initrd.gz - ядро умеет такие образы распаковывать.
Что класть в initrd? В initrd может быть, как минимум, три варианта:
  • Совсем минимальная система, которая только и делает, что находит диск и монтирует его в качестве "настоящей" корневой ФС;
  • Вся система;
  • Часть системы, способная загрузиться и подмонтировать остальные части системы с cd.
Первый вариант обычно используется в "настольных" системах. Его можно использовать и для livecd, в том случае, если основная (live) система занимает как раз что-то около 500..700Мб. Если система занимает больше - нужно использовать сжатие отдельных частей системы, для того, чтобы с ними работать, нужна уже не совсем тривиальная система.
В LiveIDE у меня используется третий вариант. Директория /usr сжата в образ squashfs, а все остальное находится в initrd.
Для маленьких систем имеет смысл использовать второй вариант - помещение системы в initrd целиком.
Файловая система, находящаяся в памяти имеет следующие преимущества: 1) она доступна на чтение/запись (а cd и squashfs - только на чтение); 2) если, кроме ядра и initrd, с диска ничего не грузится, диск можно достать из привода сразу после загрузки. Ну а недостаток большого initrd очевиден - он занимает много места в памяти.
Для загрузки ядра с initrd в качестве корневой ФС нужна следующая строка в isolinux.cfg:
append initrd=initrd.gz load_ramdisk=1 ramdisk_size=50000 rw root=/dev/ram0
В параметре ramdisk_size нужно указать число, несколько превосходящее размер распакованного initrd.
Если в системе не используется sysvinit, а используется свой init-скрипт, нужно дописать к этой строке что-то вроде "init=/sbin/install-image" .
Теперь создаем образ initrd (например, так: dd if=/dev/zero of=initrd bs=1024 count=40x1024), форматируем его (mkfs.ext2 initrd), монтируем как loop-устройство (mount -o loop initrd /mnt/initrd), кладем туда все, что решили положить, отмонтируем и сжимаем (gzip initrd). Создаем директорию (mkdir output/), из которой будем собирать образ диска, в нее кладем директорию isolinux, создаем директорию isolinux/kernel, туда кладем ядро и initrd. По мере надобности кладем файлы/директории в корневую директорию диска.
Для создания загрузочного iso-образа используем команду вроде следующей
mkisofs -o /path/to/live-image.iso -r -V "My Live CD" -v -no-emul-boot -boot-load-size 4 -boot-info-table -b isolinux/isolinux.bin -c isolinux/isolinux.boot /path/to/output

Конечно, вряд ли все получится с первого раза. Чтобы не пороть кучу cd-болванок, образы можно тестировать под эмулятором (qemu).

ЗЫ. Я в курсе, что это "не совсем дебиан-вей". Это, скорее, слако-вей. Но этот способ гораздо более гибкий.

7 комментариев:

  1. Очень интересный пост, давно хочу собрать свой живой линукс. Буду руководствоваться. Спасибо.

    ОтветитьУдалить
  2. Спасибо, хорошее руководство.

    ОтветитьУдалить
  3. Анонимный10/16/2008 11:11 AM

    Нельзя ли разместить ссылку на миниатюрный LiveCD, который только загружает Ghost 11 и позволяет просто восстановить систему с DWD-RW SATA на HDD SATA?

    ОтветитьУдалить
  4. Анонимный2/05/2010 11:04 AM

    Именно это мы, как правило, и имеем в виду, когда ищем где бы скачать или как бы собрать самому малюсенький компактный LiveCD с минимальным набором (2-3 полезные программки типа Акрониса, Мемтеста, да текстовый редактор типа блокнота, да ещё возможность вырезать, копировать и вставлять нужные файлы из указанного места в указанное место, да в реестре покопаться, да чтобы с имитацией интерфейса WindowsХР. Всё!
    А то куда ни посмотришь - 600 мб, 700 мб!... а недавно увидел совсем "компактный" Линукс, требующий до 5 гб! (или мне что-то не то показалось?)
    Куда столько??? Всего-то и надо мегов 50: загрузиться быстренько с компакт-диска да с файлами на винче поработать - систему поднять. Да хотя бы тот же boot.ini или что-нибудь подобное восстановить - неужели нужно всякий раз загружать всю эту тяжесть на 600 мегов?!

    ОтветитьУдалить
  5. @Анонимный
    >> Именно это мы, как правило, и имеем...

    Мы, амператор всея... не? :D

    ВНЕЗАПНО, первая ссылка в гугле по запросу `linux rescue live cd': http://www.livecdlist.com/ ; Упорядочиваем по размеру... Первым идёт (опять же, внезапно) tomsrtbt размером в 3 метра (собственно, классический его вариант записывается на дискету и занимает соотв. 1,44Mb).

    ОтветитьУдалить
  6. А для имитации интерфейса windows xp я вам ВНЕЗАПНО посоветую... Windows XP! :D

    ОтветитьУдалить