пятница, 10 июня 2011 г.

Установка FreeBSD с корнем на ZFS, используя GPT

В связи с удобством zfs, особенно в части расширения ssd-кэшами, начал переводить сервера на zfs.
warning: не забываем про память! Учитываем, что надо 2+ гига
warning: На i386-arch ставить скорее вредно.. если встанет вообще. Так что только amd64.

Диски пока в основном старые, но для удобства надо бы делать выравнивание. Вообще, под загрузчик надо 62 сектора, но с выравниванием начинать будем или с 64 сектора, или со второго мегабайта. Я выровняю на 1М, 256 блоков=128кб на блоке 512 байт. (интересно, когда можно будет руками задать размер блока через опции, а не патчи кода)

# gpart create -s GPT ad6

# gpart add -b 1M -s 256 -t freebsd-boot ad6

# gpart show ad6
=> 34 625142381 ad6 GPT (298G)
34 2014 - free - (1M)
2048 256 1 freebsd-boot (128k)
2304 625140111 - free - (298G)

Впрочем, размер раздела можно было задать и через -s 128k, с версии 8.0 beta 1 уже понимало ключи размерности.

Дальше нужен своп -- туда идут дампы при падениях, да и работать без свопа вообще -- идея плохая. Размер - если памяти достаточно, и система не на ssd ставится - лучше сделать равным размеру памяти, чтобы полный дамп влез. Место на sata достаточно дешёвое, и даже на sas лишние 10 гиг на фоне сотен штатных -- потеря небольшая. Впрочем, кому как. Главное, не меньше 2 гигов.

Со свопом ещё нюанс: если мы начали свопиться, и вдруг какой-то диск выпадает -- есть огромный шанс словить kernel panic, поэтому надо будет или каким-то образом зеркалировать его, или создавать в файле уже на zfs.

# gpart add -s 4G -t freebsd-swap ad6

Теперь создадим основной раздел

# gpart add -t freebsd-zfs ad6
ad6p3 added

# gpart show ad6
=> 34 625142381 ad6 GPT (298G)
34 2014 - free - (1M)
2048 256 1 freebsd-boot (128k)
2304 8388608 2 freebsd-swap (4.0G)
8390912 616751503 3 freebsd-zfs (294G)

Разметка закончена.
Создадим основной пул.

куда примонтируем, название пула, какие диски
нюанс: у mdadm есть опция missing, что полезно при сборке 1 или 10 рейда без части дисков (если на второй части рабочие данные например). У zfs, насколько я понял, штатно такого не сделать. Или создать sparse-файл размером как диск (даст ли?), и сразу его отключить (zpool offline) и стереть, или создать пул на 1 диск и потом добавить в него второй. Неприменимо для raidz, насколько я знаю - там extend не делался раньше, только переносом пула.
Сделать зеркало из простого диска -- zpool attach (pool) (disk) (new disk)

# zpool create -O atime=off -m /mnt/zfs pool ad6p3

Пора поставить загрузчик.
# gpart bootcode -b /boot/pmbr ad6
bootcode written to ad6

Для выполнения мы должны иметь этот самый /boot/pmbr в основной системе.
PMBR это Protective MBR
Это своеобразная "заглушка", что диск размечен.

Дальше надо записать основной загрузчик.
# gpart bootcode -p /boot/gptzfsboot -i 1 ad6

-i 1 - это первый раздел, который freebsd-boot, в gpart show 3 колонка.

