Малиновый Прог против Интернета Кирпичей, или Raspberry Pi с графикой на read-only microSD

в 21:00, , рубрики: diy или сделай сам, flash-память, IoT, microSD, Raspberry Pi, read-only root, Readonly, гаджеты, загрузка, загрузочная флешка, загрузочная флэшка, износ, Интернет вещей, крепсондо

Аннотация

Запуск Raspberry Pi с полной поддержкой графики на microSD, навсегда остающейся в режиме read-only после установки системы. Отсутствие какой-либо записи данных на флэш-память повышает надёжность устройства, приближая его к промышленному классу изделий. Пошаговая инструкция. Небольшой театр инженерного абсурда для развлечения аудитории.

Малиновый Прог против Интернета Кирпичей, или Raspberry Pi с графикой на read-only microSD - 1Мне понадобилось сетевое устройство с открытым кодом и выходом HDMI, и я решил попробовать Малиновый Прог. Да, я именно так предлагаю переводить Pi: Прог. Понятное дело, даже одноплатнику нужна операционка. И вот, захожу я на официальный сайт, ожидая встретить там подробное руководство по созданию суровой, неломаемой Вещи à la turnkey box. Но народ, как ни в чём не бывало, устанавливает Ubuntu (т.е. Raspbian Jessie) прямо на microSD, размещая и swap там же. Как обычный десктоп, face palm.

Но то цветочки. Малиновые ягодки — это проекты фоторамок из МалинПрога, требующие обязательного выключения кнопкой. Иначе фоторамка после сбоя питания может не заработать, вместо картинок предлагая воспользоваться fsck. Но и это не предел, под катом читателя ждёт настоящий шедевр инженерного абсурда, найденный автором на просторах сети.

Итак, по стандартной инструкции нормальный одноплатник превращается в раздутый десктоп со средним временем жизни год-полтора, пока изношенная флэшка не сдохнет, превратив в общем-то хороший девайс в кирпич. И большинство людей, похоже, это вполне устраивает. Меня — нет.

Куда мир катится

Прежде чем открывать спойлер, оденьте защитную маску, либо заранее возьмитесь руками за голову.

Неплохой проект, который испортила одна рекомендация

Представьте себе большой телевизор и демонстратор слайд-шоу на базе RPi, но с нейтрализацией скринсейвера аппаратным (!) имитатором ёрзающей мыши. Дескать, в оконном интерфейсе Raspbian тайм-аут скринсейвера больше 720 минут не выставляется. Поэтому, дабы каждые 12 часов не шевелить мышь вручную, народ автоматизирует процесс микроконтроллером, создающим виртуальные «ползки» USB-мыши каждые 4 минуты. Я не шучу, вот реальный проект на RPi, там же ссылка на микроконтроллер ECIO28P, и прошивка взбадривателя имеется.

Ладно, не буду отрицать самостоятельной полезности аппаратного взбадривателя: это реальный лайф-хак для тех, у кого почасовая оплата идёт за сидение перед монитором. Или для поддержания в тонусе какого-нибудь особо тупого сурового промышленного терминала, из-под антивандальной брони которого торчит один разъём для мыши (для PS/2 должен подойти зелёный переходник). Да, если втиснуть раздутый десктоп в одноплатный компьютер, то в руках über-умельцев это грозное оружие, особенно с брутально торчащей из разъёма платой МК. Сразу видно: человек умеет работать руками. Но если нужен вечно включённый экран, на линуксе достаточно головы, резиденты данного ресурса прекрасно это знают. Для гостей портала я всё-таки дам инструкцию, мало ли чего.

Отключение DPMS, скринсейвера и заодно всех GUI-элементов

Для начала примем, что используется минималистичная оболочка LightDM, и отключим X-серверу DPMS в файле /etc/lightdm/lightdm.conf:
...
xserver-command=X -s 0 -dpms -nocursor
...

Флажок -nocursor убирает долой из центра экрана неподвижную стрелку курсора. А вместо нейтрализации скринсейвера можно просто закомментировать его запуск в файле ~/.config/lxsession/LXDE/autostart. Если это не помогает, можно повесить по cron(8) с интервалом 718 минут команду xscreensaver-command -deactivate.

Я поступил просто: принял LightDM с автовходом, но оставил в файле ~/.config/lxsession/LXDE/autostart лишь вызов feh с префиксом '@' для перезапуска в случае аварии и соотв. параметрами. Т.е. как бы обычная графика, но без lxpanel, без pcmanfm, без xscreensaver, с отключённым DPMS и скрытым курсором несуществующей мыши.

Минимальную графику очень легко получить командами apt-get и правкой файла autostart, причём в системе будет всё необходимое для жизнедеятельности стандартных приложений, включая X-сервер, менеджер окон, менеджер сеансов и менеджер дисплея с автовходом пользователя. Но пока это ещё не Вещь, а всего лишь одноплатный десктоп.

