Осторожно! Многобукафф!
Это четвертая и главная часть длинного повествования об одном исследовании, цели которого:
1. Автоматизация процесса установки и переустановки.
2. Определение оптимального разбиения диска.
3. Определение оптимальной процедуры установки.
Здесь рассматривается Автоматическая установка FreeBSD 10 на ZFS.
Рассмотрим внимательно процесс загрузки дистрибутива.
Сначала загрузчик (описание LOADER.4TH и сценарий LOADER.RC) показывает нам меню (сценарий MENU.RC), описанное в нескольких файлах.
SHORTCUTS.4TH — указывает что отобразить
BEASTIE.4TH — описывает псевдографику «демона».
BRAND.4TH - «прорисовка» бренда (слово FreeBSD).
VERSION.4TH – версии.
MENU.4TH, MENU_COMMANDS.4TH, MENUSETS.4TH — меню.
По результату выполнения сценария меню происходит загрузка.
После загрузки ядра и непосредственно операционной системы с дистрибутива выполняется сценарий \distrib\ETC\RC.LOCAL (еще в монопольном режиме), где и описано первое меню операционной системы (если нет /etc/installerconfig): Install – запускается Bsdinstall, Shell – открывается строка, также в монопольном режиме, LiveCD – выходим из однопользовательского режима в многопользовательский в среде LiveCD. Пользователь один — root с пустым паролем.
/etc/installerconfig – это список параметров автоматической установки и сценарий послеустановочных операций, которые выполнятся без всяких вопросов.
Но нам эта схема не подходит, мы хотим выполнить всю установку без bsdinstall, с помощью нашего скрипта. Поэтому наш скрипт (назовем его instscr.sh) мы поместим в /etc дистрибутива, а в rc.local добавим несколько строк перед запуском этого меню (строка if [ -f /etc/installerconfig ]; then), первые строки, где определяется тип терминала мы не трогаем.
Вставленный код:
if [ -f /etc/instscr.sh ]; then
/bin/sh -xv /etc/instscr.sh
exit 0
fi
параметр —xv поставлен для принудительного вывода в терминал команд и результатов для отладки. В «боевой» версии скрипта его можно убрать.
Пара слов о создании собственного дистрибутива FreeBSD. По непонятным мне причинам UltraIso не смог внедрить нужные файлы в ISO установочного диска FreeBSD. Возможно потому, что это была пробная версия программы. После долгого поиска бесплатной утилиты я решил не заморачиваться, а
1) на тестовом серваке FreeBSD установил инструменты записи CD (/usr/ports/sysutils/cdrtools),
2) смонтировал официальный дисрибутив в /mnt
mount_cd9660 /dev/cd0 /media
3) скопировал содержимое в подготовленную папку ~/distr
4) сделал скрипт на запуск формирования дистрибутива из папки, состоящий из одной строки
#!/bin/sh
mkisofs -V 10_1_RELEASE_AMD64_CD -J -R -b boot/cdboot -no-emul-boot -o ~/FreeBSD10_2.iso ~/distr
5) все изменения мы вносим в дистрибутив в каталоге ~/distr, запускаем скрипт и по окончанию его работы забираем готовый образ установочного диска из домашнего каталога.
В начале скрипта мы попробуем определить имена устройств жесткого диска и сетевой платы. Если кто знает способ проще и надежней — пишите.
iface=`dmesg | grep Ethernet | awk -F: ' { print ($1) } '`
dev=`camcontrol devlist | awk -F\( ' $2!~/cd/ { print($2) } ' | awk -F, ' { print($1) } '`
При определении жесткого диска из списка мы удаляем CD привод, а из оставшихся берем первый попавшийся. Поэтому, если у Вас в системе больше одного жесткого диска, либо воткнута флэшка — возможно, что система установится не туда, куда хотелось бы.
Далее мы будем использовать эти переменные.
По окончании работы скрипт предупредит о необходимости изъять установочный диск из привода. Обращаю Ваше внимание на то, что этот диск без всяких вариантов удаляет все на имеющемся диске и устанавливает новую систему, поэтому важно соблюдать осторожность и не уничтожить действующую машину случайным запуском. Если не вынуть диск из привода, с каждым запуском будет происходить установка при условии, что первым в BIOS стоит наш диск.
Также мы добавим несколько строк для выполнения некоторых послеустановочных настроек.
В установленной системе создаем файл /etc/rc.local. Этот файл содержит только команду на запуск послеустановочного скрипта, который запустится при первом запуске до выхода в многопользовательский режим (до появления приглашения ко входу пользователя):
cat << EOF > /mnt/etc/rc.local
#!/bin/sh
/bin/sh -xv /etc/postinstall.sh
EOF
А вот создание этого скрипта:
cat << EOF > /mnt/etc/postinstall.sh
#!/bin/sh
sed -I -e 's/KOI8-R/UTF-8/g' /etc/login.conf
cap_mkdb /etc/login.conf
echo 'Passw0rd' | pw usermod root -h 0
echo 'fff' |pw useradd fff -h 0 -G wheel -L russian
pw usermod -n root -L russian
rm /etc/rc.local
rm /etc/postinstall.sh
EOF
С помощью sed меняем кодировку с KOI8-R на UTF8, затем пересоздаем базу, меняем пароль root, создаем пользователя, руту также назначаем русский язык, и удаляем все эти файлы, чтоб они не выстрелили при следующем запуске. Теперь система будет полностью готова к тому, что мы зайдем на этот сервер по ssh с нормальным UTF-8 терминалом. Русский язык, на мой взгляд, root-у тоже нужен, иначе после выполнения su мы увидим вместо папок и файлов с русскими именами всякие закорючки.
Смысл всего этого действа в том, что нам необязательно присутствовать около сервера. Достаточно выслать дистрибутив (по почте или по tftp, через netboot), который все сделает сам, мы зайдем на готовый сервер и настроим его, как надо. Либо при установке большого числа одинаковых серверов такой дистрибутив сэкономит нам немного сил и времени.
Полностью скрипт:
#!/bin/sh -xv
echo " This script will install FreeBSD in unattended mode."
echo " Please be patient."
########### var
#dev="da0"
#iface="m0"
iface=`dmesg | grep Ethernet | awk -F: ' { print ($1) } '`
dev=`camcontrol devlist | awk -F\( ' $2!~/[cd|md|fd]/ { print($2) } ' | awk -F, ' { print($1) } '`
honame="FreeBSDtest11.seczone.ru"
########### gpart
gpart destroy -F $dev
kldload zfs
sysctl vfs.zfs.min_auto_ashift=12
gpart create -s GPT $dev
gpart add -s 512 -a 4k -t freebsd-boot -l boot0 $dev
gpart add -s 4g -a 4k -t freebsd-swap -l swap0 $dev
gpart add -a 4k -t freebsd-zfs -l disk0 $dev
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 $dev
########### zpool
zpool create -f -m /mnt zroot /dev/gpt/disk0
zpool set bootfs=zroot zroot
zfs set mountpoint=/mnt zroot
zpool export zroot
zpool import -o cachefile=/tmp/zpool.cache zroot
zfs create zroot/usr
zfs create zroot/usr/home
zfs create zroot/var
zfs create zroot/data1
zfs create -o compression=gzip zroot/data2
zfs create -o compression=lzjb zroot/tmp
zfs create -o compression=lzjb zroot/usr/ports
zfs create zroot/usr/local
zfs create zroot/usr/local/www
zfs create -o compression=lzjb zroot/usr/src
zfs create -o compression=lzjb zroot/usr/obj
zfs create -o compression=lzjb zroot/var/crash
zfs create zroot/var/db
zfs create zroot/var/log
zfs create -o compression=gzip zroot/var/mail
zfs create -o compression=lzjb zroot/var/tmp
########## prepare
swapon /dev/gpt/swap0
chmod 1777 /mnt/tmp
chmod 1777 /mnt/var/tmp
cd /mnt ; ln -s usr/home home
######### install
echo "install ..."
cd /usr/freebsd-dist
#fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.0-RELEASE/src.txz
#fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.0-RELEASE/base.txz
#fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.0-RELEASE/kernel.txz
cat base.txz | tar --unlink -xvpJf - -C /mnt
cat kernel.txz | tar --unlink -xvpJf - -C /mnt
cat src.txz | tar --unlink -xvpJf - -C /mnt
echo "install ok"
cp /tmp/zpool.cache /mnt/boot/zfs/zpool.cache
########## tuning
cat << EOF > /mnt/etc/rc.conf
dumpdev="AUTO"
zfs_enable="YES"
hostname=$honame
ifconfig_$iface="inet 192.168.1.103 netmask 255.255.255.0"
defaultrouter="192.168.1.1"
sshd_enable="YES"
EOF
cat << EOF > /mnt/boot/loader.conf
zfs_load="YES"
EOF
cat << EOF > /mnt/etc/resolv.conf
nameserver 78.108.68.68
nameserver 78.108.68.108
EOF
cat << EOF > /mnt/etc/postinstall.sh
#!/bin/sh -xv
sed -I -e 's/KOI8-R/UTF-8/g' /etc/login.conf
cap_mkdb /etc/login.conf
echo 'Passw0rd' | pw usermod root -h 0
echo 'fff' |pw useradd fff -h 0 -G wheel -L russian
pw usermod -n root -L russian
rm /etc/rc.local
rm /etc/postinstall.sh
EOF
cat << EOF > /mnt/etc/rc.local
#!/bin/sh -xv
/bin/sh -xv /etc/postinstall.sh
EOF
cat << EOF > /mnt/etc/fstab
# Device Mountpoint FStype Options Dump Pass#
/dev/gpt/swap0 none swap sw 0 0
EOF
zfs umount -a
zfs set mountpoint=legacy zroot
zfs set mountpoint=/data1 zroot/data1
zfs set mountpoint=/data2 zroot/data2
zfs set mountpoint=/tmp zroot/tmp
zfs set mountpoint=/usr zroot/usr
zfs set mountpoint=/var zroot/var
echo "Please remove install media"
echo "AFTER system shutdown"
sleep 30
shutdown -p now
Однако при установке на BIOS с поддержкой UEFI внезапно наступил на грабли. BIOS не может найти загрузочную запись в файловой системе zfs на GPT разделе.
Согласно мануалу (https://www.freebsd.org/cgi/man.cgi?query=uefi&sektion=8&manpath=FreeBSD+10.2-stable) имеем проблему:
“Переменные окружения EFI не поддерживаются в загрузчике или ядре.
Boot1.efi загружает loader.efi с первой файловой системы freebsd-ufs, которую он находит, даже если она располагается на другом диске.
Boot1.efi не может загрузить loader.efi с файловой системы zfs. В результате UEFI не поддерживает расположение файловой системы root в конфигурации zfs.”
Все, приплыли.
Поясню глубину фэйла. Мы хотели просто накатывать втихую FreeBSD на любую систему, имея только загрузочный раздел, своп и zfs, а UEFI требует наличие msdos раздела (причем, не все UEFI могут прочитать msdos раздел, созданный FreeBSD, разработчики рекомендуют использовать Fat16 или даже Fat12), на котором будет лежать загрузчик. К тому же загрузчик boot1.efi будет искать loader.efi на ufs разделе, таким образом наш zfs будет третьим в зоопарке систем на диске, при этом он не будет загрузочным. И последнее, если мы так настроим диск, тогда не-EFI системы не смогут загрузиться с этого диска. Таким образом, прежде чем приступить к установке мы должны определиться, будет ли система с обычным BIOS, или EFI. От этого зависит способ нарезки диска и порядок установки. Мы не сможем использовать один универсальный линейный способ, подходящий для разных систем. Добавляет неразберихи то, различные производители материнских плат используют отличающиеся способы реализации efi загрузчиков. В общем, пока нет сколько-нибудь универсального и надежного способа установки FreeBSD на GPT раздел. Если мы имеем на диске MBR, тогда даже EFI системы используют эмуляцию BIOS и грузят ось «по старинке» (либо автоматически, либо указваем руками параметр Legacy в настройках EFI). Некоторые материнские платы пользователю указать даже для GPT разделов Legacy режим загрузки. Тогда система, установленная по схеме из предыдущей главы, запустится нормально.
Итог: для реализации красивой и универсальной установки нам надо подождать, пока выйдут подходящие версии системы, а пока мы можем ставить FreeBSD только на Legacy BIOS.