Введение#
Сборка тонкого клиента, ориетнированного на определенные клиенты, сводится к следующим этапам:
- Скачиваем полный репозиторий ThinStation
- Собираем “толстый” (полный) образ
- Загружаем тонкий клиент на толстом образе
- Получаем список необходимых для этого клиента модулей ядра и пакетов
- Исправляем конфиги сборки, оставив только самое необходимое (в том числе полученное на предыдущем этапе)
- Собираем “тонкий” (облегченный) образ
Подготовка кухни#
Сразу скажу, что есть и другой путь сборки - скачивание подготовленного .iso образа. Но мне это кажется не таким удобным, поэтому я буду описывать “правильный” вариант.
Скачивание репозитория#
Вообще, для работы с ThinStation рекомендуется иметь базовые знания работы с Git. Просто потому, что ваши изменения нужно будет куда-то сохранять, а заблудиться в иерархии файлов, когда кухня уже распакована (не зная Git) - очень легко. Скачивание сводится к выполнению одной команды.
1git clone --depth 1 git://github.com/Thinstation/thinstation.git -b 5.5-Stable
где 5.5-Stable
- актуальная на данный момент ветка. К сожалению размер репозитория за последние годы очень сильно вырос - в 2014-ом году он занимал чуть более 2 ГБ, а сейчас скачать придется целых 8 ГБ. Поэтому во всех мануалах предлагают скачивать его с ключом --depth 1
- на вкус и цвет.
Также нужно заметить, что мейнтейнеры проекта рекомендуют даже клонировать репозиторий от имени рута - об этом мне сказали, когда я пытался предложить изменения по исправлению владельца некоторых скриптов. Насколько это правильно - я не берусь судить, но если вы наблюдаете проблемы с правами на файлы - возможно стоит последовать этому совету.
Подготовка chroot#
В корневой директории скачанного репозитория лежит bash-скрипт setup-chroot
, который сделает всю работу за вас. О нем нужно знать лишь то, что запускать его нужно от рута (т.к. он, например, монтирует в новое дерево служебные файловые системы), а во-вторых он имеет набор ключей, самым нужным из которых на первом этапе является ключ -a
- не задавать вопросы, а скачивать всё что нужно автоматически.
К слову, всё остальное выполняется уже внутри этого чрута. В первый раз операция подготовки может занять до часу времени (на медленном диске), но потом вход осуществляется практически мгновенно до следующей полной очистки.
Толстый образ#
Сборка толстого образа - это предварительный этап и нужен он для того, чтобы в первый раз загрузить ваше железо и выяснить, какой набор пакетов и модулей ему понадобится. В последствии, если у вас зоопарк железа или предвидится закупка нового - просто храните этот образ под рукой. Пересобирать его придется только при серьезных изменениях, например - новая версия ядра.
Безусловно, есть вероятность, что для вашего железа это кто-то уже сделал. Вы можете зайти в директорию ts/build/machine
и поискать там название вашей платформы. Если найдете - смело пропускайте этот пункт.
Настройка сборки#
Первое, что вам понадобится, отредактировать файл ts/build/build.conf
(изначально это симлинк на build.conf.example
- сделайте копию) следующим образом (раскомментируйте строки):
1...
2# Пригодится, чтобы больше узнать о железе
3package lshw
4...
5# Набор xorg-пакетов для практически любого видео
6package xorg7-v4l
7package xorg7-vesa
8package xorg7-vmware
9package xorg7-ati
10package xorg7-nouveau
11package xorg7-openchrome
12package xorg7-intel
13package xorg7-sis
14...
15# Системные утилиты, в том числе - hwlister, о нем ниже
16package extensions
17package extensions-x
18...
19# Изменение системы сжатия
20param initrdcmd "gzip"
21...
22# Включает полный набор firmware - иногда не работает, но рекомендую раскоментировать
23param allres true
24param allfirmware true
25...
Всё остальное сейчас не важно - настраивать тонко будем потом.
Отдельно остановлюсь на том, зачем нужно поменять систему сжатия со squashfs
на gzip
. Скрипт hwlister.sh
, о котором пойдет речь ниже, использует очень интересную методику поиска загруженного firmware - он просто смотрит время доступа к файлам в /lib/firmware
и на основе этого делает выводы, какие файлы были загружены. Но squashfs
монтируется с параметром relatime
, что приводит к тому, что время доступа к файлам не меняется и список firmware (чёрт, не знаю, как перевести это слово, не потеряв смысл) всегда пуст. Изменение режима сжатия на gzip
- самый простой и быстрый способ вернуть скрипт к жизни не залезая в кишки. Я написал об этом разработчикам, но ответа пока не было.
Сборка#
Сборка любого образа выполняется в chroot - так что не забываем в него зайти. Для сборки толстого образа существует также специальный параметр --allmodules
, который включает в образ все доступные модули ядра, что также пригодится на неизвестном железе.
1soar@localhost $ sudo ./setup-chroot
2[root@TS_chroot]/# cd build
3[root@TS_chroot]/build# ./build --allmodules --license ACCEPT --autodl
После того, как процесс завершится, в директории boot-images
можно будет найти варианты образа - iso, pxe и syslinux. Можно использовать любой и загружать клиент любым удобным способом.
Сбор информации#
Когда подопытное железо успешно загрузилось, необходимо зайти в консоль любым удобным способом и написать:
1hwlister.sh
Это обычный 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-сессии.
1# У пользователя не будет локального UI, так что локально выкручиваем громкость на максимум
2AUDIO_LEVEL=100
3MIC_LEVEL=100
4
5# Для бездисковых станций резонно собирать логи в одном месте
6SYSLOG_SERVER=syslog.example.com
7
8# Локаль и таймзона
9LOCALE=ru_RU.UTF8
10TIME_ZONE=Europe/Moscow
11
12# Кнопки "Безопасного извлечения устройства" также не будет - поэтому включаем обязательно
13USB_STORAGE_SYNC=ON
14DISK_STORAGE_SYNC=ON
15# Монтировать устройства нужно в директорию, которую мы потом пробросим в удаленную сессию
16USB_MOUNT_DIR=/mnt/usb
17# Для поддержки кириллицы на съемных накопителях, я для себя вывел вот такой набор параметров. Он точно подходит для FAT32/NTFS разделов и FreeRDP
18USB_MOUNT_OPTIONS="rw,nosuid,nodev,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro"
19DISK_MOUNT_OPTIONS="rw,nosuid,nodev,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,showexec,utf8,flush,errors=remount-ro"
20
21# Если выключили NetworkManager и включили autonet - обязательно настройте сеть
22NET_USE_DHCP=ON
23
24# Нулевая сессия должна быть оконным менеджером
25# Можно попробовать обойтись без него и даже вообще без Иксов
26# но это тема для отдельной статьи
27SESSION_0_TITLE=Desktop
28SESSION_0_TYPE=openbox
29SESSION_0_AUTOSTART=ON
30
31# Главная рабочая сессия
32# Список параметров FreeRDP - пожалуй также повод для отдельной статьи
33SESSION_1_TITLE=RemoteDesktop
34SESSION_1_TYPE=freerdp
35SESSION_1_AUTOSTART=ON
36SESSION_1_FREERDP_SERVER=rdp.example.com
37SESSION_1_FREERDP_OPTIONS="+decorations +fonts +aero ..."
Сборка тонкого образа#
Теперь, когда конфигурация готова, остается лишь собрать легковесный образ. Всё те же команды, что и для полного образа, за исключением одного параметра:
1soar@localhost $ sudo ./setup-chroot
2[root@TS_chroot]/# cd build
3[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
добавить строку:
1prtdir /ts/ports/yourproject
Хранить в отдельной директории будет гораздо проще и безопаснее. После редактирования файла нужно не забыть перезайти в chroot. Стоит отметить, что в этом файле уже присутствуют директории с портами, разложенными по коллекциям. Сборщик будет искать порт по имени во всех директориях по-порядку, поэтому, если боитесь коллизии имен - располагайте вашу директорию выше остальных.
Теперь вам понадобится создать один единственный bash-скрипт, который будет отвечать за сборку порта: /ts/ports/yourproject/portname/Pkgfile
. Образец можно посмотреть здесь, а можно подсмотреть в любом другом порте. Базовый вариант выглядит так:
1name=mdetect-TS
2version=0.5.2.3
3release=1
4source=(http://ftp.de.debian.org/debian/pool/main/m/$name/$name-$version.tar.bz2)
5
6build() {
7 cd $name-$version
8
9 ./configure --prefix=/usr \
10 --exec-prefix=/ \
11 --sysconfdir=/etc \
12 --mandir=/usr/man \
13 --disable-extras
14
15 make
16 make DESTDIR=$PKG install
17}
Давайте разберемся, что он делает (на самом деле делает не он, он лишь определяет стадию сборки):
- Скачивает файлы, заданные в
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
упаковывается в архив. Это и будет наш порт, готовый для установки.
Проверим наши предположения. Чтобы выполнить первую сборку, необходимо сделать следующее:
1[root@TS_chroot]/# cd ts/ports/yourproject/portname/
2[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -kw
3=======> Building '/ts/ports/yourproject/portname/portname#0.5.2.3-1.pkg.tar.xz'.
4...
5=======> WARNING: Footprint not found, creating new.
6=======> 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-сумм. Можно эти файлы удалить перед сборкой и они сгенерируются автоматически, а можно выполнить следующую последовательность действий:
1[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -kw
2[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -uf
3[root@TS_chroot]/ts/ports/yourproject/portname# pkgmk -um
Порт собран - самое время установить его в систему. На данном этапе речь идет о системе рабочей, той, где вы собираете ThinStation.
1[root@TS_chroot] # prt-get install portname
2prt-get: installing /ts/ports/yourproject/portname
3=======> Package '/ts/ports/yourproject/portname/portname#0.5.2.3-1.pkg.tar.xz' is up to date.
4prt-get: installing portname 0.5.2.3-1
5
6-- Packages installed
7portname
8
9prt-get: installed successfully
Теперь архив распакован в систему и все файлы доступны для использования. Однако эти файлы не появятся в собранном вами образе - для этого вам кроме порта, понадобится еще и пакет.
Создание пакета#
Минимальный пакет может выглядеть так:
1soar@localhost$ tree ts/build/packages/mypackage/
2ts/build/packages/mypackage/
3├── dependencies
4├── etc
5│ └── somefile-placed-in-etc
Где в файле dependencies
достаточно указать одну строку - base
. Считается хорошим тоном, чтобы все пакеты зависели хотя бы от пакета base
, но вы можете добавить больше правил. Этого уже достаточно, чтобы при включении строки package mypackage
в ваш build.conf
- файл somefile-placed-in-etc
попал в директорию /etc
вашего готового образа.
Что же делать, если мы хотим, чтобы наш пакет, кроме обычных файлов, включал в сборку наш порт? Для этого нам понадобятся всего два скрипта. Скрипт установки ts/build/packages/mypackage/build/install
:
1#!/bin/sh
2
3# mypackage - имя нашего порта
4export PACKAGE=mypackage
5export PORTS=$PACKAGE
6repackage -e
7
8returnval=$?
9
10exit $returnval
И скрипт удаления ts/build/packages/mypackage/build/remove
:
Теперь, при запуске магического ./build
наш порт будет добавлен в дерево файлов образа и появится в сборке. Конечно, если вы не забыли добавить этот пакет в build.conf
.
Обновления#
Нужно отметить, что все манипуляции описанные выше возможны благодаря магии системы портов CRUX. Порт устанавливается и удаляется из системы на основе данных из .footprint
и важно следить, чтобы этот файл всегда был актуален. Есть и другие подводные камни - прерванный процесс установки, ошибка во время установки и еще множество различных непредусмотренных действий могут легко привести к тому, что в вашей системе (и как следствие - образе) будут файлы, которые вы совсем не ожидаете увидеть. Я периодически делаю полную очистку кухни, чтобы быть уверенным в том, что система будет вести себя as-expected. Однако, иногда на это времени не хватает. Поэтому, если какой-то пакет и/или порт стал неконсистентным, я для себя вывел следующую последовательность команд, которая в 99% случаев очистит все лишние файлы и всё-таки приведет дерево в порядок:
1# Обновляем порт, футпринт и мд5
2prt-get update mypackage
3prt-get update -uf mypackage
4prt-get update -um mypackage
5# Очищаем билд (выполняет содержимое файла remove, описанного выше)
6./build --removeall
7# Удаляем порт
8prt-get remove mypackage
9# Обновляем пакет (при наличии .dna файла)
10update mypackage
11# Устанавливаем порт
12prt-get install mypackage
13# Запускаем сборщик
14./build --license ACCEPT --autodl
Что еще почитать#
Вот пара достаточно интересных статей, которые когда-то мне очень помогли:
- Thinstation — «худеем» с тонкими клиентами до версии 2.5
- Подключение к ферме Citrix XenApp бездисковых клиентов на основе Thinstation Linux
Ну и на всякий случай, моя ветка ThinStation на GitHub, где можно найти некоторые дополнительные профили и изменения, может быть пригодится: