Тонкие клиенты (linux) из устаревших компьютеров
Мы — начинающая, но крайне активная компания. Как и у любой начинающей компании, у нас есть ограниченный стартовый капитал, который хотелось бы потратить с максимальной пользой. Одна из существенных статей таких расходов — покупка «железа», в частности, системных блоков. Мы решили отказаться от традиционной схемы «один сотрудник — один системный блок» и сделать офисную сеть на тонких клиентах. В качестве тонких клиентов были использованы списанные из организаций системники.
В наличии имеется следующее «железо»:
- Мощный системный блок (двухядерный Athlon, 3Гб оперативной памяти, большой жесткий диск)
- Несколько списанный системников уровня Pentium III, порядка 256 Мб оперативки, жесткие диски убитые/отсутствуют, есть CD-приводы
Необходимо из них собрать офисную сеть, чтобы все могли комфортно работать. Единственное решение в такой ситуации — сделать из списанных компьютеров тонких клиентов, которые могут работать на мощном компьютере (сервере). Загрузка тонких клиентов будет выполняться со специально сделанных LiveCD. Желательно использовать безопасный протокол, так как в будущем хотелось бы иметь возможность работать и удаленно (через интернет).
В качестве серверной ОС взята Linux (Ubuntu).
Для того, чтобы сделать тонких клиентов, воспользуемся thinstation. С официального сайта можно скачать как универсальный LiveCD, так и архив, из которого можно дальше сделать собственный iso-образ. LiveCD подходит для первого знакомства и содержит в себе различные клиенты для подключения к Windows и Unix серверам по разнообразным протоколам (RDP, VNC, SSH и т. д.) Мы будем работать с архивом и сделаем с его помощью свой iso-образ, «заточенный» под наши нужды.
Перед началом сборки определимся, какой сервер терминалов мы будем использовать. Так как у нас линукс, то, по идее, достаточно туннелировать графику через SSH, однако все это танцы с бубном — как на стороне клиента, так и на стороне сервера. Возьмем готовое решение — NX Server. Для Ubuntu уже существуют deb-пакеты. С другой стороны, NX client есть и в составе thinstation. Таким образом, нам остается только настроить сервер и сделать загрузочные CD-диски.
Делаем iso-образы клиентов
Примерная последовательность выглядит так:
1. Скачиваем с официального сайта пакет ThinStation. tar.gz
2. Распаковываем: tar xzvf Thinstation-2.2.2.tar.gz
3. В корневой папке редактируем build.conf и thinstation.conf.buildtime (эти файлы используются во время сборки образа)
- В файле build.conf оставляем только нужные модули и пакеты (модули отвечают за драйверы, пакеты — за программы).
- В блоке, где идет активация клиентов, оставляем только package nx — это наш NX клиент.
- param nxurl должен указывать на пакет nxclient. tar.gz (этот пакет подгружается во время сборки iso-образа). Можно указать внешнюю ссылку, можно скачать и положить на localhost. Ссылки на образы других клиентов, естественно, комментируем.
- param keyfile — берем с сервера (файл ssh_host_rsa_key.pub). Рекомендую прописать полный путь до этого файла во избежание путаницы.
- param knownhosts — проще всего сгенерировать с помощью любого LiveCD. Загружаемся, по ssh выполняем вход на наш сервер, после этого в профиле должен появиться файл known_hosts. Копируем его. Также необходимо прописать полный путь до этого файла.
- В файл thinstation.conf.buildtime копируем содержимое из /conf/nx.conf.sample и /conf/x-common.conf.sample. Настраиваем, исходя из своей сети. Проще всего прописывать статические ip-адреса.
Образец файла thinstation.conf.buildtime:
NET_USE_DHCP=Off
NET_IP_ADDRESS=10.0.0.3
NET_MASK=255.255.255.0
SESSION_0_TYPE=nx
SESSION_0_TITLE=»Gnome»
SESSION_0_NX_ADVANCED_ENABLE_SSL_ENCRYPTION=»true»
SESSION_0_NX_GENERAL_DESKTOP=»Gnome»
SESSION_0_NX_GENERAL_SERVER_HOST=»10.0.0.1″
SESSION_0_NX_GENERAL_REMEMBER_PASSWORD=»true»
SESSION_0_NX_GENERAL_RESOLUTION=»fullscreen»
SESSION_0_NX_GENERAL_SESSION=»Unix»
SCREEN_RESOLUTION=»1280×1024″
SCREEN_COLOR_DEPTH=»24″
SCREEN_BLANK_TIME=10
SCREEN_STANDBY_TIME=20
SCREEN_SUSPEND_TIME=30
SCREEN_OFF_TIME=60
4. Выполняем сборку образа: ./build
5. Смотрим на лог сборки. Если все ОК — готовый образ появится в /boot-images/iso/. Записываем его на болванку.
Устанавливаем сервер терминалов
Делаем так, как указано на официальном сайте:
sudo dpkg -i nxclient…
sudo dpkg -i nxnode…
sudo dpkg -i nxserver…
Все должно заработать «из коробки».
Чтобы убедиться в работоспособности, можно быстро загрузиться с любой другой машины через LiveCD (Ubuntu/Xubuntu), прописать у нее сеть, поставить на нее только NX клиента, и подключиться к нашему серверу.
Все работает бодро. В нашей системе почему-то не активируется смена языка, пришлось в автозагрузку профиля добавить вот такой скрипт:
setxkbmap -model pc105 -layout us,ru\(winkeys\) -option -option grp:alt_shift_toggle -option compose:ralt
Еще наблюдаются какие-то глюки в firefox (черные прямоугольники вместо некоторых изображений). Судя по записям в интернете, это застарелая проблема, нужно ковырять в профиле.
Наконец, бесплатная версия NX сервера допускает одновременную работу только двух клиентов (итого — 3 человека: один на самом сервере, 2 — через тонких клиентов). Если хотим больше — либо приобретаем платную версию, либо ставим виртуальные системы (например, на proxmox). Но это уже, как говорится, совсем другая статья…
Тонкий бездисковый клиент на базе Ubuntu, не требующий монтирования ФС по сети
Изображение с сайта getwallpapers.com
История
В далёком 2013 году в одном банке использовались тонкие клиенты на основе DisklessUbuntu. С ними были некоторые проблемы, по-моему монтирование корневой ФС по сети в больших филиалах со слабой сетью работало не очень. Тогда мой хороший друг @deadroot сделал первую версию тонкого клиента, который грузился целиком в память, не требуя что-то монтировать по сети для работы.
Потом этот клиент активно допиливал я, там было сделано много полезных штук, специфичных именно для нашего сценария использования. Потом банк закрылся (отозвали лицензию), остатки исходников клиента переехали на мой гитхаб: thunclient. Пару раз я его слегка допиливал на заказ.
Недавно у меня дошли руки сделать из этой кучи страшных ненадёжных скриптов достаточно удобное для использования решение:
- Vagrant поднимает виртуалку, которую можно настраивать как обычную рабочую станцию.
- Одним скриптом из неё собирается готовые для загрузки по сети файлы, лишнее вырезается.
- Vagrant поднимает виртуальный PXE сервер и сетевой клиент для проверки получившейся сборки.
Что умеет
В банке для удалённого подключения к тонкому клиенту пользователя использовался VNC ( x11vnc для подключения к уже запущенной сессии Xorg). Это далеко не всем требуется (обычно хватает возможности подключения к сеансу RDP на сервере терминалов), и тут всё очень индивидуально в плане требований удобства/безопасности. Поэтому эту часть я выкладывать не стал.
Аналоги
Если Thinstation полностью устраивает — то лучше пользоваться им, это более старый и зрелый проект. Плюс он раза в полтора меньше по размеру, всё-таки это специально заточенная под минимальный объём сборка, а не слегка допиленная обычная Ubuntu.
Но версии софта в нём достаточно древние и его там мало. Если нужно что-то дополнительное, помимо клиентов RDP/Citrix/… — потребуется собирать это руками, и так при каждом обновлении.
kvaps указал в комментарии, что LTSP может скопировать образ squashfs в память и работать без монтирования ФС по сети: это настраивается переменной LTSP_NBD_TO_RAM. Для настройки используется chroot, что может быть менее удобно, особенно для настройки графического окружения и приложений. Также хороший зрелый проект, можно рассматривать как альтернативу.
Vagrant vs chroot
Прошлые версии использовали chroot, как собственно и большинство похожих проектов, тот же Thinstation к примеру. Это несложно, но всё-таки запущенная в chroot отдельная программа не соответствует происходящему на реальной машине: нету взаимодействия с системным init, с другими программами и службами. Плюс Vagrant позволил сделать процесс создания клиента максимально простым: виртуалка настраивается как обычная машина.
Конечно, использование Vagrant приносит и некоторые сложности.
На машине должна работать служба virtualbox-guest-utils , для работы общих папок. Кроме того, нужен менеджер загрузки ( grub ), обязательный для машины с диском и бесполезный для загружаемого по сети клиента. Эти проблемы я решил, исключая из сборки все файлы этих пакетов. Поэтому на размер получившегося образа они не влияют.
Кроме того, для Vagrant обязателен работающий на машине ssh, пускающий пользователя со сгенерированным ключом. Я исключаю из сборки домашний каталог пользователя vagrant, используемого для настройки, вместе с его ssh ключами. Ключи для используемого при работе пользователя ubuntu можно положить в его домашний каталог.
Ну и для работы Vagrant генерирует настройки сетевых интерфейсов, которые будут ошибочными для реальной машины. Пришлось на время сборки подменять файл interfaces , и написать скрипт, который на реальной машине генерирует конфиг для настройки всех доступных интерфейсов по DHCP.
Provisioning делается с помощью Ansible. Это очень удобный инструмент для конфигурации всяческого софта и железа. Но включать в итоговый образ Ansible и требующийся ему второй python с нужными библиотеками не хотелось бы: бесполезный балласт. Ставить Ansible на машину, где запукается виртуальное окружение, тоже не хочется: это усложнит работу.
Vagrant позволяет сделать хитрость: поставить Ansible на одну машину (тестовый PXE сервер), и с неё делать разворачивание других машин, в рамках той же playbook. Для этого машины должны иметь статический IP, чтобы прописать его в ansible inventory. Ну а проблему с конфигурацией интерфейсов мы решили в прошлом пункте.
Непослушный кабачок
Squashfs — сжимающая read-only файловая система. Лежит в основе большинства существующих Linux LiveCD. Именно она позволяет создать достаточно компактный образ системы, помещающийся в оперативную память тонкого клиента.
Из итогового образа надо много чего вырезать: /tmp , /run , /proc , /sys , /usr/share/doc и так далее.
Утилита mksquashfs поддерживает аж 3 типа списков для исключения файлов: по полному пути, по маскам и по регулярным выражениям. Казалось бы, всё прекрасно. Но последние два варианта не поддерживают пути, начинающиеся с / . У меня не получилось исключить все файлы внутри некоторой структуры папок, не исключая последнюю папку.
Мне быстро надоело с ней бороться, я просто нашёл find -ом все файлы и папки, которые надо исключить, и запихнул в один большой файл с исключениями по полному пути. Костыли.jpg. Но работает. Единственным артефактом этого подхода в итоговом образе остаётся одинокая папка /proc/NNN , соответствующая номеру процесса mksquashfs, которого при создании списка исключений ещё не было. Сверху всё равно монтируется procfs.
Магия initrd
Чтобы не тянуть в составе ядра все необходимые драйвера и логику монтирования корневой ФС, Linux использует initial ramdisk. Раньше использовался формат initrd, в котором этот диск представлял собой настоящий образ файловой системы. В ядре 2.6 появился новый формат — initramfs, представляющий собой извлекаемый в tmpfs cpio-архив. Как initrd, так и initramfs могут быть сжаты для экономии времени загрузки. Многие названия утилит и имена файлов по-прежнему упоминают initrd, хотя он уже не используется.
В Debian/Ubuntu для создания initramfs используется пакет initramfs-tools. Он даёт следующие возможности для кастомизации:
- хуки — скрипты специального формата, которые позволяют добавлять в образ модули ядра и исполняемые файлы со всеми необходимыми им библиотеками
- скрипты в каталогах init-bottom , init-premount , init-top , local-block , local-bottom , local-premount , local-top , выполняемые в соответствующий момент загрузки. См. man initramfs-tools(8)
- самое интересное — добавлять собственные скрипты загрузки, отвечающие за монтирование корневой ФС. Они должны определять shell функцию mountroot() , которая будет использована главным скриптом /init . В составе уже есть local для монтирования корня на локальном диске и nfs для монтирования корня по сети. Используемый скрипт выбирается параметром загрузки boot .
Итого, чтобы примонтировать корневую ФС каким-то сильно хитрым образом, надо создать свой скрипт загрузки, определить в нём функцию mountroot() , передать имя этого скрипта в параметре загрузки boot и не забыть написать хуки, подтягивающие в initramfs все нужные скрипту программы и модули ядра.
Борьба за оверлеи
Для создания единой корневой файловой системы из нескольких используется OverlayFS. В первых версиях использовалась AUFS (она используется большинством линуксовых LiveCD). Но её не приняли в ядро, и сейчас всем рекомендуют переходить на OverlayFS.
После монтирования настоящей корневой ФС в каталог внутри initramfs, будет запущена программа run_init из состава klibc-utils . Она проверит, что корневая ФС смонтирована внутри initramfs, отчистит initramfs (зачем зря терять память?) и переместит точку монтирования корневой ФС в / , и запустит системный init. Подробности. Эта программа собрана в виде отдельного исполняемого файла, потому что скрипт, использующий любые внешние утилиты, сломается после отчистки initramfs.
Если корневая ФС собирается из нескольких оверлеев, смонтированных внутри initramfs, при работе run_init эти точки монтирования пропадают, и она ломается. Эту проблему можно решить, переместив точки монтирования оверлеев внутрь корневой ФС, где они уже не пропадут. Рекурсия 🙂 Делается так: mount —move olddir newdir .
AppArmor пришлось отключить: её профили рассчитаны на прямое монтирование корневой ФС с одного устройства. При использовании OverlayFS она видит, что /sbin/dhclient это на самом деле /AUFS/root/sbin/dhclient , и профиль ломается. Единственный вариант её использовать — переписать все профили для всех приложений, и обновлять при необходимости.
Где нужна возможность записи
Под идее, Linux может спокойно работать, когда все ФС примонтированы только на чтение. Но многие программы рассчитывают на возможность записи на диск, приходится монтировать туда tmpfs:
- /tmp , /var/tmp — понятно, нужны очень многим
- /var/log — пишем логи
- /run — без него не запустятся почти все сервисы
- /media — монтированиие подключенных носителей
- /var/lib/system — используется многими программами из systemd, в частности systemd-timesyncd
- /var/lib/dhclient — сюда dhclient записывает информацию о leases
- /etc/apparmor.d/cache — если вы всё-таки поборете AppArmor, то ему надо будет писать файлы в /etc . ИМХО отвратительно, для таких вещей есть /var .
Итого
Если вы хотите собрать загружаемую по сети и работающую только из памяти сборку Ubuntu — вот тут есть готовый удобный конструктор: thinclient. Если потребуется помощь — пишите в ЛС или в тикеты на гитхабе, подскажу.