Пользователь
0,0
рейтинг
27 декабря 2012 в 16:29

Администрирование → Бездисковая загрузка по сети и жизнь после нее из песочницы

История


Однажды к нам пришли (ну, не сами...) серверы с 14 хардами по 2Тб. Избавившись от аппаратного рейда (зачем — вопрос отдельный), мы задумались о том, что неплохо бы сделать для них загрузку по сети, дабы избавиться от возни с разделами. Диски предполагалось экспортировать по iSCSI, и не хотелось выделять какие-то диски на Особенные Системные Диски, а какие-то на всё остальное. Таким образом возникла задача сделать загрузку по сети с размещением корневого каталога в оперативной памяти.

Теория


По сути, для того, чтобы система загрузилась ей необходимо 3 компонента — ядро, начальное окружение initramfs и корневой каталог, в котором система будет работать.

Практика


Все действия проводятся на машине с ubuntu precise.

PXE

Для начала настроим PXE. Мануалов на эту тему уйма, поэтому я расскажу только самую суть.
Ставим ваш любимый dhcp сервер, например isc-dhcp-server, который будет раздавать машинкам ip адреса и указывать путь к файлу pxelinux.0, который будет отдавать tftp сервер (tftp-hpa или же atftp).
aptitude install isc-dhcp-server tftpd-hpa

Пример конфига dhcp сервера. В примере pxe-сервер находится по адресу 10.0.0.1.
option domain-name-servers 8.8.8.8;
server-name "pxe";

subnet 10.0.0.0 netmask 255.255.255.0 {
        range dynamic-bootp 10.0.0.2 10.0.0.10;
        option subnet-mask 255.255.255.0;
        option routers 10.0.0.1;
        option root-path "10.0.0.1:/var/lib/tftpboot/";

        filename "pxelinux.0";
}


Запускаем tftp сервер (в ubuntu он имеет init-скрипт, но вполне вероятно, что вам придется запускать его и через inetd/xinetd).
Проверяем работоспособность. Кладем файл в каталог /var/lib/tftpboot и пробуем стянуть его tftp клиентом.

tftp 10.0.0.1
tftp> get pxelinux.0


В принципе неважно, где вы возьмете файл pxelinux.0, так как он является просто начальным загрузчиком, в который мы передаем то, что надо грузить дальше.
Вы можете сделать красивую менюшку в загрузчике, но сейчас нам это не нужно, поэтому мой pxelinux.cfg/default выглядит так

default vesamenu.c32
aprompt 1
timeout 2
label ubuntu 12.04
menu label Ubuntu precise
kernel vmlinuz
append initrd=initrd.img boot=ram rooturl=http://10.0.0.1/rootfs.squashfs ip=dhcp


rootfs

Образ rootfs собираем через debootstrap, чрутимся в него и ставим необходимые программы. Настраиваем сеть, hostname, фаервол и прочее, чем больше сделаем настроек, тем больше будет образ. Главное не забудьте сменить пароль на рута.

mkdir -p /mnt/rootfs
debootstrap precise /mnt/rootfs/ http://mirror.yandex.ru/ubuntu/
chroot /mnt/rootfs /bin/bash
aptitude install vim 
...

С нашим минимальным набором система получилась весом 200Мб.

Initramfs

В этом примере мы будем забирать образ корневой фс с веб-сервера, расположенного на нашем сервере сетевой загрузки, то есть на 10.0.0.1. Решение было таким просто потому, что в нашем initramfs была утилита wget. Чтобы не тянуть большой объем данных по сети, мы решили сжать образ. Это можно было бы сделать и обычным tar, но можно попробовать squashfs, тем более, что обычно в initramfs tar не встроен, с другой стороны, ничего не мешает его туда добавить.

Squashfs
Squashfs — это сжимающая файловая система, которая включена в ядро с версии 2.6.29. С ее помощью можно заархивировать каталог, примонтировать на loop устройство и читать с него, для записи же необходимо провести процедуру добавления файлов в архив. Так как при обращении к squashfs, вы читаете из архива, то это дает дополнительную нагрузку на cpu.

 mksquashfs /mnt/rootfs/ rootfs.squashfs -noappend -always-use-fragments
 du -hs rootfs.squashfs 
 92M	rootfs.squashfs

Для более эфферктивного сжатия вы можете использовать опцию -comp, чтобы установить тип сжатия, по умолчанию используется gzip.

Далее надо научить init из initramfs забирать образ корня и помещать его в оперативную память.

init в initramfs — это скрипт на sh, который производит разбор опций из cmdline, монтирует фс, делает switch_root и запускает гланый init-процесс системы.
Воспользуемся этим и допишем свои опции для cmdline. Напишем скрипт ram, который будет вызываться при значении опции boot=ram.

