Введение
Сборка тонкого клиента, ориетнированного на определенные клиенты, сводится к следующим этапам:
- Скачиваем полный репозиторий ThinStation
- Собираем "толстый" (полный) образ
- Загружаем тонкий клиент на толстом образе
- Получаем список необходимых для этого клиента модулей ядра и пакетов
- Исправляем конфиги сборки, оставив только самое необходимое (в том числе полученное на предыдущем этапе)
- Собираем "тонкий" (облегченный) образ
Подготовка кухни
Сразу скажу, что есть и другой путь сборки - скачивание подготовленного .iso образа. Но мне это кажется не таким удобным, поэтому я буду описывать "правильный" вариант.
Скачивание репозитория
Вообще, для работы с ThinStation рекомендуется иметь базовые знания работы с Git. Просто потому, что ваши изменения нужно будет куда-то сохранять, а заблудиться в иерархии файлов, когда кухня уже распакована (не зная Git) - очень легко. Скачивание сводится к выполнению одной команды.
где 5.5-Stable
- актуальная на данный момент ветка. К сожалению размер репозитория за последние годы очень сильно вырос - в 2014-ом году он занимал чуть более 2 ГБ, а сейчас скачать придется целых 8 ГБ. Поэтому во всех мануалах предлагают скачивать его с ключом --depth 1
- на вкус и цвет.
Также нужно заметить, что мейнтейнеры проекта рекомендуют даже клонировать репозиторий от имени рута - об этом мне сказали, когда я пытался предложить изменения по исправлению владельца некоторых скриптов. Насколько это правильно - я не берусь судить, но если вы наблюдаете проблемы с правами на файлы - возможно стоит последовать этому совету.
Подготовка chroot
В корневой директории скачанного репозитория лежит bash-скрипт setup-chroot
, который сделает всю работу за вас. О нем нужно знать лишь то, что запускать его нужно от рута (т.к. он, например, монтирует в новое дерево служебные файловые системы), а во-вторых он имеет набор ключей, самым нужным из которых на первом этапе является ключ -a
- не задавать вопросы, а скачивать всё что нужно автоматически.
К слову, всё остальное выполняется уже внутри этого чрута. В первый раз операция подготовки может занять до часу времени (на медленном диске), но потом вход осуществляется практически мгновенно до следующей полной очистки.
Толстый образ
Сборка толстого образа - это предварительный этап и нужен он для того, чтобы в первый раз загрузить ваше железо и выяснить, какой набор пакетов и модулей ему понадобится. В последствии, если у вас зоопарк железа или предвидится закупка нового - просто храните этот образ под рукой. Пересобирать его придется только при серьезных изменениях, например - новая версия ядра.
Безусловно, есть вероятность, что для вашего железа это кто-то уже сделал. Вы можете зайти в директорию ts/build/machine
и поискать там название вашей платформы. Если найдете - смело пропускайте этот пункт.
Настройка сборки
Первое, что вам понадобится, отредактировать файл ts/build/build.conf
(изначально это симлинк на build.conf.example
- сделайте копию) следующим образом (раскомментируйте строки):
...
# Пригодится, чтобы больше узнать о железе
package lshw
...
# Набор xorg-пакетов для практически любого видео
package xorg7-v4l
package xorg7-vesa
package xorg7-vmware
package xorg7-ati
package xorg7-nouveau
package xorg7-openchrome
package xorg7-intel
package xorg7-sis
...
# Системные утилиты, в том числе - hwlister, о нем ниже
package extensions
package extensions-x
...
# Изменение системы сжатия
param initrdcmd "gzip"
...
# Включает полный набор firmware - иногда не работает, но рекомендую раскоментировать
param allres true
param allfirmware true
...
Всё остальное сейчас не важно - настраивать тонко будем потом.
Отдельно остановлюсь на том, зачем нужно поменять систему сжатия со squashfs
на gzip
. Скрипт hwlister.sh
, о котором пойдет речь ниже, использует очень интересную методику поиска загруженного firmware - он просто смотрит время доступа к файлам в /lib/firmware
и на основе этого делает выводы, какие файлы были загружены. Но squashfs
монтируется с параметром relatime
, что приводит к тому, что время доступа к файлам не меняется и список firmware (чёрт, не знаю, как перевести это слово, не потеряв смысл) всегда пуст. Изменение режима сжатия на gzip
- самый простой и быстрый способ вернуть скрипт к жизни не залезая в кишки. Я написал об этом разработчикам, но ответа пока не было.
Сборка
Сборка любого образа выполняется в chroot - так что не забываем в него зайти. Для сборки толстого образа существует также специальный параметр --allmodules
, который включает в образ все доступные модули ядра, что также пригодится на неизвестном железе.
soar@localhost $ sudo ./setup-chroot
[root@TS_chroot]/# cd build
[root@TS_chroot]/build# ./build --allmodules --license ACCEPT --autodl
После того, как процесс завершится, в директории boot-images
можно будет найти варианты образа - iso, pxe и syslinux. Можно использовать любой и загружать клиент любым удобным способом.
Сбор информации
Когда подопытное железо успешно загрузилось, необходимо зайти в консоль любым удобным способом и написать:
Это обычный bash-скрипт, после выполнения которого вы обнаружите несколько файлов:
/firmware.list
- список необходимых firmware/module.list
- список необходимых модулей ядра/package.list
- список необходимых пакетов, учитывая архитектуру будет содержать толькоxorg7-*
пакеты/vbe_modes.list
- если используетсяuvesafb
, этот файл будет содержать список поддерживаемых режимов
Некоторые файлы могут отсутствовать, если ничего подходящего не найдено
Также я рекомендую куда-нибудь сохранить вывод lshw
- обязательно пригодится в будущем, когда железки под рукой уже не будет, а вы будете вспоминать, какое-же там было видео-ядро (немного личного опыта).
Этот же скрипт попытается загрузить файлы на ваш tftp-сервер, указанный в конфиге, однако, надеюсь, у вас запись на tftp, как и у меня, запрещена. Поэтому забираем файлы с тестируемой системы любым способом и кладем в директорию ts/build/machine/MACHINENAME
, где MACHINENAME
- кодовое имя, которое вы дадите своему железу.
Тонкий образ
Сборка тонкого образа - это всегда балансирование на границе между функциональностью и объемом. Меньше объем - быстрее загрузка бездисковых рабочих станций по сети, быстрее старт системы, меньше оперативной памяти требуется клиентам. Лично у меня стояла задача сделать образ минимального объёма всего под одну задачу - терминальный RDP-клиент. Об этом я и буду рассказывать.
Итак, у нас есть офис, набор тонких клиентов, подключенных проводами, получающих адрес по DHCP, загружающихся по PXE и стартующих одно единственное приложение - RDP-клиент.
Конфигурация сборки - build.conf
Как я уже писал выше, первый этап в конфигурации сборки - это правка файла build.conf
. Он определяет какие пакеты будут включены в образ и некоторые другие параметры сборщика.
- Все строки начинающиеся с
machine
- комментируем. Должно остаться только то, что используется у вас. Нужно отметить, что в конфигурации можно держать активными сразу несколько профилей - тогда получится образ, запускающийся на любом из них (в теории, если нет конфликтов). - Скорее всего вам не понадобятся файловые системы кроме
vfat
иntfs
- поэтому в блоке файловых систем можно смело комментировать строкиisofs
,udf
,ext*
. - Так как мы создали профиль для своего железа, содержащий необходимые пакеты
xorg7
, то все строки содержащиеpackage xorg7-*
- можно смело комментировать. - Смело комментируем все пакеты локалей
package locale-*
кроме, конечноru_RU
, и, по желанию,en_US
- нужна она или нет вопрос спорный. - Если вам нужен удаленный доступ к рабочим станциям - включите
package sshd
- Если вам нужны смарт-карты и USB-токены - включите
package ccidreader
- Если вы собираетесь вырезать оконный менеджер, рабочий стол и показывать пользователю только одно приложение (например FreeRDP) - включите пакет
package automount
для автоматического монтирования любых USB-устройств. При этомpackage udisks
можно смело выключить. - Если вам не нужен интерфейс для Wi-Fi соединений и другие рюшечки - закомментируйте
package networkmanager
и включитеpackage autonet
. Но будьте готовы к тому, что придется покопаться в его внутренностях - это скриптовая обвязка для системных утилит и в некоторых сетях может работать не совсем так, как ожидается. - Чтобы максимально облегчить образ, включаем
package openbox
и выключаемpackage gtk-*
,package icons-*
,package fonts-*
.
Что касается пакетов в разделе Applications - здесь выбор полностью за вами. Всё описанное выше применимо к тонким клиентам, где пользователь не будет видеть своего рабочего стола (RDP, VNC, etc) и для использования, например, локального браузера - многое из перечисленного выше придется оставить.
Остается не забыть вернуть param initrdcmd "squashfs"
и убрать 3 строки в самом конце: package alltimezone
, param allres true
и param allfirmware true
- в тонком образе это нам не пригодится.
Runtime-конфигурация - thinstation.conf.buildtime
Файл thinstation.conf.buildtime
является по своей сути bash-скриптом, предоставляющим переменные окружения для всех скриптов запуска. Перед тем, как начать его редактировать, стоит заглянуть в директорию ts/build/conf
(github) - здесь собраны кусочки конфигураций для каждого пакета, включающие в себя пояснения и все доступные переменные.
Давать какие-то универсальные советы - сложно. Настройка будет зависеть от вашего окружения и используемых пакетов. Приведу лишь пример для RDP-сессии.
# У пользователя не будет локального UI, так что локально выкручиваем громкость на максимум
AUDIO_LEVEL=100
MIC_LEVEL=100
# Для бездисковых станций резонно собирать логи в одном месте
SYSLOG_SERVER=syslog.example.com
# Локаль и таймзона
LOCALE=ru_RU.UTF8
TIME_ZONE=Europe/Moscow
# Кнопки "Безопасного извлечения устройства" также не будет - поэтому включаем обязательно
USB_STORAGE_SYNC=ON
DISK_STORAGE_SYNC=ON
# Монтировать устройства нужно в директорию, которую мы потом пробросим в удаленную сессию
USB_MOUNT_DIR=/mnt/usb
# Для поддержки кириллицы на съемных накопителях, я для себя вывел вот такой набор параметров. Он точно подходит для FAT32/NTFS разделов и FreeRDP
USB_MOUNT_OPTIONS="rw,nosuid,nodev,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro"
DISK_MOUNT_OPTIONS="rw,nosuid,nodev,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro"
# Если выключили NetworkManager и включили autonet - обязательно настройте сеть
NET_USE_DHCP=ON
# Нулевая сессия должна быть оконным менеджером
# Можно попробовать обойтись без него и даже вообще без Иксов
# но это тема для отдельной статьи
SESSION_0_TITLE=Desktop
SESSION_0_TYPE=openbox
SESSION_0_AUTOSTART=ON
# Главная рабочая сессия
# Список параметров FreeRDP - пожалуй также повод для отдельной статьи
SESSION_1_TITLE=RemoteDesktop
SESSION_1_TYPE=freerdp
SESSION_1_AUTOSTART=ON
SESSION_1_FREERDP_SERVER=rdp.example.com
SESSION_1_FREERDP_OPTIONS="+decorations +fonts +aero ..."
Сборка тонкого образа
Теперь, когда конфигурация готова, остается лишь собрать легковесный образ. Всё те же команды, что и для полного образа, за исключением одного параметра:
soar@localhost $ sudo ./setup-chroot
[root@TS_chroot]/# cd build
[root@TS_chroot]/build# ./build --license ACCEPT --autodl
И это всё. В зависимости от того, что вы указали в build.conf
, вы получите готовые образы для загрузки по PXE, с CD-ROM, жесткого диска или флешки. При описанной конфигурации можно добиться образа размером ~90 MB и времени загрузки по PXE (от включения питания до рабочего стола) около 1 минуты. С локального диска и того быстрее.
Другие возможности
Нужно отметить, что всё, о чем я писал выше - советы по сборке универсального образа. Я добился того, чтобы с одного образа можно было загрузить любой ПК из присутствующих в зоопарке компании. Но может получиться так, что вам понадобится сделать несколько вариантов клиентов, с разными настройками или, например, разными адресами серверов. В таком случае обратите внимание, что ThinStation умеет как скачивать дополнительные конфигурационные файлы во время загрузки, так и докачивать дополнительные модули. Это очень хорошо описано в документации, и я на этом останавливаться не буду.
Полезные заметки
Очистка кухни
Периодически, особенно если вы активно экспериментируете с версиями пакетов, сборкой, пересборкой, перекомпилированием бинарников и т.д., рано или поздно вам придется начать очищать рабочую директорию от накопившегося мусора.
- Не забыть выйти из chroot
- Убедиться, что сохранили все свои изменения в Git
- Отмонтировать все системные ФС внутри кухни:
umount -R thinstation/*
- Запустить скрипт очистки:
sudo ./setup-chroot -a
- Удалить всё, что осталось:
git clean -dx
- это удалит все несохраненные файлы
Добавление своих пакетов
Если вы собираетесь привносить в проект что-то свое, нужно знать о том, что в терминологии ThinStation, а вернее в терминологии CRUX Linux, на котором базируется TS, существует два базовых понятия:
- package (далее "пакет") - некая абстракция, указывающая на то, что необходимо установить в будущий образ. Пакет может содержать кусок дерева файловой системы, отдельные файлы, или даже просто один конфигурационный файл, указывающий, например на зависимости.
- port (далее "порт") - подобие
*.deb
иди*.rpm
пакета, с одним важным отличием: архив со скомпилированными файлами не содержит правил установки, а представляет из себя просто кусок дерева файловой системы. Любые правила (скрипт компиляции, скрипты пост-установки, и т.д.) лежат рядом с архивом и легко редактируются.
Когда вы хотите дополнить образ чем-то своим, первое, о чем стоит задуматься, а что именно вам нужно? Если вы хотите добавить в образ пару текстовых конфигов - просто создайте свой пакет, включите его build.conf
- и этого будет более чем достаточно. Если же вам нужно собирать бинарные файлы - то вам понадобится сделать свой порт.
Создание своего порта
Первое, что я рекомендую сделать, это создать для своих поделок отдельную директорию. Для этого нужно в файл ts/etc/prt-get.conf
добавить строку:
Хранить в отдельной директории будет гораздо проще и безопаснее. После редактирования файла нужно не забыть перезайти в chroot. Стоит отметить, что в этом файле уже присутствуют директории с портами, разложенными по коллекциям. Сборщик будет искать порт по имени во всех директориях по-порядку, поэтому, если боитесь коллизии имен - располагайте вашу директорию выше остальных.
Теперь вам понадобится создать один единственный bash-скрипт, который будет отвечать за сборку порта: /ts/ports/yourproject/portname/Pkgfile
. Образец можно посмотреть здесь, а можно подсмотреть в любом другом порте. Базовый вариант выглядит так:
name=mdetect-TS
version=0.5.2.3
release=1
source=(http://ftp.de.debian.org/debian/pool/main/m/$name/$name-$version.tar.bz2)
build() {
cd $name-$version
./configure --prefix=/usr \
--exec-prefix=/ \
--sysconfdir=/etc \
--mandir=/usr/man \
--disable-extras
make
make DESTDIR=$PKG install
}
Давайте разберемся, что он делает (на самом деле делает не он, он лишь определяет стадию сборки):
- Скачивает файлы, заданные в
source
(в данном случае -http://ftp.de.debian.org/debian/pool/main/m/mdetect-TS/mdetect-TS-0.5.2.3.tar.bz2
), их может быть несколько - Распаковывает все скачанные файлы в рабочую директорию
- Выполняет
configure
+make
- Делает
make install
из директории/ts/ports/yourproject/portname/work/src
в/ts/ports/yourproject/portname/work/pkg
- Полученное содержимое директории
pkg
упаковывается в архив. Это и будет наш порт, готовый для установки.
Проверим наши предположения. Чтобы выполнить первую сборку, необходимо сделать следующее:
[root@TS_chroot]/# cd ts/ports/yourproject/portname/
[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -kw
=======> Building '/ts/ports/yourproject/portname/portname#0.5.2.3-1.pkg.tar.xz'.
...
=======> WARNING: Footprint not found, creating new.
=======> Building '/ts/ports/yourproject/portname/portname#0.5.2.3-1.pkg.tar.xz' succeeded.
Конечный файл portname#0.5.2.3-1.pkg.tar.xz
(имя файла формируется с учетом переменных заданных в начале скрипта) представляет из себя готовый к установке порт и содержит в себе дерево файловой системы. Остается включить его в образ - о том, как это сделать, смотрите ниже.
Нужно также отметить, что если у вас в директории с портом присутствуют файлы .footprint
или .md5sum
- сборка может "провалиться" с ошибкой из-за несоответствия дерева файлов или md5-сумм. Можно эти файлы удалить перед сборкой и они сгенерируются автоматически, а можно выполнить следующую последовательность действий:
[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -kw
[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -uf
[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -um
Порт собран - самое время установить его в систему. На данном этапе речь идет о системе рабочей, той, где вы собираете ThinStation.
[root@TS_chroot] # prt-get install portname
prt-get: installing /ts/ports/yourproject/portname
=======> Package '/ts/ports/yourproject/portname/portname#0.5.2.3-1.pkg.tar.xz' is up to date.
prt-get: installing portname 0.5.2.3-1
-- Packages installed
portname
prt-get: installed successfully
Теперь архив распакован в систему и все файлы доступны для использования. Однако эти файлы не появятся в собранном вами образе - для этого вам кроме порта, понадобится еще и пакет.
Создание пакета
Минимальный пакет может выглядеть так:
soar@localhost$ tree ts/build/packages/mypackage/
ts/build/packages/mypackage/
├── dependencies
├── etc
│ └── somefile-placed-in-etc
Где в файле dependencies
достаточно указать одну строку - base
. Считается хорошим тоном, чтобы все пакеты зависели хотя бы от пакета base
, но вы можете добавить больше правил. Этого уже достаточно, чтобы при включении строки package mypackage
в ваш build.conf
- файл somefile-placed-in-etc
попал в директорию /etc
вашего готового образа.
Что же делать, если мы хотим, чтобы наш пакет, кроме обычных файлов, включал в сборку наш порт? Для этого нам понадобятся всего два скрипта. Скрипт установки ts/build/packages/mypackage/build/install
:
#!/bin/sh
# mypackage - имя нашего порта
export PACKAGE=mypackage
export PORTS=$PACKAGE
repackage -e
returnval=$?
exit $returnval
И скрипт удаления ts/build/packages/mypackage/build/remove
:
Теперь, при запуске магического ./build
наш порт будет добавлен в дерево файлов образа и появится в сборке. Конечно, если вы не забыли добавить этот пакет в build.conf
.
Обновления
Нужно отметить, что все манипуляции описанные выше возможны благодаря магии системы портов CRUX. Порт устанавливается и удаляется из системы на основе данных из .footprint
и важно следить, чтобы этот файл всегда был актуален. Есть и другие подводные камни - прерванный процесс установки, ошибка во время установки и еще множество различных непредусмотренных действий могут легко привести к тому, что в вашей системе (и как следствие - образе) будут файлы, которые вы совсем не ожидаете увидеть. Я периодически делаю полную очистку кухни, чтобы быть уверенным в том, что система будет вести себя as-expected. Однако, иногда на это времени не хватает. Поэтому, если какой-то пакет и/или порт стал неконсистентным, я для себя вывел следующую последовательность команд, которая в 99% случаев очистит все лишние файлы и всё-таки приведет дерево в порядок:
# Обновляем порт, футпринт и мд5
prt-get update mypackage
prt-get update -uf mypackage
prt-get update -um mypackage
# Очищаем билд (выполняет содержимое файла remove, описанного выше)
./build --removeall
# Удаляем порт
prt-get remove mypackage
# Обновляем пакет (при наличии .dna файла)
update mypackage
# Устанавливаем порт
prt-get install mypackage
# Запускаем сборщик
./build --license ACCEPT --autodl
Что еще почитать
Вот пара достаточно интересных статей, которые когда-то мне очень помогли:
- Thinstation — «худеем» с тонкими клиентами до версии 2.5
- Подключение к ферме Citrix XenApp бездисковых клиентов на основе Thinstation Linux
Ну и на всякий случай, моя ветка ThinStation на GitHub, где можно найти некоторые дополнительные профили и изменения, может быть пригодится: