Rootfs только для чтения: как сохранить настройки, журналы и состояние обновления
Корневая файловая система Linux только для чтения помогает сохранять программный образ неизменным при обычной эксплуатации, но продукту всё равно нужно записываемое состояние. Настройки сети должны переживать перезагрузку, журналам требуется ограниченное хранилище, а обновление должно сохранять достаточно информации для восстановления. Задача проектирования — явно определить срок жизни, владельца и политику отказа для каждого типа данных.
Начните с инвентаризации записей
Для каждого сервиса перечислите, что и когда он записывает, максимальный объём и поведение при ошибке записи. Учтите программы ранней загрузки, DHCP-клиенты, идентичность SSH, состояние часов, базы данных и аварийные дампы. Даже редко записывающее приложение может помешать запуску, если его стандартный путь расположен на файловой системе только для чтения.
| Класс данных | Типичное место | Требуемое поведение |
|---|---|---|
| Системные программы и заводские настройки | Rootfs только для чтения | Замена контролируемым обновлением ПО |
| Сокеты выполнения, PID-файлы и временные данные | Ограниченный tmpfs в /run или /tmp | Повторное создание при каждой загрузке |
| Конфигурация заказчика | Постоянный каталог приложения | Проверка, версионирование и сохранение при поддерживаемых обновлениях |
| Идентичность устройства и учётные данные | Постоянное хранилище с ограниченным доступом или аппаратной защитой | Уникальное предоставление и явная политика сброса |
| Диагностика | Ограниченная энергозависимая и/или постоянная область журналов | Соблюдение сроков хранения, приватности и бюджета места |
| Метаданные и подготовка обновления | Зарезервированная постоянная область или неактивный слот | Сохранение при необходимых переходах восстановления |
Пути в таблице описывают роли, а не универсальную разметку. Плата с eMMC, небольшое устройство NOR и сырая NAND требуют разной интеграции накопителя. Выбирайте файловую систему и схему обновления, поддерживаемые реальными BSP, загрузчиком и технологией флеш-памяти.