Задача

Сферический одноплатник в вакууме — это скучно. Не для того на Малиновом Проге целая гребёнка GPIO с I2C/PWM, а также всякие CSI-DSI и сторожевой таймер. Но я в качестве практического примера использую всё-таки сетевой демонстратор с HDMI-выходом, добавив возможность нескольким пользователям по очереди «захватывать» общий экран-табло и транслировать на него свой рабочий стол, не вставая с кресла. Экран повёрнут лицом в сторону гостей, в состоянии покоя тихонечко перебирает случайным образом картинки, выложенные в сети. Если надо показать гостю продукт, один из сидящих за стойкой администраторов временно превращает табло в «зеркало» своего монитора, но потом освобождает его для другого админинистратора. В моём случае это реальный бизнес-инструмент, висящий в реальном торговом зале. Кстати, благодарю пользователя Sauron за подсказку.

Однако, глянув на размер этой публикации, я решил отложить описание прикладного решения (т.е. собственно видеомодуля) в отдельную статью. Пока позвольте сфокусироваться на изначальной задаче: заставить Raspberry Pi загружаться и работать с microSD в режиме read-only, не боясь отключения питания и не запиливая флэш-память мусором.

Теория вопроса

Даже очень серьёзная файловая система с журналом в конечном итоге не может проконтролировать процессы, происходящие внутри SD-носителя при отключении питания. Например, серьёзные SSD-накопители для использования в ЦОД имеют конденсаторы, разряда которых как раз хватает на закрытие последней транзакции записи, и даже остаётся ещё немного. А что с отключением питания в microSD? Я уверен, там конденсаторов достаточной ёмкости нет, зато есть ненулевая вероятность того, что запись страницы NAND-памяти не успеет завершиться. И потом драйвер файловой системы от прочитанного придёт в такое недоумение, что потребуется ручное вмешательство оператора. Вот вам и фоторамка с fsck.

Насколько сложно перевести microSD Raspberry Pi в режим read-only методом Микеланджело, т.е. убирая лишние службы и пакеты? Достаточно просто, если нет графики (ссылка). Но стоит пустить в систему иксы с этими их многочисленными менеджерами всего, начинается долгий и нудный поединок с непредсказуемым результатом. Это вам не иголка в стоге сена, её хотя бы магнитом можно вытянуть. Представьте, что неизвестное количество иголок спрятаны в клубке из колючей проволоки, да ещё обильно присыпаны гвоздями. Какой там поиск иголок, не убиться бы насмерть.

Лемма: для выполнения даже самой элементарной новой функции линукс-система всегда подтянет кучу ненужных зависимостей, причём даже с «лёгкой» графикой рост системной энтропии получается кратный.

Теорема: в любом конечном наборе программных пакетов всегда найдётся бесконечно малый кусок кода, который попытается записать один бесконечно бесполезный бит на файловую систему, смонтированную в read-only, чем вызовет фатальную ошибку, повалит всю систему и перечеркнёт многочасовые усилия оператора.

Решение: UnionFS

Один немец несколько лет назад придумал очень красивый способ собрать все эти иголки в корыто с помощью UnionFS и просто сжигать их в печи при каждой перезагрузке. К сожалению, оригинальный пост уже погиб вместе с хостившим его доменом, но немец точно не одинок. Благодарные читатели сохранили идею, я считаю просто необходимым опубликовать её здесь.

Суть в том, что поверх постоянной «подложки» (read-only файловой системы на microSD) при каждом включении создаётся временная «нашлёпка» в ОЗУ, поглощающая всю ненужную энтропию и «сгорающая» при выключении питания устройства. Файловая система на microSD всё время остаётся read-only, и потому риск её повреждения снижается почти до нуля, как и риск преждевременного износа флэшки. Почему не строго до нуля? Знатоки EXT4, поправьте меня, но драйвер файловой системы всё-таки что-то записывает на носитель при каждом монтировании-демонтировании файловой системы, даже если она монтируется в read-only. И noatime не поможет.

Недостатки

Какие минусы, помимо «сгорания» логов? Устройства без аппаратных часов при старте всегда считают, что на дворе 1 января 1970 года, и пребывают в этом заблуждении вплоть до подъёма сетевого стэка и доступности NTP. Поэтому на момент данной публикации целый ряд файловых объектов «нашлёпки» будут примерно на 46 лет моложе, чем им кажется. С другой стороны, несколько секунд от начала эпохи — уже не ноль.

Обновления безопасности накатывать на такую систему довольно неудобно. Но, опять же, взломать такую Вещь несколько сложнее, чем эксплуатировать уязвимость Adobe Flash в браузере обычного десктопа.

