Почти три года назад, я написал статью о создании тонких клиентов (бездисковые машины с загрузкой по сети) под FreeBSD. С той поры утекло много воды, из той организации я уволился, на новом месте этого не потребовалось. А вот на старом - первые-вторые пеньки продолжали работать, и есть не просили =) Так получилось, что в ту контору я вернулся, приходящим админом - между моими приходами там успело смениться три или четыре администратора - раскурочили всё что смогли, не считая пары серверов, кроме того с которого грузились тонкие клиенты. Стрёмно, видать - на нём висела почти вся контора =) После нескольких месяцев разгребания, восстановления и обновления добрался и до тонких клиентов. За прошедшее время появилось много новых и хороших идей у меня, ещё больше хорошего воплотили разработчики FreeBSD. Немного теории. Дано - куча старых тазиков, типа пни первые-вторые-третьи, без хардов, с количеством RAM около 64Mb (+64/-16). На первых пеньках стоят сетевухи с поддержкой загрузки по сети - PXE (fxp /xl ). В BIOS вторых-третьих пней зашит загрузчик для сетеых карт типа RTL8139[a/b/c/d]. Машинки будут стягивать по TFTP загрузчик, он, уже по NFS будет вытаскивать ядро, модули и параметры. После загрузки ОС, запускаются иксы и rdesktop - подключаемся к виндовому терминал-серверу. Дополнительные задачи, которые не были реализованы вообще, или реализованы криво в предыдущей версии - корректное монтирование/отмонтирование флэшек на ходу, проброска звука из терминальной сессии на локальную машину, и, самое главное - возможность запуска X-сервера без конфигурационного файла - ибо именно прописывание разрешения, частоты развёртки, и т.п. для Win-админов было самым сложным. Итак, собирать будем на базе FreeBSD 7.2 . Особенных требований к машине, откуда всё это грузиться будет, нет. Тока чтоб сама смогла загрузиться, да и всё =)) Чтоб меньше елозила диском, при работе и раздаче по сети файловых систем - побольше рамы (хотя бы 256Mb) - всё влезет в кэш, и к диску будет минимум обращений. Готовим машину для раздачи файловых систем по NFS и TFTP. Прописываем запуск NFS-сервера:
router$ grep --after-context=4 NFS /etc/rc.conf# NFS nfs_server_enable="YES" nfs_server_flags="-u -t -n 40 " rpcbind_enable="YES" nfs_client_enable="YES" router$
Прописываем файловые системы, расшаренные по сети:
router$ cat /etc/exports# То, что расшариваем по NFS #/usr/ports/distfiles -maproot=root -network 192.168 -mask 255.255.0.0 /usr/ports /usr/src -maproot=root -network 192 .168 -mask 255 .255 .0 .0 #/pxeroot -maproot=root -network 192.168 -mask 255.255.0.0 #/usr/src -maproot=root -network 192.168 -mask 255.255.0.0 /shares/tftp/7 .2 /eliron -maproot=root -ro -network 192 .168 -mask 255 .255 .0 .0 router$
Раскомментируем, и немного подправляем строки запуска tftpd через inetd :
router$ grep shares /etc/inetd.conftftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /shares/tftp/7 .2 /eliron \ -u roottftp stream tcp nowait root /usr/libexec/tftpd tftpd -l -s /shares/tftp/7 .2 /eliron \ -u root router$
Не забываем запустить сам inetd :
router$ grep inetd /etc/rc.conf inetd_enable="YES"
Прописываем запуск DHCP-сервера (у меня DHCP сервер (isc-dhcp30-server) находиться на этой же машине, у вас может находиться на другой):
router$ grep --after-context=5 DHCPd /etc/rc.conf# DHCPd dhcpd_enable="YES" dhcpd_conf="/usr/local/etc/dhcpd.conf"#dhcpd_ifaces="fxp0 dc0 sk0" dhcpd_ifaces="fxp0 sk0"#dhcpd_flags="-d " router$
У меня, настройки для заданной сети выглядят в dhcpd.conf примерно так:
subnet 192 .168 .110 .0 netmask 255 .255 .255 .0 { range 192 .168 .110 .1 192 .168 .110 .199 ; option routers 192 .168 .110 .254 ; option subnet-mask 255 .255 .255 .0 ; option netbios-name-servers 192 .168 .0 .19 , 192 .168 .0 .251 ; option netbios-dd-server 192 .168 .110 .253 ; option netbios-node-type 8 ; option broadcast-address 192 .168 .110 .255 ; option ntp-servers 192 .168 .0 .253 ; next-server 192 .168 .110 .254 ;# option root-path "192.168.130.254:/shares/tftp/4.11/gp"; option root-path "192 .168 .110 .254 :/shares/tftp/7 .2 /eliron"; filename "/boot/pxeboot"; option domain-name-servers 192 .168 .0 .19 ; option domain-name "grand-prix"; option domain-name-servers 192 .168 .0 .251 , 192 .168 .0 .19 ; }
Заливаем сорцы (csup ) выбранного релиза, и собираем мир и ядро в директорию, которая будет расшарена по NFS/TFTP, устанавливаем системные конфиги:
router$ mkdir -p /shares/tftp/7 .2 /eliron router$ cd /usr/src/ router$ make buildworld && make buildkernel && make installworld \ ? DESTDIR=/shares/tftp/7 .2 /eliron && make installkernel \ ? DESTDIR=/shares/tftp/7 .2 /eliron && \ ? make distribution DESTDIR=/shares/tftp/7 .2 /eliron
После сборки мира и ядра, монтируем по nullfs порты и исходные коды ядра, относительно корневой директории будущих тонких клиентов:
router$ mount -t nullfs /usr/ports /shares/tftp/7 .2 /eliron/usr/portsmount : /shares/tftp/7 .2 /eliron/usr/ports: No such file or directory router$ mkdir -p /shares/tftp/7 .2 /eliron/usr/ports router$ mount -t nullfs /usr/ports /shares/tftp/7 .2 /eliron/usr/ports router$ mount -t /usr/src /shares/tftp/7 .2 /eliron/usr/src/
Также, монтируем файловую систему устройств (понадобиться при сборке некоторых портов):
router$ mount -t devfs devfs /shares/tftp/7 .2 /eliron/dev
Сразу же, копируем некоторые файлы, которые нам понадобяться при дальнейшей работе - или для удобства дальнейшей работы:
router$ cp /root/.cshrc /shares/tftp/7 .2 /eliron/root/
И рисуем конфиги - резольвера:
router$ cat /shares/tftp/7 .2 /eliron/etc/resolv.confsearch grand-prix nameserver 192 .168 .0 .251 nameserver 192 .168 .0 .19 router$
Системного файла сборочной информации - make.conf :
router$ cat /shares/tftp/7 .2 /eliron/etc/make.conf# kernel config KERNCONF=NFSBOOT# added by lissyara 2007-07-19 in 01:08 PORTSDIR?= /usr/ports .if ${ .CURDIR} == ${PORTSDIR} /mail/exim# Дефолтовая кодировка заголовков WITH_DEFAULT_CHARSET?= koi8-r# Отключаем IPv6 WITHOUT_IPV6= yes # Версия BDB - в чём ведёт свои БД подсказок WITH_BDB_VER= 1 # Подержка перекодировки (для заголовков) WITH_ICONV= yes .endif# vim .if ${ .CURDIR} == ${PORTSDIR} /editors/vim WITHOUT_X11=yes NO_GUI=yes .endif# GD .if ${ .CURDIR} == ${PORTSDIR} /graphics/gd WITH_ICONV=yes .endif# rdesktop .if ${ .CURDIR} == ${PORTSDIR} /net/rdesktop WITH_ICONV= yes .endif router$
Собственно, на этом моменте я попробовал загрузить одну машину с новой фрёй, но - обломался =) Я собрал GENERIC ядро, а оно по сети не грузиться =) Поэтому, чуть ниже будет ещё одна пересборка ядра, уже из chroot. Теперь можно делать chroot в корневую директорию тонких клиентов, и собирать необходимый софт:
router$ chroot /shares/tftp/7 .2 /eliron router$
Ставим rdesktop - для подключения клиента к виндовому серверу терминалов:
router$ setenv BATCH yes router$ cd /usr/ports/ router$ make -C net/rdesktop install clean
Иксы - полностью:
router$ make -C x11/xorg install clean
Ставим monitord - он будет отслеживать падения rdesktop и перезапускать его при необходимости:
router$ make -C sysutils/monitord install clean
Где-то между делом - пока собираются порты - пересобираем ядро (это я пересобирал - а вы могли просто не собирать на этапе инсталляции клиента). Рисуем конфиг для ядра - оно мало отличается от GENERIC:
router$ mkdir -p /root/scripts router$ cd /usr/src/sys/i386/conf/ router$ ln -s /root/scripts/NFSBOOT router$ cat /root/scripts/NFSBOOT# thin clients kernel config include GENERIC ident NFSBOOT-GENERIC# цвет консоли - кому как удобней, и буфер консоли options SC_NORM_ATTR=(FG_GREEN|BG_BLACK)options SC_KERNEL_CONS_ATTR=(FG_RED|BG_BLACK)options SC_HISTORY_SIZE=2022 # как раз опции для поддержки бездисковых клиентов options BOOTPoptions BOOTP_NFSROOToptions BOOTP_COMPAT router$
Также, пишем такие конфигурационные файлы/скрипты - для старта/работы тонкого клиента. Для начала реализуем монтирование/отмонтирование флэшек в тонких клиентах - через devd :
router$ diff -Nru /etc/devd.conf /etc/devd.by.lissyara.conf --- /etc/devd.conf 2009 -07 -22 18 :01 :02 .000000000 +0000 +++ /etc/devd.by.lissyara.conf 2009 -07 -22 21 :01 :02 .000000000 +0000 @@ -325 ,3 +325 ,16 @@ action "/etc/acpi_ac $notify "; }; */ + +# added by lissyara 2009-07-02 in 10:45 MSK +# if inserted flash - mount it +attach 100 { + device-name "umass[0 -9 ]+"; + action "/root/scripts/mount.da0.sh &"; +}; +# if usb flash removed - force umount it +detach 100 { + device-name "umass[0 -9 ]+"; + action "/root/scripts/umount.da0.sh &"; +}; + router$
Собственно, скрипт монтирования - не забываем сделать исполняемым:
router$ more /root/scripts/mount.da0.sh #!/bin/sh # ждём устаканивания системы sleep 2 # опции монтирования - шоп русские имена файлов показало # и запись была синхронной options ="-o sync -L ru_RU.KOI8-R -D CP866"# c флэшкой возможны два варианта - da0s1 и da0 - смотря как # оно форматировалось. чаще всего первый, но попадается и второй # добавлено через пару недель: попался и третий вариант =)) if test -r /dev/da0s1then device="/dev/da0s1"else if test -r /dev/da0s2 then device="/dev/da0s2" else device="/dev/da0" fi fi # запускаем fsck - чтоб не материлось /sbin/fsck_msdosfs -y -p $device # монтируем флэшку /sbin/mount_msdosfs $options $device /mnt# через пару секунд рестартуем hald - бывает виснет =( sleep 2 && /usr/local/etc/rc.d/hald restart &# запускаем sync раз в секунду /root/scripts/sync.sh & router$
Кладём файл делающий sync раз в секунду:
router$ more /root/scripts/sync.sh #!/bin/sh echo $? > /tmp/sync.pidwhile true do sync sleep 1 done router$
Скрипт выполняющий отмонтирование:
router$ more /root/scripts/umount.da0.sh #!/bin/sh # на всякий случай sync # принудительно отмонтируем флэшку umount -f /mnt &# ждём пару секунд sleep 2 # убиваем скрипт выполняющщий синхронизацию kill `cat /tmp/sync.pid`# рестартуем hald /usr/local/etc/rc.d/hald restart router$
Рисуем главный конфигурационный файл системы - rc.conf :
router$ cat /etc/rc.conf# rc.conf # Русский язык в консоли font8x14="cp866-8x14" font8x16="cp866b-8x16" font8x8="cp866-8x8" scrnmap="koi8-r2cp866"# Убираем запуск sendmail (я вообще поставил на тонких клиентов exim :)) sendmail_enable="NONE" sendmail_submit_enable="NO" exim_enable="YES" exim_flags="-q60m -oP /var/run/exim.pid"# имя хоста hostname ="thin-client"# rootfs in read-only root_rw_mount="NO"# чтоб не пытался сохранять энтропию в файл entropy_file="NO"# файл с hostid hostid_file="/tmp/hostid"# чтоб не обновляло сообщение дня update_motd="NO"# нет устройств для дампа dumpdev="NO"# мышь moused_enable="YES"# var on memory varmfs="YES" varsize="2m" populate_var="YES"# tmp on memory tmpmfs="YES" tmpsize="1m"# ssh sshd_enable="YES"# на всякий случай - вдруг хард подключу =) fsck_y_enable="YES"# hald and other gnome_enable="YES" hald_enable="YES"#hald_flags="--verbose=yes --daemon=no" dbus_enable="YES" polkitd_enable="YES"# start X trough monitord(8) #monitord_enable="YES" # указываем свой конфиг вместо штатного devd_flags="-f /etc/devd.by.lissyara.conf"# пара задумок на будущее. ещё года через три реализую =) # BlueTooth #hcsecd_enable="YES" # #fusefs_enable="YES" # bugs =) mkdir -p /var/cache/hald/ >/dev/null 2 >&1 mkdir -p /var/run/PolicyKit >/dev/null 2 >&1 /usr/sbin/chown :polkit /var/run/PolicyKit >/dev/null 2 >&1 /bin/mkdir -p /var/lib/misc >/dev/null 2 >&1 /usr/bin/touch -f /var/lib/misc/PolicyKit.reload >/dev/null 2 >&1 /usr/sbin/chown :polkit /var/lib/misc/PolicyKit.reload >/dev/null 2 >&1 /bin/chmod 0664 /var/lib/misc/PolicyKit.reload >/dev/null 2 >&1 mkdir -p /var/log/exim >/dev/null 2 >&1 /usr/sbin/chown 26 :6 /var/log/exim >/dev/null 2 >&1
Часть 2