Выберите неизменяемый слой и границы записи
SquashFS — сжатая файловая система только для чтения. Ещё один вариант — корневая ext4, смонтированная только для чтения, с другими особенностями образа и восстановления. Ни один вариант сам по себе не подтверждает подлинность работающего ПО. Если нужна проверенная программная среда, проектируйте цепочку доверия: dm-verity проверяет целостность блоков по доверенному корневому хешу и должен быть встроен в доверенный путь загрузки.
Предпочитайте отдельные записываемые пути приложения разрешению записи во весь /etc. Оставляйте значения по умолчанию в образе, а явные переопределения заказчика храните отдельно. Для старого ПО с фиксированным путём bind-монтирование может предоставить там постоянный каталог приложения. Создайте точки монтирования в образе и установите владельцев до запуска сервиса.
OverlayFS на весь корень позволяет поддержать ПО с многочисленными жёстко заданными путями записи, но добавляет особенности обновления. Старый файл верхнего слоя может скрывать исправленный файл нового нижнего образа. Маркеры удаления тоже могут сохранять устаревшее представление. Определите, отбрасывается ли верхний слой, мигрируется или привязан к определённому поколению образа.
Для OverlayFS записываемая верхняя файловая система должна поддерживать необходимые расширенные атрибуты и сведения записей каталогов; рабочий каталог должен быть пустым и находиться на той же файловой системе, что верхний каталог. Сверяйте документацию ядра по OverlayFS с установленным ядром. Не считайте произвольные версии ядер поставщиков взаимозаменяемыми.
Сделайте порядок загрузки условием корректности
Смонтируйте постоянное хранилище, проверьте ожидаемые идентичность и структуру, инициализируйте нужные каталоги, выполните утверждённую миграцию и только затем запускайте приложения. Не переходите незаметно на пустой каталог в RAM при отсутствии критически важной постоянной конфигурации. Выберите заметный режим восстановления или документированный режим ограниченной функциональности.
Для старого приложения следующий пример показывает связь путей после успешного монтирования тома данных. Оба каталога должны уже существовать, а права — соответствовать учётной записи сервиса. Встройте шаги в выбранную систему инициализации, а не выполняйте их на поздней стадии загрузки.
# /data is the verified, mounted persistent filesystem.
# /etc/myapp is a mount point created in the rootfs image.
mount --bind /data/config/myapp /etc/myapp
# Start myapp only after this mount succeeds.
Зависимости systemd и скрипты BusyBox/SysV по-разному задают порядок. Изучите фактический каркас Buildroot, выбранную систему инициализации и скрипты сервисов. Проверьте /proc/mounts на устройстве, чтобы увидеть реальные монтирования, в том числе не остался ли под неудавшейся точкой монтирования обычный каталог.
Сохраняйте конфигурацию при прерванной записи
Проверяйте новую конфигурацию до активации. Для однофайлового формата типичная прикладная последовательность фиксации записывает временный файл в том же каталоге, синхронизирует его, переименовывает поверх текущего файла и синхронизирует каталог. Проверяйте каждое возвращаемое значение и сохраняйте заведомо исправное поколение, если продукт требует восстановления.
validate(candidate)
write(temp_in_same_directory, candidate)
fsync(temp_file)
rename(temp_file, active_file)
fsync(parent_directory)
report_success()
Это псевдокод, а не готовая утилита. Устанавливайте права до публикации файла, учитывайте конкурирующие записи и используйте транзакционную базу, если несколько записей должны изменяться вместе. Документация Linux по fsync объясняет, почему синхронизация одного файла не обязательно сохраняет его запись каталога. Долговечность данных всё равно зависит от файловой системы, драйвера и накопителя; проверяйте отключение питания на реальном оборудовании.
Выделите отдельные бюджеты журналам и временным файлам
Tmpfs использует виртуальную память, может задействовать включённый swap и теряет содержимое при размонтировании. Ограничьте байты и inode, затем включите этот бюджет в испытания пиковой памяти. Большой неограниченный каталог журналов в RAM может исчерпать память у в остальном исправного приложения.
В образах systemd значение Storage=volatile сохраняет журнал в /run/log/journal; постоянное хранение использует /var/log/journal, когда он доступен. Настройте RuntimeMaxUse или SystemMaxUse для выбранного режима по документации journald поставляемой версии. BusyBox syslog требует собственных настроек размера, ротации и назначения.
Резервируйте место конфигурации и обновлений независимо от подробной диагностики. Каталоги на общей файловой системе сами по себе не изолируют ёмкость; используйте подходящие квоты, разделы или явное резервирование. Определите события, которые должны переживать отключение питания, и удаляйте секретные учётные данные из журналов. Удалённое журналирование полезно только при определённом поведении для потери связи, роста очереди и пропусков доставки.
Проектируйте постоянные данные вместе с откатом
Программные слоты A/B не создают автоматически данные приложения A/B. Новое приложение может преобразовать общую базу в формат, который старое не читает. Возможны обратно совместимые схемы, отдельные поколения данных или явно проверенный путь восстановления. Руководство RAUC по хранению данных рассматривает общие и резервируемые разделы и подчёркивает необходимость продуктовой реализации миграции.
Не допускайте, чтобы подготовка обновления исчерпывала место для конфигурации. Различайте загруженный пакет, проверенный пакет, выбранный загрузочный слот и подтверждённую успешную загрузку. Постоянно храните лишь состояние, необходимое выбранной системе обновления. Сброс к заводским настройкам должен иметь письменное описание: удаляет ли он настройки заказчика, сохранённые журналы, учётные данные и идентичность устройства. Этим категориям часто требуется разная обработка.
Приёмочные испытания и диагностика
| Внесённый отказ | Определяемый ожидаемый результат | Что проверить первым |
|---|---|---|
| Отключение питания при фиксации конфигурации | Действительное предыдущее или новое поколение, без молчаливого принятия повреждённых настроек | Проверка конфигурации, маркеры поколений и ошибки файловой системы |
| Постоянный том отсутствует или повреждён | Документированное восстановление | Журнал монтирования, идентичность устройства и порядок запуска приложения |
| Исчерпаны байты или inode журналов | Политика конфигурации и обновления по-прежнему соблюдается | Ёмкость файловой системы, использование inode и ошибки журналирования |
| Обновление с последующим откатом | Старое ПО может использовать сохранённые или восстановленные данные | Версии схем и журнал миграции |
| Холодная загрузка после интенсивного использования временных файлов | Состояние выполнения воссоздано в пределах бюджета памяти | Ограничения tmpfs и записи пиков памяти |
| Новая rootfs со старым оверлеем | Обновлённые значения по умолчанию и программы видимы как предусмотрено | Файлы верхнего слоя, маркеры удаления и политика миграции |
Если настройки исчезают, сначала проверьте, что записываемый путь постоянный и смонтирован до использования. Если старое поведение сохраняется после обновления, исследуйте маскирование оверлеем и сохранённую конфигурацию. Если сервис сообщает «файловая система только для чтения», найдите конкретную попытку записи вместо перевода всего корня в режим записи. Эти испытания требуют контролируемого внесения отказов в лаборатории и согласованного восстановления; результатов испытаний отключением питания здесь не заявлено.
Диагностика прошивки и BSP от Obeita подходит для начала анализа накопителя и загрузки. Реализованный проект HMI на Linux/Qt даёт связанный контекст терминала. Этот проект не подтверждает проверку описанной здесь архитектуры постоянного хранения.