vim /usr/share/initramfs-tools/scripts/ram

#!/bin/bash
retry_nr=0

do_rammount()
{
        log_begin_msg "Configuring networking"
        configure_networking
        log_end_msg

        log_begin_msg "Downloading rootfs image"
        mkdir -p /tmp/squashfs
        wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
        log_end_msg

        log_begin_msg "Mounting rootfs image to /mnt/squashfs"
        mkdir -p /mnt/squashfs
        mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs /mnt/squashfs
        log_end_msg

        log_begin_msg "Mounting tmpfs and copy rootfs image"
        mkdir -p ${rootmnt}
        mount -t tmpfs -o size=1G none ${rootmnt}
        cp -r -v /mnt/squashfs/* ${rootmnt} || exit 2
        log_end_msg

        log_begin_msg "Umount squashfs"
        umount /mnt/squashfs || exit 2
        log_end_msg
}
mountroot()
{
        for x in $(cat /proc/cmdline); do
                case $x in
                rooturl=*)
                        export rooturl=${x#rooturl=}
                        ;;
                esac
        done

        log_begin_msg "Loading module squashfs"
        modprobe squashfs
        log_end_msg        # For DHCP
        modprobe af_packet

        wait_for_udev 10

        # Default delay is around 180s
        delay=${ROOTDELAY:-180}

        # loop until rammount succeeds
        do_rammount

        while [ ${retry_nr} -lt ${delay} ] && [ ! -e ${rootmnt}${init} ]; do
                log_begin_msg "Retrying rammount"
                /bin/sleep 1
                do_rammount
                retry_nr=$(( ${retry_nr} + 1 ))
                log_end_msg
        done
}


Через параметр rooturl можно указывать откуда качать образ корневой фс. Для работы со squashfs необходимо подгрузить ее модуль в ядро. Указываем в /etc/initramfs-tools/initramfs.conf BOOT=ram и пересобираем initramfs

mkinitramfs -o /var/lib/tftpboot/initrd.img


Включаем машинку, на которой будем тестировать, и смотрим на происходящее. После успешной загрузки мы получили бездисковую систему, которая занимает в памяти около 300Мб, при этом мы может писать в нее, но после ребута, система вернется в свое первоначальное состояние.

В это примере, мы использовали squashfs просто для сжатия образа, но почему бы нам не попробовать примонтировать корневой раздел в squashfs и не посмотреть, что получится? Меняем наш скрипт, в функции do_rammount() оставляем только монтирование squashfs.

do_rammount()
{
        log_begin_msg "Configuring networking"
        configure_networking
        log_end_msg

        log_begin_msg "Downloading rootfs image"
        mkdir -p /tmp/squashfs
        wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
        log_end_msg

        log_begin_msg "Mounting rootfs image to /mnt/squashfs"
        mkdir -p /mnt/squashfs
        mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs ${rootmnt}
        log_end_msg

}


Пересобираем initramfs, запускаем, смотрим. Система загружается в режиме ro, но зато занимает в памяти всего около 180Мб.
В каких-то случаях монтирование в режиме ro это хорошо, но нас это не устраивает, но и просто так тратить оперативную память нам тоже не хочется. Выход же был найден при помощи Aufs.

Aufs
Aufs позволяет делать каскадно-объединённое монтирование файловых систем — одну в режиме только на чтение, а вторую в rw. Работает она в режиме copy-on-write, то есть все изменения записываются на rw систему и после этого чтение производится с нее же.
Опять переписываем наш скрипт.
В фукнцию mountroot() добавляем
        log_begin_msg "Loading module aufs"
        modprobe aufs
        log_end_msg


А фукнцию do_rammount() приводим к следующему виду:
do_rammount()
{
        log_begin_msg "Configuring networking"
        configure_networking
        log_end_msg

        log_begin_msg "Downloading rootfs image"
        mkdir -p /tmp/squashfs
        wget ${rooturl} -O /tmp/squashfs/rootfs.squashfs
        log_end_msg

        log_begin_msg "Mounting rootfs image to /mnt/ro"
        mkdir -p /mnt/ro
        mount -t squashfs -o loop /tmp/squashfs/rootfs.squashfs /mnt/ro
        log_end_msg

        log_begin_msg "Mounting tmpfs to /mnt/rw"
        mkdir -p /mnt/rw
        mount -t tmpfs -o size=1G none /mnt/rw
        log_end_msg

        log_begin_msg "Mounting aufs to /mnt/aufs"
        mkdir -p /mnt/aufs
        mount -t aufs -o dirs=/mnt/rw=rw:/mnt/ro=ro aufs /mnt/aufs
        log_end_msg

        [ -d /mnt/aufs/mnt/ro ] || mkdir -p /mnt/aufs/mnt/ro
        [ -d /mnt/aufs/mnt/rw ] || mkdir -p /mnt/aufs/mnt/rw

        mount --move /mnt/ro /mnt/aufs/mnt/ro #сдвигаем точку squashfs монтирования в aufs
        mount --move /mnt/rw /mnt/aufs/mnt/rw #сдвигаем точку монтирования tmpfs в aufs 

        mount --move /mnt/aufs ${rootmnt} #сдвигаем точку монтирования aufs в ${rootmnt}
}


Пересобираем initramfs, запускаем, смотрим. Система занимает в памяти 181Мб, при этом мы можем менять ее, писать, читать. Все изменения хранятся отдельно в /mnt/rw, а сама система хранится в /mnt/ro.

В результате мы получили систему, которая грузится по сети, занимает небольшой объем в памяти, при этом после каждой перезагрузки пропадают все изменения (поэтому надо заранее собирать все нужные продукты жизнедеятельности системы в надежное место).

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

Ссылки


Ubuntu boot to ram
Squashfs home page
PXE
Татьяна @Invariant
карма
21,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (40)

  • +3
    Спасибо, познавательно! Интересно было бы провернуть подобное с FreeBSD.
    • 0
      Вообще без проблем.
      Тонкость была только одна, в имя загрузчика, который грузился по сети, пришлось добавить в конец псевдосимвол, который, уже не помню по какой причине, запрашивался по PXE.
  • +2
    А почему образ храните в RAM?
    Я реализовал сетевую загрузку с помощью pxe+nfsroot(ro)+aufs+init-скрипт. Обошелся без initrd. Работает на 30+серверах и 30+ офисных компах. Образы, конечно же, разные.
    NFS в целом удобнее — нет ограничений на размер, удобнее обновлять.
    • 0
      Было бы интересно почитать относительно реализации. Не оформите?
      • 0
        Давно собирался, но, видимо, так никогда и не соберусь. Если есть конкретные вопросы, то попробую ответить.
        • 0
          Конкретно интересует формирование образа системы с загрузкой посредством pxe, с которого будет возможность нормально пользоваться флешками, подключатся по RDP и расшаривать локально подключенные принтеры/МФУ. Т.е. все то, что должно было бы работать в thinstation, но стабильно и без костылей…
          • 0
            У нас на десктопах не совсем thinstation. Нормальные мощные компы, всё работает локально, /home монтируется локально, а остальное по сети в RO.
            Есть и thinstation для RDP, но новый админ настраивал без меня и взял какое-то готовое решение.
            • 0
              > /home монтируется локально, а остальное по сети в RO
              как устанавливаете новый софт?
    • +2
      Храним в RAM, чтобы не беспокоиться о том, отвалится у нас сеть или нет. В вашем случае, если поломается nfs-сервер, то будет грустно…
      • 0
        По опыту — если отвалится сеть, то система продолжает работать, ибо уже загруженное в память никто насильно не выгрузит. Но с другой стороны — зачем работающий сервер, у которого отвалилась сеть?
        А отдельно nfs-сервер ни разу не падал.
        • +1
          Сеть может моргнуть, например. может отвалиться на пару минут. Да что угодно может случиться.
          • +1
            Еще раз: если отваливается сеть, то всё продолжает работать. В крайнем случае при желании системы что-то прочитать и наличии опции hard, система будет ждать ответа сервера. Да, «неприятно», но при отвалившейся сети это уже второстепенно.
            Дабы прояснить ситуацию: я нисколько не настаиваю на nfsroot, просто делюсь мнением и опытом. С initrd+wget+squashfs+aufs тоже дело имел, но не понравилось.
            • +1
              а что не понравилось?
              Мы такую схему использовали и вполне удачно, интересно, какие проблемы у людей возникают)
              • 0
                1) Самое главное: ограничение на размер. К примеру, офисный образ весит около 7Гб (несколько IDE, браузеры, офис и прочее).
                2) Поддержка. Актуально для десктопов, на серверах другие законы :)
                Мне достаточно поменять конфиг в файле, доустановить пакет и не надо ничего переупаковывать и перезагружаться.
                • 0
                  Ясно. Для ваших задач, я думаю самое оно. У нас они были совсем другие)
                • 0
                  Вы сами ответили на все свои вопросы. Это решение для небольшого образа (200-300Мб), который крутится на сервере, а он в свою очередь должен работать, даже если патч-корд поломался, а дцшник спит и никак не может его заменить, Другой вопрос это как сделать так, чтобы это не порушило все остальное (можно грузить систему по отдельному интерфейсу, если средства позволяют), но зато тут я уверена, что сервер будет работать и без сети.
        • +2
          Когда упадёт NFS — станете делать по другому?
          Падает всё. Нет исключений.
          • +2
            Когда упадет nfs — поднимется копия виртуалки с nfs-сервером на другом хосте. А как я уже сказал, серверы не заметят подмены.
            • 0
              Так сразу говорите, что у вас построен отказоустойчивый NFS.
              Кроме того, получится всё равно не очень красиво. Из-за падения отдельного NFS-стораджа виртуалка (и видимо далеко не одна...) почувствует hard-reboot (или я вас вновь плохо понимаю из-за недостатка информации).

              upd: я понял, кажется. вы храните сам NFS-сервер на виртуалке. Ок, решение как решение. Только автор как раз указывает, что он с помощью сетевой загрузки создаёт распределенное хранилище.
              • 0
                Нет-нет-нет, никакого ребута. Просто клиенты «висят» на чтении.

                NFS сервер живет на вируталке и обеспечивает загрузку других 30+ серверов. Что не так?

                Так сразу говорите, что у вас построен отказоустойчивый NFS.

                Разговор про сетевую загрузку, а не про отказоустойчивость :)
                • 0
                  Эм.
                  Окей, у вас отказоустойчивая NFS-шара в виде виртуалки. Её локальным диском является некоторый распределенный блочный сторадж.
                  Зачем же тогда возиться с NFS, когда можно просто использовать iSCSI сразу к блочному стораджу, монтировать файловую систему в ro, и поднимать aufs поверх этой файловой системы? Получите то же самое (много места, нормальная гибкость), только без промежуточного звена в виде виртуалки, предоставляющей NFS.
                  • 0
                    У нас нет iSCSI. И вообще почти все сервера бездисковые.
                    • 0
                      Виртуалка с NFS поверх чего работает? Не на святом же духе.
                      Если то, поверх чего работает виртуалка с NFS, не отказоустойчиво, то у всё равно когда упадет это самое «то» и все ваши загруженные по сети машины умрут.
            • 0
              только если это pNFS4 или выше, иначе будет очень неприятно клиентам…
              • 0
                Не замечал недовольства nfs-клиентов при перезагрузке системы с nfs-сервером.
    • +1
      Действительно, у вас просто пока не «моргала» сеть…
    • +2
      Если NFS сервер отвалился в момент ожидания возврата из write/read, то процесс-обработчик уснёт непробудным сном. Как побочный эффект будет мёртвый mount в худшем случае до ближайшего ребута.

      Да и вообще появляется лишняя сущность, сильно зависимая от погоды в сегменте сети, что есть нехорошо.
  • +1
    >NFS в целом удобнее — нет ограничений на размер, удобнее обновлять.
    Если падает сеть, nfs отваливается. Если у вас на nfs root, то привет.
  • 0
    Вот есть проект для терминал сервера с загрузкой посети (тонкий и толстый клиенты) ltsp.org/. Возможно будет немного меньше велосипедов. Но есть ограничение по дистрибутивам.
    • 0
      Мой велосипедик маленький, простой и сделан для того, чтобы убежать от nfs.
      • 0
        Все сводится к «ресурсы выделяемые на поддержку» данного решения. А это уже Вам решать.
        • 0
          Спасибо за участие, но это решение не для терминального сервера, который думает за клиента, это просто способ загрузиться по сети, погасить интерфейс и спокойно работать дальше, а диски в сервере полностью отведены под хранение данных.
  • 0
    А что хостит эти 14 дисков? СХД же какая-нибудь наверняка. Не логичнее ли грузится сразу с iSCSI? Если образ системы весит 200МБ (да хоть 1GB) расход места на загрузочные тома ничтожен, а геморрою меньше, да и сложность системы поменьше, а следовательно мест для ошибки и траблшутинга, если что, тоже меньше. А то что сеть моргает, так у меня статистически железо в серверах летит чаще, чем сеть моргает.
    • 0
      Предназначение этих дисков — собрать raid10 и экспортировать этот md том наружу по iSCSI. Диски стоят в простом толстом сервере, это не готовая промышленная СХД.
      • 0
        Т.е. одним разделяемым LUN-ом весь раздел «как есть»?
        Тогда в принципе понятно.
        • 0
          да, ОС не должна «жить» на этих дисках.
  • 0
    Не вижу смысла сжимать в SquashFS, разница пусть даже в 500 Мбайт занятой оперативки для современного сервера вообще ни о чём. Зато куда проще будет обновлять файлы и не потребуется AuthFS.
    • 0
      Там описаны разные вариации и никто не настаивает на том, что надо использовать именно squashfs.
  • +1
    А можно было просто грузиться с флешки =)
    Но с сетевой загрузкой есть свои плюсы, безусловно.
    • +1
      Угу, особенно речь идет о некотором количестве серверов в нескольких удаленных датацентрах, с флешки, да )

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.