(впрочем, можно написать просто # gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ad6)

Что за файлы есть в /boot и зачем они нужны -- очень хорошо описано тут:
http://bu7cher.blogspot.com/2011/05/freebsd.html

Дальше начинается шаманство, которое называется "разделение пула на датасеты". Тут есть множество схем.
Поскольку созданные разделы делят весь объем диска, не надо долго высчитывать, где сколько места нужно, поэтому имеет смысл создавать по датасету на основные разделы. Вдобавок, это облегчает работу со снапшотами. Хотя меру надо знать. Ну и добавить-удалить раздел не проблема.

# zfs create pool/usr
# zfs create pool/usr/home
# zfs create pool/var
# zfs create -o exec=off -o setuid=off -o readonly=on pool/var/empty
# zfs create -o setuid=off pool/tmp
# chmod 1777 /mnt/zfs/tmp
# zfs create -o compression=on -o exec=off -o checksum=off pool/var/log

Дальше можно создать usr/ports, usr/src, usr/obj, var/db, var/log, var/run, var/mail итд.

Для веб серверов я дополнительно выделяю
# zfs create pool/var/db
# zfs create pool/var/db/mysql
# zfs create pool/var/www

Некоторые говорят - зачем к примеру выделять usr/ports. Кто-то выделяет, чтобы поставить сжатие на порты. Но в данном случае выделяется ради снапшотов usr.

Также не забываем про права. Дело в том, что к примеру /var/db/mysql с дефолтными правами вполне может не заработать.
# chown mysql:mysql /var/db/mysql
# chmod 0700 /var/db/mysql

Имеет смысл рассматривать разделение для перевода основной части системы в read-only, а всё изменяемое снэпшотить.

А теперь накатываем систему.
Тоже много вариантов. Через rsync с основной системой, через make world, с ливсд выполнением пачки install.sh...


# make DESTDIR=/mnt/zfs installkernel KERNCONF=WM8
# make DESTDIR=/mnt/zfs installworld
warning: /tmp должен быть, быть достаточной ёмкости и не содержать опции noexec
Сразу перекинем порты
# portsnap -p /mnt/zfs/usr/ports/ extract
И сорцы
# rsync -avS /usr/src/ /mnt/zfs/usr/src/
Но etc окажется почти пуст.
# make DESTDIR=/mnt/zfs distrib-dirs distribution

Но после перезагрузки пул не найдёт -- надо скопировать информацию о нём
# cp /boot/zfs/zpool.cache /mnt/zfs/boot/zfs/

После этого нужно настроить boot/loader.conf, прописать rc.conf, make.conf, fstab итд.

Сделаем чрут и донастроим
# chroot /mnt/zfs /bin/csh

loader.conf:
## поддержка загрузки
# echo 'zfs_load="YES"' >> /boot/loader.conf
# echo 'vfs.root.mountfrom="zfs:zroot"' >> /boot/loader.conf
##
# echo 'vfs.zfs.prefetch_disable=1' >> /boot/loader.conf

## если памяти меньше гига -- без этих строк будет падать. если больше - лучше не добавлять.
# echo 'vm.kmem_size="330M"' >> /boot/loader.conf
# echo 'vm.kmem_size_max="330M"' >> /boot/loader.conf
# echo 'vfs.zfs.arc_max="40M"' >> /boot/loader.conf
# echo 'vfs.zfs.vdev.cache.size="5M"' >> /boot/loader.conf
##
# echo 'loader_logo="beastie"' >> /boot/loader.conf

Также надо в rc.conf вписать строку для автомонтирования пулов
echo 'zfs_enable="YES"' >>/etc/rc.conf
Без этой строки автомонтирования нет как минимум в обычной системе, когда корень не на zfs.

также надо вписать пользователей, поставить им пароль, пароль руту (а то будет не войти потом), настроить временную зону...

Теперь надо сделать загрузку с pool. Главное - не делать zfs set mountpoint=/ pool - получим error: failed to initialize ZFS library

Я загрузился так:
# загружаемся с ZFS (loader prompt)
load zfs
set vfs.root.mountfrom=zfs:pool
boot
# добавляем в loader.conf(5) поддержку zfs и точку
# монтирования / (корня)
# //после загрузки.
echo zfs_load=YES >>/boot/loader.conf
echo vfs.root.mountfrom=\"zfs:pool\" >>/boot/loader.conf

При этом корректно прописались все пути в пуле. Хотя есть подозрение, что у меня все пути были legacy, а в некоторых доках при создании датасетов им прописывают mountpoint - тогда надо менять.

Есть вариант через
# export LD_LIBRARY_PATH=/mnt/pool/lib
# zfs umount -fa
# zfs set mountpoint=legacy pool
# zfs set mountpoint=/tmp pool/tmp
# zfs set mountpoint=/usr pool/usr
# zfs set mountpoint=/var pool/var
Сделал только 3 первые команды, забыв про /usr - система не загрузилась.

Теперь размечаем второй диск так же, ставим загрузчики.
hint: сделать копию разметки (без данных, надо будет тоже ставить загрузчик итд):
gpart backup /dev/ada0 | gpart restore /dev/ada1
!!! не перепутать диски!
warning: надо сразу проверить, что размеры дисков равны или начинать создание на более "мелком" диске. Иначе потом зеркало будет не создать без ужимания пула.
Видел вариант через cfdisk или fdisk с копированием структуры, но потерял.

Добавим второй (подготовленный) диск в зеркало
# zpool attach pool ad6p3 ad4p3
В данном случае - имя пула, диск в пуле (первый), наш второй диск.

zpool status покажет оба диска, новый будет ONLINE (resilvering)
Ждём окончания и можно работать. Если что - можно выполнить zpool scrub pool, но во фре это занимает весьма много времени. И видим ещё преимущество zfs -- resilvering у меня делался только для данных, это было порядка 50 гигов из 320. Это весьма быстрее, чем для целого диска.

Также соберём зеркало из своп-областей
gmirror label gm0-swap /dev/ad4p2 /dev/ad6p2
Или в варианте через UUID, что даже надёжнее.
Вписываем в fstab полученное зеркало, ребутимся, радуемся.

Использованные материалы (имеет смысл их хотя бы просмотреть)
http://nix-sa.blogspot.com/2011/04/freebsd-zfs-gpt.html
http://www.opennet.ru/tips/info/1844.shtml
http://wiki.opennet.ru/ZFS_%D0%B8_FreeBSD
http://kosmoflyko.blogspot.com/2010/11/freebsd-zfs.html
http://wiki.lissyara.su/wiki/%D0%97%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B0_%D1%81_ZFS-mirror_%D0%BD%D0%B0_GPT_%D0%B2%D0%BE_FreeBSD

Просто полезная дока
http://xgu.ru/wiki/ZFS

3 комментария:

  1. Застрелиться :) Я бы добавил в warning "утилиты типа wipe на самом деле не будут затирать ваши файлы" ( http://habrahabr.ru/qa/8049/ ). Кстати, я ошибаюсь, или в девятке должна появится установка на ZFS?

    ОтветитьУдалить
  2. Если нужно делать wipe - создать шифрованный раздел (который freebsd-ufs), и уже поверх ставить пул. Если надо срочно очистить - wipe-им ключ шифрования раздела и ребутимся. И всё, восстановить раздел не получится даже под пытками.

    ОтветитьУдалить
  3. приятно видеть, что автор указывает источники :)

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