С появлением FreeBSD 5.2.1 отличия в настройках сервера бездисковых клиентов относительно ветки 4.x стали настолько значительны, что даже потребовалось обновлять соответствующую статью handbook. Причем в статье эти изменения были проведены сравнительно недавно, так что на образе инсталляционного диска FreeBSD-5.2.1-Release, записанного 25.02.2004, оказалась уже безнадежно устаревшая, применимая в лучшем случае к FreeBSD 5.1, версия документа. Кроме того, поскольку handbook ограничен размерами, а материал по этой теме весьма объемый, то в соответствующей статье handbook многое описано довольно поверхностно, и сам алгоритм построения сервер-бездисковая система теряется в дебрях вариантов реализаций, технологий и описаний особенностей разных версий FreeBSD.
Поэтому, стараясь не упустить из поля зрения все многообразие вариантов, я сосредоточился на описании только одного из способов настройки машины FreeBSD-5.2.1-Release для работы в качестве сервера бездисковых клиентов. И чтобы сохранить четкость изложения в своей статье, разбираю весь процесс на конкретном примере.
Поскольку я ограничиваюсь лишь конкретным вариантом, следует выдвинуть некоторые условия. Главное, что способ, разбираемый в моей статье несколько отличается от канонического варианта, который описан в handbook и для которого написаны rc-файлы в дистрибутиве FreeBSD. В разбираемых примерах бездисковые станции не будут располагать свои файловые системы в виртуальной памяти, вместо этого они будут пользоваться NFS. Это относится к файловым системам, которые будут монтироваться как "только для чтения" (например, / и /usr), так и для "чтения-записи" (/etc и /var). Кроме того, для бездисковых станций будут написаны свои rc-скрипты.
Во всех примерах будет использоваться сервер FreeBSD-5.2.1-Release с IP-адресом 192.168.1.2/24, hostname: server. На этой машине будут настроено следующее программное обеспечение:
Если это не оговорено отдельно, все программное обеспечение устанавливается из портов.
Бездисковым станциям выделен диапазон адресов 192.168.1.10-192.168.1.254. Имя хоста - hostname формируется по следующему правилу: diskless-<последний октет IP-адреса станции>. Так, бездисковой станции (Intel Pentium-90, 16Mb RAM, Сетевой адаптер Intel EtherExpress-100 с поддержкой PXE), выбранной для примеров, присвоен IP-адрес 192.168.1.101/24 и hostname: diskless-101.
Суть загрузки бездисковой системы по сети в том, чтобы на этапе загрузки машины передать ей по сети ядро FreeBSD. Handbook в связи с этим упоминает два способа:
Оба варианта: PXE и etherboot пользуются BOOTP или DHCP, посредством которых получают необходимую информацию о сетевых адресах. Разница между этими способами заключается в том, что etherboot, используя TFTP или NFS, целиком выкачивает с сервера и загружает ядро FreeBSD, а PXE вначале по протоколу TFTP получает несравнимо меньшую по размерам программу pxeboot, которая затем уже сама по NFS или TFTP обеспечивает загрузку ядра системы.
Поскольку опыт показывает, что в настоящее время становится значительно проще купить новую сетевую карту с поддержкой спецификации PXE, чем перепрограммировать старую, то способы загрузки бездисковых клиентов с применением etherboot или netboot я оставляю за пределами рассмотрения своей статьи. Скажу только, что etherboot гораздо легче, чем netboot настроить для загрузки ядра FreeBSD, а PXE, в свою очередь, еще проще, поскольку вообще не требуется устанавливать дополнительного программного обеспечения.
Далее ядро ОС бездискового клиента монтирует корень своей файловой системы на NFS-ресурсе сервера и вызывает /sbin/init (или то, что его может заменить init.bak, oinit, sysinstall), монтирует devfs в каталог /dev, выполняет скрипт /etc/rc и для соответствующих терминальных устройств из файла /etc/ttys порождает процессы getty.
Скрипт /etc/rc, который завершает цикл загрузки и запускает основные демоны системы, стоит отметить отдельно. Для данного способа загрузки бездисковых клиентов, скрипт /etc/rc важен еще и тем, что входе его выполнения будет произведена "подмена" одной из файловых систем. Дело в том, что ради экономии места на диске сервера, корневую файловую систему мы сделаем общей для всех бездисковых клиентов, поэтому логичнее всего монтировать ее в режиме "только для чтения". Соответственно, каталог /etc для всех бездисковых станций окажется, к сожалению, одним и тем же и к тому же будет доступен только для чтения. Поэтому, чтобы обеспечить гибкость создания индивидуальных для каждого клиента директорий /etc, заложим в rc-скрипт операцию по монтированию каждой бездисковой станции своего /etc, доступного для чтения и записи. Аналогичных целей можно добиться, применив стандартные rc-скрипты FreeBSD. Однако, в этом случае /etc будет размещаться в виртуальной памяти компьютера, что на мой взгляд не очень хорошо, поскольку для бездисковых станций основным, и часто дефицитным ресурсом является как раз оперативная память. По этому вариант с виртуальной памятью я рассматривать не буду, подробнее о нем можно узнать, изучив скрипты загрузки FreeBSD 5.2.1 /etc/rc.d/initdiskless и /etc/rc.d/diskless.
Как можно догадаться, настройка самой бездисковой станции требует минимальных усилий и заключается лишь в установке в ее корпус сетевой карты с поддержкой спецификации PXE. Далее, в зависимости от конкретных особенностей оборудования станции, остается указать только правильный порядок загрузки, т.е. выбрать загрузку с LAN. Это обычно делается либо в BIOS компьютера, либо в меню самой сетевой карты. На тестовой станции, BIOS которой, не поддерживал загрузку по сети, мне пришлось проводить настройку через меню сетевой карты. Для того чтобы попасть в меню сетевой карты потребовалось на этапе загрузки компьютера нажать Crtl+S.
Теперь становится очевидным, что поскольку все основные работы по конфигурированию бездисковых станций придется выполнять на сервере, то в первую очередь необходимо настроить сам сервер.
Настройка сервера бездисковых станций FreeBSD заключается в установке следующих сервисов: NFS, DHCP и TFTP. Очередность конфигурирования этих служб для конечного результата неважна однако, следуя логике загрузки бездискового клиента, установим следующий порядок: DHCP, TFTP, NFS.
Установка самой ОС сервера производится обычным способом за исключением небольшой детали: в нашем случае, для размещения файловых систем клиента, отводятся две отдельные партиции, одна предназначается "только для чтения", другая для "чтения-записи". В нашем случае мы будем монтировать эти партиции в следующие каталоги корневой файловой системы сервера:
/diskless_ro
/diskless_rw
В последствии эти файловые системы будут с соответствующими правами экспортированы бездисковым клиентам по NFS. Если у читателя нет возможности использовать под файловые системы бездисковых клиентов специально выделенные партиции, все же не следует делать ошибки, размещая их на одной физической файоловой системе сервера. Вместо этого лучше выделить подкаталоги в /usr, /home или /var. Например, если /usr и /var это различные файловые системы сервера, то каталоги клиентов могут быть такими: /usr/diskless_ro и /var/diskless_rw. Такое распределение файлов клиента по разным физическим файловым системам обуславливается особенностями работы NFS часть которых, будет затронута, в описании настройки NFS-сервера.
Первое что необходимо для загрузки бездискового клиента, это обеспечить его информацию об IP-адресе, маске подсети, расположению корневой файловой системы и т.д. Для этих целей потребуется установить BOOTP- или DHCP-сервер.
Поскольку BOOTP в настоящее время успешно вытесняется его более молодым приемником DHCP, ограничимся рассмотрением более современного варианта. А о том, как настроить классический BOOTP-сервер для работы с бездисковыми клиентами, можно прочитать в handbook.
Для настройки сервера DHCP под FreeBSD воспользуемся продуктом ISC DHCP (isc-dhcp3), который также поддерживает и протокол BOOTP. ISC DHCP не входит в дистрибутив FreeBSD, поэтому его придется инсталлировать из пакетов, портов или исходных текстов. Установку из портов можно произвести так:
server# cd /usr/ports/net/isc-dhcp3 && make install clean
Поскольку при описании NFS-сервера мы договорились, что каждому бездисковому клиенту будем предоставлять NFS-ресурс для записи, то время от времени менять IP-адреса бездисковым станциям становится просто не корректно, поэтому в конфигурации DHCP-сервера нам придется отказаться от динамического распределения адресов, и использовать ISC DHCP для клиентов BOOTP.
Основные настройки DHCP-сервера хранятся в файле /usr/local/etc/dhcpd.conf. Редактируем его чтобы составить простую конфигурацию. Поскольку в нашем примере всего одна подсеть и один сервер бездисковых клиентов, можно смело выносить почти всю информацию в раздел глобальных параметров:
authoritative; # Сервер авторитетен для своей подсети
ddns-update-style none; # Отказываемся от динамического обновления DNS
use-host-decl-names on; # выдавать клиентам "hostname", которое указано в поле host
option routers 192.168.1.1; # Укажем маршрутизатор по умолчанию
next-server 192.168.1.2; # Здесь указывается сервер, с которого берется boot-файл
filename "pxeboot"; # Собственно boot-файл, который читается с next-server
option root-path "192.168.1.2:/diskless_ro"; # Здесь будет корень файловой системы клиента
subnet 192.168.1.0 netmask 255.255.255.0 { } # Описываем подсеть. Динамического распределения адресов
# не будет, и здесь тоже не будет никаких опций. Однако, убрать
# описание подсети нельзя, иначе DHCP-сервер не загрузится
# Описания бездисковых станций: для каждого клиента
# указываем имя хоста, его IP и MAC адреса
host diskless-10 { # Имя хоста, которое из-за "use-host-decl-names on" будет
# будет передано клиенту в качестве его hostname
hardware ethernet 00:0D:9D:8B:BB:48; # MAC-адрес сетевой карты бездискового клиента.
fixed-address 192.168.1.10; # IP-адрес, назначаемый клиенту.
}
...
host diskless-101 {
hardware ethernet 00:0C:29:74:2B:35;
fixed-address 192.168.1.101;
}
...
host diskless-254 {
hardware ethernet 00:02:B3:8A:D6:BF;
fixed-address 192.168.1.103;
}
Теперь можно стартовать DHCP-сервер:
server# /usr/local/sbin/dhcpd
И если загрузка прошла удачно, получим подобный ответ:
Internet Software Consortium DHCP Server V3.0.1rc12
Copyright 1995-2003 Internet Software Consortium.
All rights reserved.
For info, please visit http://www.isc.org/products/DHCP
Wrote 0 deleted host decls to leases file.
Wrote 0 new dynamic host decls to leases file.
Wrote 0 leases to leases file.
Listening on BPF/fxp0/00:0c:29:f8:78:fc/192.168.1.0/24
Sending on BPF/fxp0/00:0c:29:f8:78:fc/192.168.1.0/24
Sending on Socket/fallback/fallback-net
Остается только добавить вызов DHCP в автоматическую загрузку сервера:
#server cd /usr/local/etc/rc.d
#server mv isc-dhcpd.sh.sample isc-dhcpd.sh
#server chmod 755 isc-dhcpd.sh
Бездисковый клиент вместе со своим IP-адресом получает от DHCP-сервера еще 3 важных для загрузки параметра:
Параметр root-path потребуется чуть позже при загрузке ядра и монтировании корневой файловой системы. А пока, PXE сетевой карты бездисковой станции, именно два последних, из вышеперечисленных параметров, автоматически попытается использовать для продолжения загрузки. Файл pxeboot (8) является измененной версией загрузчика loader (8), работающего на 3-м этапе загрузки FreeBSD (подробнее о загрузке FreeBSD можно прочитать в handbook). Поскольку бездисковый клиент ожидает получить эту программу по протоколу TFTP, то его следует настроить на сервере 192.168.1.2.
TFTP-сервер во FreeBSD входит в дистрибутив и никакого дополнительного программного обеспечения устанавливать не потребуется. Демон называется tftpd и обычно запускается из inetd. Поэтому для того, чтобы запустить TFTP-сервер, мы просто создадим специальный каталог /tftpboot и запишем туда pxeboot:
server# mkdir /tftpboot
server# cp /boot/pxeboot /tftpboot
зададим соответствующую строку в /etc/inetd.conf:
tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /tftpboot
Здесь опция -l включает логирование операций, -s устанавливает каталог, который является корневым для tftpd после выполнения им вызова chroot(). Подробнее о работе tftpd и системном вызове chroot() можно прочитать в страницах man tftpd(8) и chroot(2).
Сервер настроен, остается только перезапустить демон inetd:
server# killall -HUP inetd
Если все прошло успешно, команда:
server# sockstat -4l| grep 69
Вернет похожий результат:
root inetd 556 5 udp4 *:69 *:*
После того, как загрузчик pxeboot будет успешно скачан по TFTP, он, руководствуясь опцией "root-path" попытается по протоколу NFS обратиться к каталогу /diskless_ro сервера 192.168.1.2, так, как будет считать что, там содержится корневая файловая система с ядром операционной системы бездисковой станции.
Здесь необходимо сделать следующее замечание: что pxeboot может быть также настроен для загрузки ядра по протоколу TFTP, что позволит загружать разным бездисковым станциям разные версии ядер. Правда чтобы это осуществить, необходимо перекомпилировать pxeboot с опцией LOADER_TFTP_SUPPORT= YES, указанной в файле /etc/make.conf сервера. Подробнее об этом см. в handbook и в файле /usr/share/examples/etc/make.conf.
Мы же ограничимся универсальным для всех станций ядром, поэтому возникает необходимость настроить NFS-сервер и экспортировать клиентам соответствующие каталоги сервера. Сделаем общую для всех директорию /diskless_ro доступной режиме "только для чтения", а в /diskless_rw расположим каталоги, индивидуальные для каждого IP-адреса станции, так чтобы каждый бездисковый клиент смог производить туда запись. В таких каталогах для каждой рабочей станции, в свою очередь, необходимо создать поддиректории etc и var. Например, тестовая станция будет иметь собственный каталог: /diskless_rw/192.168.1.101 и два подкаталога /diskless_rw/192.168.1.101/etc и /diskless_rw/192.168.1.101/var. Таким образом, каталог /diskless_ro будет пока пуст а /diskless_rw на этом этапе будет иметь следующую структуру:
/diskless_rw/192.168.1.10
/diskless_rw/192.168.1.10/etc
/diskless_rw/192.168.1.10/var
...
/diskless_rw/192.168.1.101
/diskless_rw/192.168.1.101/etc
/diskless_rw/192.168.1.101/var
...
/diskless_rw/192.168.1.254
/diskless_rw/192.168.1.254/etc
/diskless_rw/192.168.1.254/var
Кроме того, бездисковые станции, в режиме "только для чтения " будут пользоваться серверной файловой системой /usr.
Для того, чтобы разрешить бездисковым станциям беспрепятственно пользоваться всеми этими каталогами, необходимо соответствующим образом настроить NFS-сервер. Для этого в файл /etc/exports необходимо поместить следующие строки:
# Файловые системы доступные для чтения:
/usr -ro -maproot=0 -network 192.168.1.0 -mask 255.255.255.0
/diskless_ro -ro -maproot=0 -network 192.168.1.0 -mask 255.255.255.0
# Файловые системы доступные для записи. Здесь ресурсы
# выделяемые каждой бездисковой станции, описываются одной строкой:
#
# Diskless-10
/diskless_rw/192.168.1.10/etc /diskless_rw/192.168.1.10/var -mapall=root 192.168.1.10
# ...
# Diskless-101
/diskless_rw/192.168.1.101/etc /diskless_rw/192.168.1.101/var -mapall=root 192.168.1.101
# ...
# Diskless-254
/diskless_rw/192.168.1.254/etc /diskless_rw/192.168.1.254/var -mapall=root 192.168.1.254
Теперь меняем /etc/rc.conf, чтобы стартовать NFS-сервер при загрузке системы:
rpcbind_enable="YES"
nfs_server_enable="YES"
Тут следует обратить внимание и при необходимости изменить переменную nfs_server_flags:
nfs_server_flags="-u -t -n 48 -h 192.168.1.2"
Здесь очень важен параметр -n, который определяет количество демонов nfsd, которые обслуживают работу NFS, реально это отражается на числе одновременно подключенных клиентов NFS. Данный параметр следует отрегулировать в зависимости от количества клиентов. Ключи -u и -t включают поддержку соответственно UDP и TCP; -h указывает на привязку к конкретному сетевому интерфейсу.
Теперь, для того, чтобы лишний раз не перезагружать машину стартуем NFS-сервер вручную:
server# rpcbind
server# nfsd -u -t -n 48 -h 192.168.1.2
server# mountd -r
После того, как NFS-сервер загрузился без ошибок, проверим, насколько успешно экспортировались файловые системы:
server# showmount -e
Exports list on localhost:
/usr 192.168.1.0
/diskless_rw/192.168.1.103/var 192.168.1.254
/diskless_rw/192.168.1.103/etc 192.168.1.254
...
/diskless_rw/192.168.1.101/var 192.168.1.101
/diskless_rw/192.168.1.101/var 192.168.1.101
...
/diskless_rw/192.168.1.101/etc 192.168.1.10
/diskless_rw/192.168.1.101/etc 192.168.1.10
/diskless_ro 192.168.1.0
Размещать diskless_rw и diskless_ro на одной физической файловой системе не рекомендуется, поскольку NFS экспортирует клиенту не каталог, а файловую систему целиком. В /etc/exports каждая строка представляет собой описание экспорта одной файловой системы сервера одному или нескольким клиентам. Причем для каждой экспортируемой файловой системы, один и тот же клиент может быть указан только один раз.
Например, если /diskless_rw и /diskless_ro разные файловые системы, то такой /etc/exports будет правильным:
/diskless_rw 192.168.1.101
/diskless_ro -ro 192.168.1.101
Ошибочный вариант /etc/exports:
/usr/diskless_rw 192.168.1.101
/usr/diskless_ro -ro 192.168.1.101
Если diskless_rw и diskless_ro принадлежат одной и той же файловой системе /usr, то при попытке их экспорта одному и тому же клиенту возникнет ошибка, и diskless_ro не будет экспортирован. Правила требуют, чтобы оба ресурса /usr/diskless_rw и /usr/diskless_ro были указаны одной строкой, однако тогда придется выбирать между тем, оставить ли их доступными клиенту "только для чтения" или же разрешить "чтение-запись".
Однако, демон mountd может быть "обманут", если вместо конкретных машин, посредством сетевых масок будут указаны диапазоны адресов. Например, еще один ошибочный вариант /etc/exports, который, тем не менее, будет "успешно" обработан:
/usr/diskless_rw -network 192.168.1.0 -mask 255.255.255.0
/usr/diskless_ro -ro -network 192.168.0.0 -mask 255.255.0.0
В этом случае /usr/diskless_rw и /usr/diskless_ro будут успешно экспортированы. Причем поскольку мы имеем дело не с каталогами, а с файловой системой целиком, то для подсети 192.168.1.0 с маской 255.255.255.0 оба ресурса как /usr/diskless_rw, так и /usr/diskless_ro будут экспортированы с атрибутом rw, т.е. окажутся доступны для чтения и записи, но это не правильно с точки зрения безопасности.
Теперь, когда мы сделали все предварительные настройки сервера, можно заняться конфигурацией бездисковых станций, а именно, подготовим ядро, поместим его файловую систему (состоящую из двух частей: доступной "для чтения" и доступной "для чтения и записи") и напишем скрипты загрузки.
Как уже было сказано выше, pxeboot будет ожидать, что NFS-ресурс 192.168.1.2:/diskless_ro является корневой файловой системой, и поэтому попытается найти на ней ядро. При загрузке бездискового клиента с использованием pxeboot можно вполне обойтись и ядром GENERIC, однако оно включает в себя много лишних драйверов, но не содержит нескольких удобных BOOTP-опций. Следовательно, нам необходимо скомпилировать свое ядро DISKLESS, чтобы затем вместе с другими файлам разместить его на файловой системе клиента.
Компилируем ядро привычным способом, изменяя GENERIC и убирая из ядра все, что по нашему мнению является лишним. Главное, чтобы там осталось:
options NFS_ROOT
options NFSCLIENT
Можно обойтись без, но очень полезно добавить в ядро следующие опции, которые не присутствуют в GENERIC:
options BOOTP
options BOOTP_NFSROOT
options BOOTP_COMPAT
Включение этих опций вызовет дополнительный диалог с DHCP-сервером по определению IP-адресов бездискового клиента. Однако иначе мы не сможем по BOOTP передавать клиенту такие приятные вещи как hostname. Как отмечено в handbook, можно еще добавить options BOOTP_NFSV3 и BOOTP_WIRED_TO, но это уже по вкусу.
Следующее ядро, было успешно опробовано на нескольких бездисковых станциях:
machine i386
cpu I486_CPU
cpu I586_CPU
cpu I686_CPU
ident DISKLESS
options SCHED_4BSD #4BSD scheduler
options INET #InterNETworking
options FFS #Berkeley Fast Filesystem
options SOFTUPDATES #Enable FFS soft updates support
options UFS_ACL #Support for access control lists
options UFS_DIRHASH #Improve performance on big directories
options MD_ROOT #MD is a potential root device
options NFSCLIENT #Network Filesystem Client
options NFS_ROOT #NFS usable as /, requires NFSCLIENT
options CD9660 #ISO 9660 Filesystem
options PROCFS #Process filesystem (requires PSEUDOFS)
options PSEUDOFS #Pseudo-filesystem framework
options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!]
options KTRACE #ktrace(1) support
options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
options KBD_INSTALL_CDEV # install a CDEV entry in /dev
device isa
device pci
device fdc
# ATA and ATAPI devices
device ata
device atadisk # ATA disk drives
device atapicd # ATAPI CDROM drives
options ATA_STATIC_ID #Static device numbering
# atkbdc0 controls both the keyboard and the PS/2 mouse
device atkbdc # AT keyboard controller
device atkbd # AT keyboard
device psm # PS/2 mouse
device vga # VGA video card driver
device splash # Splash screen and screen saver support
# syscons is the default console driver, resembling an SCO console
device sc
device agp # support several AGP chipsets
# Floating point support - do not disable.
device npx
# Add suspend/resume support for the i8254.
device pmtimer
# Serial (COM) ports
device sio # 8250, 16[45]50 based serial ports
# Parallel port
device ppc
device ppbus # Parallel port bus (required)
device lpt # Printer
# PCI Ethernet NICs.
device miibus # MII bus support
device fxp # Intel EtherExpress PRO/100B (82557, 82558)
# Pseudo devices - the number indicates how many units to allocate.
device random # Entropy device
device loop # Network loopback
device ether # Ethernet support
device pty # Pseudo-ttys (telnet etc)
device md # Memory "disks"
options BOOTP
options BOOTP_NFSROOT
options BOOTP_NFSV3
options BOOTP_COMPAT
Поскольку бездисковая станция отличается от обычной машины, лишь тем, что имеет файловые системы на NFS-ресурсе, то для ее успешной загрузки необходимо воссоздать, почти без изменений, дерево каталогов FreeBSD. Исходя из того, что на сервере мы для этих целей выбрали каталоги /diskless_ro и /diskless_rw, то все файлы будут располагаться именно там.
Сначала подготовим каталог /diskless_rw и отложим его, поскольку он будет использоваться только в конце загрузки бездискового клиента.
Директория /diskless_rw предназначена для хранения индивидуальных файловых систем всех клиентов и, после установки NFS-сервера, организована по следующему правилу: /diskless_rw/IP-адрес-станции/rw-файловая-система. Например, для тестового бездискового клиента были созданы следующие каталоги:
server# mkdir /diskless_rw/192.168.1.101
server# mkdir /diskless_rw/192.168.1.101/etc
server# mkdir /diskless_rw/192.168.1.101/var
Это сделано для того, чтобы каталоги /diskless_rw/IP-адрес-станции/etc и /diskless_rw/IP-адрес-станции/var монтировались в качестве /etc и /var бездискового клиента. Такое размещение каталогов позволяет выделить каждой бездисковой станции индивидуальные каталоги, предназначенные для чтения и записи.
Далее, в var и etc необходимо создать еще ряд подкаталогов (etc/pam.d etc/X11 и var/log, var/run, var/tmp, var/home), которые все равно потребуются для работы машины. Поэтому выполняем:
server# mkdir /diskless_rw/192.168.1.101/etc/pam.d
server# mkdir /diskless_rw/192.168.1.101/etc/X11
server# mkdir /diskless_rw/192.168.1.101/var/home
server# mkdir /diskless_rw/192.168.1.101/var/log
server# mkdir /diskless_rw/192.168.1.101/var/run
server# mkdir /diskless_rw/192.168.1.101/var/tmp
Таким образом деревья каталогов etc и var на тестовой бездисковой станции, будут выглядеть так:
/diskless_rw/192.168.1.101
/diskless_rw/192.168.1.101/etc
/diskless_rw/192.168.1.101/etc/pam.d
/diskless_rw/192.168.1.101/etc/X11
/diskless_rw/192.168.1.101/var
/diskless_rw/192.168.1.101/var/home
/diskless_rw/192.168.1.101/var/log
/diskless_rw/192.168.1.101/var/tmp
/diskless_rw/192.168.1.101/var/run
Поскольку, во FreeBSD 5.2.1 был убран код, позволяющий во время загрузки передать ядру по BOOTP информацию, о том где располагается swap-файл бездисковой станции, будем размещать swap-файл каждого клиента в его же файловой системе:
dd if=/dev/zero of=diskless_rw/192.168.1.101/swap bs=1k count=32000
Аналогичные действия должны быть произведены для каждой бездисковой станции.
Подробнее, о файловом составе всех этих каталогов, и о том, как обеспечить нормальную работу раздробленных /etc и /var поговорим чуть позже.
Директория /diskless_ro предназначена для размещения корневой файловой системы бездисковой станции. Здесь нам потребуются следующие каталоги: bin, boot, dev, etc, lib, libexec, mnt, sbin, usr и var.
Директории bin, lib, libexec и sbin содержат основные библиотеки и программы FreeBSD поэтому, возьмем эти каталоги без изменений из файловой системы сервера:
server# cp -r /bin /lib /libexec /sbin /diskless_ro
Далее, создадим еще директорию usr, куда в дальнейшем по NFS будет монтироваться каталог /usr с сервера:
server# mkdir /diskless_ro/usr
Затем, следует подготовить каталог /boot бездисковой станции и разместить там ядро. Сделаем его из соответствующей директории сервера, и скопируем туда заранее скомпилированное ядро DISKLESS:
server# cp -r /boot /diskless_ro
server# cp /sys/i386/compile/DISKLESS/kernel /diskless_ro/boot/kernel
При использовании такой конфигурации у меня возникали проблемы при загрузке некоторых бездисковых станций. Часть этих машин мне удалось победить, убрав из загрузки boot4th и составив свой loader.rc. Ели вы, вместе со мной решились на этот шаг, то:
server# cd /diskless_ro/boot
server# rm *.4th
Избавившись от boot4th мы, к сожалению, одновременно лишимся и автоматической подгрузки device.hints. Избежать этой проблемы можно двумя путями:
Из-за того, что старое оборудование капризно, то иногда требуется довольно много времени на его конфигурацию, и поэтому чтобы обеспечить более гибкие настройки параметров ядра стоит пользоваться именно вторым вариантом.
Поскольку те значения, которые записаны в device.hints являются обыкновенными переменными ядра, нужные из их мы можем включить в виде set variable="value" в файл loader.rc. Тогда loader.rc будет выглядеть так:
set hint.fdc.0.at="isa"
...
boot /boot/kernel/kernel
Здесь последняя строка loader.rc, указывает, какое ядро следует загружать.
Проще всего компиляцию loader.rc проводить так, а затем просто убрать лишние переменные ядра:
server# cd /diskless_ro/boot
server# awk '{print "set "$1}' device.hints > loader.rc
server# echo "boot /boot/kernel/kernel" >> loader.rc
Например, меня выручал такой loader.rc:
set hint.fdc.0.at="isa"
set hint.fdc.0.port="0x3F0"
set hint.fdc.0.irq="6"
set hint.fdc.0.drq="2"
set hint.fd.0.at="fdc0"
set hint.fd.0.drive="0"
set hint.fd.1.at="fdc0"
set hint.fd.1.drive="1"
set hint.ata.0.at="isa"
set hint.ata.0.port="0x1F0"
set hint.ata.0.irq="14"
set hint.ata.1.at="isa"
set hint.ata.1.port="0x170"
set hint.ata.1.irq="15"
set hint.atkbdc.0.at="isa"
set hint.atkbdc.0.port="0x060"
set hint.atkbd.0.at="atkbdc"
set hint.atkbd.0.irq="1"
set hint.atkbd.0.flags="0x1"
set hint.psm.0.at="atkbdc"
set hint.psm.0.irq="12"
set hint.vga.0.at="isa"
set hint.sc.0.at="isa"
set hint.sc.0.flags="0x100"
set hint.vt.0.at="isa"
set hint.vt.0.disabled="1"
set hint.apm.0.disabled="1"
set hint.apm.0.flags="0x20"
set hint.sio.0.at="isa"
set hint.sio.0.port="0x3F8"
set hint.sio.0.flags="0x10"
set hint.sio.0.irq="4"
set hint.sio.1.at="isa"
set hint.sio.1.port="0x2F8"
set hint.sio.1.irq="3"
set hint.ppc.0.at="isa"
set hint.ppc.0.irq="7"
boot /boot/kernel/kernel
Теперь device.hints на файловой системе клиента больше не нужен, и его можно удалить. Кроме того, каталог defaults, содержащий loader.conf теперь тоже не имеет смысла, поэтому смело выполняем:
server# cd /diskless_ro/boot
server# rm -r defaults device.hints
Стоит отметить, что иногда очень полезно выключить загрузку модуля ACPI. Бывают случаи, когда бездисковые станции просто отказываются загружаться с включенным ACPI, однако, возможна и обратная ситуация, когда бездисковые клиенты не смогут загрузиться без модуля ACPI, см. acpi (4). Отключить ACPI можно выставив переменную hint.acpi.0.disabled="1".
Вариант для device.hints:
hint.acpi.0.disabled="1"
Аналогичная запись для loader.rc выглядит так:
set hint.acpi.0.disabled="1"
На этом с директорией /boot наконец покончено.
Далее, каталог dev необходим для монтирования файловой системы devfs, на которой располагаются все файлы устройств FreeBSD. Если случайно не создать эту директорию, бездисковая станция после загрузки ядра, без всяких ошибок просто остановится во время запуска процесса init. Следовательно:
server# mkdir /diskless_ro/dev
Позаботимся также заранее о пустом каталоге var, куда в дальнейшем по NFS будет монтироваться доступная для чтения и записи директория var из соответствующего подкаталога /diskless_rw с сервера 192.168.1.2:
server# mkdir /diskless_ro/var
Кроме того, чтобы не создавать отдельные файловые системы для home и tmp бездискового клиента, сделаем символьные линки /home -> /var/home и /tmp -> /var/tmp, которые будут обеспечивать доступ в каталоги, доступные для чтения и записи:
server# cd /diskless_ro
server# ln -s /var/tmp .
server# ln -s /var/home .
Далее, необходимо создать и заполнить каталог etc. Поскольку он будет располагаться на /diskless_ro, то есть, будет общим для всех и доступен только "для чтения", сделаем его содержимое универсальным и компактным. Он будет состоять всего из нескольких обязательных файлов. Часть из них (services, netconfig и login.conf) возьмем из файловой системы сервера:
server# mkdir /diskless_ro/etc
server# cp /etc/services /etc/netconfig /etc/login.conf /diskless_ro/etc
Затем, чтобы иметь возможность индивидуально настроить каждую бездисковую станцию, применим один нехитрый трюк: воспользуемся тем, что процесс init во время загрузки машины запускает /etc/rc и во время работы этого скрипта, смонтируем поверх diskless_ro/etc файловую систему из diskless_rw/etc. Для этого напишем собственный etc/rc, который тоже следует разместить в /diskless_ro/etc:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin; export PATH
boot_ip=`kenv boot.netif.ip`
mount -t nfs 192.168.1.2:/diskless_rw/${boot_ip}/etc /etc
mount -t nfs 192.168.1.2:/diskless_rw/${boot_ip}/var /var
swapon /var/swap
rm -rf /var/tmp/*; rm -rf /var/tmp/.*;
. /etc/rc2
exit 0
Этот простейший скрипт последовательно выполняет следующие действия:
Таким образом, записывая в каталог /diskless_rw/IP-адрес-станции/etc нужные файлы и редактируя файл rc2 в этой же директории, осуществляется конфигурация каждой станции с конкретным IP-адресом. Чтобы такая станция продолжила загрузку, ей потребуются, как минимум, следующие файлы в этой директории:
auth.conf
disktab
fstab
gettytab
group
hosts
login.access
login.conf
login.conf.db
master.passwd
netconfig
protocols
pwd.db
rc
rc2
services
spwd.db
syslog.conf
termcap -> /usr/share/misc/termcap
ttys
Почти все эти файлы можно скопировать из каталога /etc сервера в /diskless_rw/192.168.1.101/etc без изменений. Исключения составят только несколько файлов:
Начнем с fstab, который для станции с IP-адресом 192.168.1.101 будет выглядеть так:
# Device Mountpoint FStype Options Dump Pass
192.168.1.2:/diskless_ro / nfs ro 0 0
192.168.1.2:/diskless_rw/192.168.1.101/etc /etc nfs rw 0 0
192.168.1.2:/diskless_rw/192.168.1.101/var /var nfs rw 0 0
192.168.1.2:/usr /usr nfs ro 0 0
Скрипт /etc/rc уже есть в корневой системе бездискового клиента, поэтому:
server# cp /diskless_ro/etc/rc /diskless_rw/192.168.1.101/etc
Далее, редактируем rc2:
#!/bin/sh
mount -a
/sbin/ldconfig -elf /usr/lib/compat /usr/X11R6/lib /usr/local/lib
syslogd
exit 0
Скрипт rc2, на который возложено продолжение загрузки бездискового клиента, последовательно выполняет следующие действия:
Зададим конфигурацию syslogd. Для этого редактируем /etc/syslog.conf бездискового клиента, т.е. для тестовой станции этот файл будет /diskless_rw/192.168.1.101/etc/syslog.conf. Здесь может быть множество вариантов, рассмотрим два из них. Все системные отчеты syslogd отправляет на сервер 192.168.1.2:
*.* @server
или укажем демону syslogd направлять все отчеты в /var/log/all.log файловой системы клиента:
*.* /var/log/all.log
Если был выбран второй вариант, то предварительно необходимо создать файл var/log/all.log с соответствующими правами:
server# touch /diskless_rw/192.168.1.101/var/log/all.log
server# chmod 600 /diskless_rw/192.168.1.101/var/log/all.log
Если же был выбран первый, необходимо убедиться, что на сервере 192.168.1.2 демон syslogd запущен с ключом -a. Например:
syslogd -a 192.168.1.0/24
Далее если требуется локализация системы необходимо добавить несколько строк в rc2 и отредактировать ttys. Так, для того, чтобы включить поддержку русского языка (koi8-r) добавляем в rc2 следующие команды:
kbdcontrol < /dev/ttyv0 -l "ru.koi8-r"
vidcontrol < /dev/ttyv0 -l "koi8-r2cp866"
vidcontrol < /dev/ttyv0 -f 8x16 "cp866-8x16"
vidcontrol < /dev/ttyv0 -f 8x14 "cp866-8x14"
vidcontrol < /dev/ttyv0 -f 8x8 "cp866-8x8"
и приводим соответствующую модификацию ttys, т.е. меняем для всех виртуальных терминалов тип консоли с cons25 на cons25r, например для ttyv0 строка будет выглядеть так:
ttyv0 "/usr/libexec/getty Pc" cons25r on secure
После всех этих действий, можно смело включать бездисковые станции, и они загрузятся, и будут прекрасно работать. Однако здесь возникают несколько подводных камней, о которых стоит предупредить.
Файлы аутентификации были взяты с сервера, и теперь все имена пользователей и их пароли на сервере и всех клиентах совпадают. Скорее всего, такое положение вещей вас не устраивает, поэтому для каждого клиента редактируем master.passwd с тем, чтобы убрать от туда всех лишних пользователей и оставить root с home-каталогом "/ " и пустым паролем. Например, так:
root::0:0::0:0:Charlie &:/root:/bin/csh
toor:*:0:0::0:0:Bourne-again Superuser:/root:
daemon:*:1:1::0:0:Owner of many system processes:/root:/sbin/nologin
operator:*:2:5::0:0:System &:/:/sbin/nologin
bin:*:3:7::0:0:Binaries Commands and Source:/:/sbin/nologin
tty:*:4:65533::0:0:Tty Sandbox:/:/sbin/nologin
kmem:*:5:65533::0:0:KMem Sandbox:/:/sbin/nologin
games:*:7:13::0:0:Games pseudo-user:/usr/games:/sbin/nologin
news:*:8:8::0:0:News Subsystem:/:/sbin/nologin
man:*:9:9::0:0:Mister Man Pages:/usr/share/man:/sbin/nologin
sshd:*:22:22::0:0:Secure Shell Daemon:/var/empty:/sbin/nologin
smmsp:*:25:25::0:0:Sendmail Submission User:/var/spool/clientmqueue:/sbin/nologin
mailnull:*:26:26::0:0:Sendmail Default User:/var/spool/mqueue:/sbin/nologin
bind:*:53:53::0:0:Bind Sandbox:/:/sbin/nologin
uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/libexec/uucp/uucico
pop:*:68:6::0:0:Post Office Owner:/nonexistent:/sbin/nologin
www:*:80:80::0:0:World Wide Web Owner:/nonexistent:/sbin/nologin
nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/sbin/nologin
test:$1$nkgb9jxT$a5ZgR4DUgOIUJGBg3.gJr.:1001:1001::0:0:test:/home/test:/bin/sh
Теперь перестроим базу паролей:
pwd_mkdb -d /diskless_rw/192.168.1.101/etc /diskless_rw/192.168.1.101/etc/master.passwd
После этих операций надо не забыть отредактировать файл etc/group (например, /diskless_rw/192.168.1.101/etc/group) и создать с необходимыми правами в директории var/home (/diskless_rw/192.168.1.101/var/home) домашние каталоги оставшимся пользователям.
Далее, поскольку мы настроили систему таким образом, что пользователи хранят свои домашние каталоги в файловых системах бездисковых станций (директория /var/home и символьная ссылка /home -> /var/home), то при такой ситуации пользователь, пересевший за другую станцию, не сможет получить доступ к своим файлам, оставленным на предыдущей машине. Решением этой проблемы может стать экспорт каталога /home с сервера на все бездисковые станции. Например, соответствующая запись /etc/exports сервера может быть такой:
/home -network 192.168.1.0 -mask 255.255.255.0
Следовательно, в fstab каждой станции надо будет добавить:
192.168.1.2:/home /home nfs rw 0 0
И наконец, не забыть заменить ссылку /home -> /var/home настоящим каталогом /home:
server# cd /diskless_ro
server# rm /home
server# mkdir /home
Однако следует учитывать, что экспорт по NFS домашних каталогов всех пользователей может быть потенциально не безопасен.
Если возникла необходимость в системе X-window, то можно пойти как минимум двумя путями. Первый - использовать скрипт startx, и запускать X-window целиком на бездисковой станции, или второй - настроить xdm и пользоваться ресурсами сервера. Для обоих вариантов потребуется загрузка демона мыши. Для тестовой станции, у которой мышь была подключена к порту com2, демон moused вызывается так:
/usr/sbin/moused -p /dev/cuaa1 -t auto
Поскольку на разных станциях мышь может быть подключена в разные порты, эту команду для каждого бездискового клиента надо модифицировать и поместить в скрипт /etc/rc2, для автоматического выполнения при загрузки системы.
Рассмотрим сначала первый способ. При этом варианте X-window на сервере устанавливается и настраиваются обычным образом. Каждому бездисковому клиенту в каталоге /etc/X11 помещается индивидуальный XF86Config. Соответственно для тестовой станции с IP-адресом 192.168.1.101 этот файл на сервере располагается в каталоге /diskless_rw/192.168.1.101/etc/X11.
На бездисковом клиенте в этом случае X-window стартует командой startx. Кроме того, если необходимо обеспечить доступ к Microsoft Windows Terminal Server, то на сервер FreeBSD устанавливается программа rdesktop, которая поддерживает протокол RDP:
server# cd /usr/ports/net/rdesktop
server# make install clean
После этого, чтобы автоматически запускать rdesktop при загрузке системы X-window, каждому пользователю бездисковой системы в их домашних каталогах можно создать файлы .xsession или .xinitrc, содержащие вызов:
rdesktop -f mswinserver
Здесь, опция -f указывает, что нужен полноэкранный режим работы, а mswinserver имя или IP-адрес сервера Microsoft Windows Terminal Server.
Второй способ, основанный на протоколе XDMCP, удобнее в том случае, если множеству пользователей необходимо настроить доступ к UNIX-серверу, для того чтобы дать им возможность работать с графическими приложениями. В этом случае, на бездисковой станции создается такой же файл XF86Config, как и при первом варианте, однако требуется дополнительная конфигурация сервера, для работы xdm.
На сервере редактируется файл /usr/X11R6/lib/X11/xdm/xdm-config, который может быть например таким:
DisplayManager.errorLogFile: /var/log/xdm.log
DisplayManager.pidFile: /var/run/xdm.pid
DisplayManager.keyFile: /usr/X11R6/lib/X11/xdm/xdm-keys
DisplayManager.servers: /usr/X11R6/lib/X11/xdm/Xservers
DisplayManager.accessFile: /usr/X11R6/lib/X11/xdm/Xaccess
DisplayManager.willing: su -m nobody -c /usr/X11R6/lib/X11/xdm/Xwilling
DisplayManager*authorize: true
DisplayManager*resources: /usr/X11R6/lib/X11/xdm/Xresources
DisplayManager*session: /usr/X11R6/lib/X11/xdm/Xsession
DisplayManager*authComplain: true
Далее файл Xservers будет пустым, Xaccess будет содержать только *, позволяющий на любой машине получить приглашение login. Затем на сервере xdm запускается командой:
server# xdm
Вызов xdm полезно оформить в виде xdm.sh и положить в /usr/local/etc/rc.d.
После того, как на сервере xdm успешно стартовал, на бездисковых клиентах X-сервер можно запускать так:
diskless-101# X -query 192.168.1.2
Если при старте бездисковой станции необходимо обеспечить автоматическую загрузку X-window, эту команду следует поместить в скрипт rc2 каждого бездискового клиента.