Пошаговая инструкция

Поскольку я впервые в жизни установил Rasbian Jessie и особо не верю в долговечность microSD даже в read-only, то решил записать все шаги подробно. Вдруг понадобится повторить.

DISCLAIMER

Извините за переносы строк. Все команды запускаются с правами root, но аккуратный читатель может использовать каждый раз sudo. Честно говоря, я не понимаю, зачем каждую команду запускать через sudo, будто это защитит от чего-то. Вот скажите, когда вы в последний раз *не были* уверены, что хотите удалить данный файл в корзину? Это как выпить пять бокалов пива по пол-литра, но на дорожку ещё налейте один 0.33, пожалуйста, а то мне уже хватит… Я дам неправильный совет: если уж взялись за эти игрушки, выходите на root командой sudo bash, не занимайтесь самообманом.

1. Инициализация

Установите Raspbian Jessie Lite. Утилитой raspi-config задайте региональные настройки и пароль пользователя pi. Подключите сеть, Debian — дитя широкополосного доступа. Загрузку в графику пока не включайте.

apt-key update
apt-get update

2. Установка и удаление программ

С графикой, установка:

apt-get install --no-install-recommends tightvncserver xtightvncviewer xserver-xorg xinit lxde-core lxappearance lightdm feh xprintidle policykit-1 busybox-syslogd ntpdate watchdog unionfs-fuse

Удаление:

dpkg --purge rsyslog
apt-get remove --purge wolfram-engine triggerhappy cron anacron logrotate dphys-swapfile fake-hwclock
apt-get autoremove --purge

Пакеты tightvncserver, xtightvncviewer, xprintidle и feh понадобились мне для частной задачи, можете обойтись без них.

Если без графики, вам *не* понадобятся также: xserver-xorg xinit lxde-core lxappearance lightdm policykit-1.

3. Создание графического окружения

Теперь утилитой raspi-config можно включить автозапуск в графическом режиме с автовходом, который будет с правами пользователя pi. Чем зацикливаться на sudo, лучше поставить сильный пароль пользователю pi, и не использовать pi для автоматического входа в графический интерфейс. Вместо этого создать пользователя pu и запускать «иксы» с его правами. Причём командный интерпретатор (default shell) этого пользователя лучше либо отключить совсем (поставив /usr/sbin/nologin), либо подменить специальным скриптом типа /usr/local/bin/pu. Об этом я намерен рассказать в другой публикации, посвящённой видеотабло с удалённым управлением по SSH, ради чего и создаётся отдельная учётная запись с пониженными правами. Ещё раз благодарю Sauron et al.

adduser --home /home/pu --shell /usr/local/bin/pu --uid 990 --gecos "RPi p-u" --gid 1000 pu
mkdir -p /home/pu/.config/lxsession/LXDE
cp -p /etc/xdg/lxsession/LXDE/desktop.conf /home/pu/.config/lxsession/LXDE/desktop.conf
touch /home/pu/.config/lxsession/LXDE/autostart
chown -R pu:pi /home/pu
sed -i 's/^#?xserver-command=.*$/xserver-command=X -s 0 -dpms -nocursor/' /etc/lightdm/lightdm.conf
sed -i 's/^#?autologin-user=.*$/autologin-user=pu/' /etc/lightdm/lightdm.conf

Вместо двух последних команд можете открыть редактором /etc/lightdm/lightdm.conf и задать значения двух параметров, первый я уже упоминал выше, второй говорит сам за себя:

...
xserver-command=X -s 0 -dpms -nocursor
...
autologin-user=pu
...

4. Сторожевой таймер (по желанию)

У меня Raspberry Pi 3 Model B, поэтому ядерный модуль сторожевого таймера зовут так:

modprobe bcm2835_wdt
echo "bcm2835_wdt " | sudo tee -a /etc/modules

Затем добавляем следующую строку в секцию [Install] в конце файла /lib/systemd/system/watchdog.service:

[Install]
WantedBy=multi-user.target

После этого включаем службу:

systemctl enable watchdog.service

Сторожевой таймер в минимальной конфигурации должен сработать, если зависло ядро. Но есть ещё много других вариантов, например, по чрезмерной нагрузке на систему, по истечению памяти, по перегреву системы, по отсутствию сигнального файла и т.д. См. также watchdog(8) и watchdog.conf(5)

5. Параметры старта

Я отключил отображение малинового лого и swap-файл, включил быструю загрузку. Для этого добавил в /boot/cmdline.txt буквально три слова logo.nologo fastboot noswap. У меня в итоге получилось так:

logo.nologo dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait fastboot noswap

6. Запечатывание корневой файловой системы Raspberry Pi в read-only

