OTA A/B обновление образа rootfs для IoT устройств с Linux при помощи проекта Mender. Недавно у меня возникла задача обновлять удалённо некоторое двузначное число IoT-устройств с Linux через интернет. Задачу нужно было решить быстро. Времени и желания изобретать что-то своё не было совсем. Устанавливать обновления вручную по ssh — нереально. Автоматизировать установку по ssh тоже, устройства могут неожиданно выключаться или терять сеть.  Поиск решений по обновлению IoT устройств показал, что, судя по всему, мне больше всего подходит Mender: end-to-end решение — клиент + сервер + инструменты A/B обновление rootfs — на устройстве есть два одинаковых раздела rootfs A и B. Система загружается с активного раздела A, устанавливает обновление на раздел B, загружается с раздела B и в случае успеха делает его активным. В случае неудачного обновления активным остаётся раздел A. работает с debian и yocto не использует контейнеры есть open-source версия под лицензией Apache v2 На сайте проекта можно почитать как всё это работает. Кстати, Mender уже упоминался на хабре в статье @MooooM, но внедрить его тогда не получилось. Я продемонстрирую процесс обновления системы на примере Raspberry Pi 3B c Raspberry Pi OS. Карта памяти от 8 ГБ и выше. В качестве сервера Mender будем использовать бесплатный демо-сервер hosted.mender.io (не более 10 устройств и 12 месяцев работы).  Подготовка образов будет производится на компьютере с Ubuntu 20.04.  В своей документации Mender рекомендуют примерно такой подход для устройств с debian: Установка чистой ОС Подготовка эталонного образа Копирование эталонного образа на ПК Преобразование эталонного образа при помощи mender-convert Подготовка устройства (provisioning) Авторизация устройства Подготовка пакета обновления (artifact) Развёртывание обновления (deploy) Регистрируемся на hosted.mender.io. Устанавливаем последнюю Raspberry Pi OS Lite по инструкции. Включаем последовательную консоль /boot/config.txt: enable_uart=1 Вставляем SD-карту в устройство(Raspberry Pi 3B) и подключаемся по uart при помощи minicom. Меняем стандартный пароль при помощи raspi-config.  Настройте и проверьте подключение к интернету. Я подключил свою Raspberry по ethernet (не совсем over-the-air, знаю). Создадим директорию /data, в которой будут храниться данные, которые должны сохраняться при обновлении образа системы. Положим туда текстовый файл important_file.txt содержащий одну строку hello_habr. Выключаем устройство и вставляем SD-карту в компьютер: Выводим список разделов: Размонтируем разделы: Считываем образ с карты: Для подготовки образа нам понадобится mender-convert и Docker. Проверяем ёмкость SD-карты, на которую будем устанавливать систему: Переводим байты в мегабайты: 7910457344 / 1024 / 1024 = 7544 MB Создаём файл с конфигурацией mender-convert ./configs/raspberrypi3_custom_config с вот таким содержимым: MENDER_STORAGE_TOTAL_SIZE_MB — общий размер SD полученный ранее MENDER_DATA_PART_SIZE_MB — размер раздела /data MENDER_ADDON_CONNECT_INSTALL — флаг установки mender-connect (позволит запускать командную строку на удалённом устройстве и передавать файлы) Создаём директорию ./rootfs_overlay/etc/mender. Это оверлей файловой системы который будет записан на наш эталонный образ при запуске mender-convert. Создаём файл конфигурации mender-client ./rootfs_overlay/etc/mender/mender.conf: TenantToken - токен который нужно посмотреть в hosted.mender.io (Settings->Organization and billing->Organization token). Создаём файл конфигурации mender-connect ./rootfs_overlay/etc/mender/mender-connect.conf: Меняем владельца и группу оверлея: Создаём директорию ./input и кладём в неё образ golden-image-1.img полученный ранее. Запускаем mender-convert.   MENDER_ARTIFACT_NAME — название релиза, которое будет отображаться в hosted.mender.io. Дальше происходит магия: в образ устанавливается U-Boot в Raspberry OS доустанавливается mender-client и mender-connect создаются A и B разделы rootfs исходя из общего размера SD-карты, а также размера раздела data данные из директории /data автоматически переносятся на новый раздел, который не будет перезаписываться при обновлении системы Подробнее можно посмотреть в ./logs/convert.log.XXXX. На выходе получаем: ./deploy/golden-image-1-raspberrypi3-mender.img - преобразованный образ системы для записи на SD-карту ./deploy/golden-image-1-raspberrypi3-mender.mender - архив с обновлением, который загружается на сервер Mender(519МБ) и потом скачивается устройствами. Записываем образ golden-image-1-raspberrypi3-mender.img на SD-карту: Теперь разделы выглядят так: Через пару минут после включения устройства на главной странице hosted.mender.io должно появиться сообщение о том, что новое устройство ожидает аутентификации. После подтверждения статус устройства поменяется с pending на accepted. Через раздел Troubleshoot можно запустить удалённый терминал на устройстве (работает через mender-connect). При этом, на устройстве не включен ssh-сервер. Есть возможность передавать файлы через вкладку File transfer. Теперь мы можем обновлять устройство по воздуху и физический доступ к нему больше не понадобится. Возвращаемся к нашему эталонному образу (golden-image-1.img). Загружаем ОС и вносим необходимые изменения. Я, например, сделаю MQTT-клиента, который шлёт на брокер температуру процессора (под спойлером). Устанавливаем пакеты: Создаём systemd таймер: /etc/systemd/system/mqtt.timer Создаём сервис, который будет вызываться таймером mqtt.timer: /etc/systemd/system/mqtt.service Скрипт, который будет вызываться сервисом mqtt.service: /home/pi/mosquitto_pub.sh Делаем скрипт исполняемым: Запускаем таймер: После внесения изменений снова считываем образ с карты: Преобразовываем образ при помощи mender-convert: Загружаем в hosted.mender.io новый релиз golden-image-2-raspberrypi3-mender.mender. Заодно можно загрузить первый релиз, если захотим откатиться. Развёртывание (deploy) можно создать для отдельного устройства, группы устройств или сразу для всех. После создания развёртывания в течении пяти минут устройство проверит есть ли для него доступное обновление и начнёт загрузку. После обновления проверим, начало ли устройство отправлять сообщения по MQTT (под спойлером): Установите MQTT Explorer. Создайте подключение к mqtt://test.mosquitto.org, порт: 1883. Подпишитесь на топик habr/# Наблюдаем, как устройство остывает после недавнего апдейта: Mender позволяет довольно легко добавить функцию обновления образа системы по воздуху в существующее устройство. Внедрение Mender никак не повлияло на процесс разарботки эталонного образа и последующих обновлений. Эталонный образ служит лишь источником для создания пакетов обновления. Open-source версия Mender позволяет делать намного больше, чем показано в этой статье, например, state-scripts, identy и inventory устройств и т.д. Open-source версию сервера Mender можно самостоятельно развернуть в облаке используя Kubernetes. Рекомендую внимательно изучить список фич доступных в open-source и коммерческих версиях. Open-source версия вполне работоспособна, но её может не хватить для того чтобы закрыть все потребности крупного проекта (нет автоматического перезапуска процесса обновления, дельта-апдейтов, мониторинга сервисов и т.д.). Было бы интересно сравнить Mender c RAUC или swupdate в качестве клиента и hawkBit в качестве бэкенда. На этом все, спасибо за внимание.