Вот теперь мы добрались, наконец, до главного.

Ниже скрипт, который следует расположить под именем mount_unionfs где-нибудь в /usr/local/bin. Не забудьте включить биты выполнимости +x (chmod 755 или 555). Обратите внимание на суффиксы .orig и .rw, они должны совпадать с подготовкой (далее):

#!/bin/sh
DIR=$1
ROOT_MOUNT=$(awk '$2=="/" {print substr($4,1,2)}' < /etc/fstab)
if [ $ROOT_MOUNT = "rw" ]; then
	/bin/mount --bind ${DIR}.orig ${DIR}
else
	/bin/mount -t tmpfs ramdisk ${DIR}.rw
	/usr/bin/unionfs-fuse -o cow,allow_other,suid,dev,nonempty ${DIR}.rw=RW:${DIR}.orig=RO ${DIR}
fi

Из других инструкций я решил воспользоваться советом и сделать следующее:

insserv -r bootlogs
insserv -r alsa-utils

rm -rf /var/lib/dhcp/
ln -s /tmp /var/lib/dhcp

Графические приложения очень любят записывать в /home что-нибудь ненужное, поэтому в дополнение к /etc и /var я включил ещё и /home. Подготовим разделы к переключению в режим UnionFS (внимание на суффиксы .orig и .rw):


cp -al /etc /etc.orig
mv /var /var.orig
mv /home /home.orig
mkdir /etc.rw /var /var.rw /home /home.rw

Наконец, файл fstab(5)

proc            /proc           proc    defaults        0       0
/dev/mmcblk0p1  /boot           vfat    ro              0       2
/dev/mmcblk0p2  /               ext4    ro              0       1
mount_unionfs   /etc            fuse    defaults        0       0
mount_unionfs   /var            fuse    defaults        0       0
mount_unionfs   /home           fuse    defaults        0       0
none            /tmp            tmpfs   defaults        0       0

7. Аудит системы и тест

Окиньте взглядом систему, уберите за собой .bash_history, всякие лог-файлы и т.д. Учтите, что они сейчас могут находиться не там, где обычно (например, в /var.orig вместо var).

Перезагрузите систему и посмотрите, что получилось. Если была допущена ошибка, есть большие шансы, что система уйдёт в single user и просто запустит консоль root. Если файловая система цела, перемонтировать её из read-only в read-write довольно просто:

mount -o rw,remount /

Если же система загрузилась нормально в read-only и выполняет все функции, поздравляю!
Это родилась Интернет-Вещь.

8. Распечатывание файловой системы

Если нужно распечатать систему, сперва верните коневую систему в состояние read-write (см. выше). Затем закомментируйте в fstab(5) строки, начинающиеся со слова mount_unionfs, после чего *обязательно* верните на место каталог /var.orig со всем содержимым (и желательно /home.orig тоже). Если не восстановить /var, потеряете базу установленных пакетов, но ведь именно ради установки обновлений безопасности командой apt-get вы только что распечатали систему, не так ли? Перед apt-get перезагрузите систему и убедитесь в её адекватности. Как запечатывать обратно, знаете;)

Альтернативы

Уважаемых читателей, которые знают готовые промышленные образы операционных систем (с поддержкой read-only) для Raspberry Pi и других одноплатных компьютеров, приглашаю делиться в комментариях. Надеюсь, с вашей помощью я смогу информационно обогатить этот раздел и других читаталей, резидентов и гостей уважаемого портала Geektimes:)

Что касается аппаратных альтернатив самому Малиновому Прогу в контексте прикладной задачи (сетевой HDMI-свисток), то я случайно наткнулся на один обзор, который, впрочем, намерен обсудить отдельно. Чисто экономически Raspberry Pi весьма выгоден, это пока главное:)

Ссылки

Make Raspbian System Read-Only
blog.pi3g.com/2014/04/make-raspbian-system-read-only

How to make RaspberryPi truly read-only, reliable and trouble-free
k3a.me/how-to-make-raspberrypi-truly-read-only-reliable-and-trouble-free

Stopping SD Card Corruption on Raspberry Pi’s Raspbian
ideaheap.com/2013/07/stopping-sd-card-corruption-on-a-raspberry-pi

Raspberry Pi как информационное табло — с помощью VNC на localhost
habrahabr.ru/post/212661

*Easy Raspberry Pi Based Screensaver/Slideshow for Exhibitions/Store Front
www.instructables.com/id/Easy-Raspberry-Pi-Based-ScreensaverSlideshow-for-E
*у меня вызвал искреннее недоумение шаг 6

ECIO(TM), a powerful USB programmable single chip computer based on PICmicro microcontroller technology
www.matrixtsl.com/product.php?Prod=ECIO28P

Автор: teleghost

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js