- PVSM.RU - https://www.pvsm.ru -

OTA обновление устройств с Linux

OTA обновление устройств с Linux - 1

TL;DR:

Mender [1].

Вступление

Недавно у меня возникла задача обновлять удалённо некоторое двузначное число 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

На сайте проекта можно почитать как всё это работает [2].

Кстати, Mender уже упоминался на хабре в статье [3] @MooooM [4], но внедрить его тогда не получилось.

Workflow

Я продемонстрирую процесс обновления системы на примере Raspberry Pi 3B c Raspberry Pi OS. Карта памяти от 8 ГБ и выше.

В качестве сервера Mender будем использовать бесплатный демо-сервер hosted.mender.io [5] (не более 10 устройств и 12 месяцев работы).

Подготовка образов будет производится на компьютере с Ubuntu 20.04.

В своей документации Mender рекомендуют примерно такой подход [6] для устройств с debian:

  1. Установка чистой ОС

  2. Подготовка эталонного образа

  3. Копирование эталонного образа на ПК

  4. Преобразование эталонного образа при помощи mender-convert

  5. Подготовка устройства (provisioning)

  6. Авторизация устройства

  7. Подготовка пакета обновления (artifact)

  8. Развёртывание обновления (deploy)

0. Сервер

Регистрируемся на hosted.mender.io [5].

1. Установка чистой ОС

Устанавливаем последнюю Raspberry Pi OS Lite [7] по инструкции [8].

Включаем последовательную консоль /boot/config.txt: enable_uart=1

2. Подготовка эталонного (golden) образа

Вставляем SD-карту в устройство(Raspberry Pi 3B) и подключаемся по uart при помощи minicom.

Меняем стандартный пароль при помощи raspi-config.

Настройте и проверьте подключение к интернету. Я подключил свою Raspberry по ethernet (не совсем over-the-air, знаю).

Создадим директорию /data, в которой будут храниться данные, которые должны сохраняться при обновлении образа системы.

Положим туда текстовый файл important_file.txt содержащий одну строку hello_habr.

3. Копирование эталонного образа

Выключаем устройство и вставляем SD-карту в компьютер:

Выводим список разделов:

lsblk -p
/dev/sda           8:0    1   7,4G  0 disk
├─/dev/sda1        8:1    1   256M  0 part
└─/dev/sda2        8:2    1   7,1G  0 part 

Размонтируем разделы:

umount /dev/sdX1
umount /dev/sdX2

Считываем образ с карты:

sudo dd if=/dev/sdX of=golden-image-1.img bs=4M status=progress

4. Преобразование эталонного образа при помощи mender-convert

Для подготовки образа нам понадобится mender-convert [9] и Docker [10].

git clone -b 2.5.0 https://github.com/mendersoftware/mender-convert.git
cd mender-convert
./docker-build

Проверяем ёмкость SD-карты, на которую будем устанавливать систему:

sudo fdisk -l
Disk /dev/sda: 7,38 GiB, 7910457344 bytes, 15450112 sectors

Переводим байты в мегабайты: 7910457344 / 1024 / 1024 = 7544 MB

Создаём файл с конфигурацией mender-convert ./configs/raspberrypi3_custom_config с вот таким содержимым:

RASPBERRYPI_CONFIG="raspberrypi3"
RASPBERRYPI_KERNEL_IMAGE="kernel7.img"
MENDER_KERNEL_IMAGETYPE="zImage"
MENDER_DEVICE_TYPE="raspberrypi3"
MENDER_STORAGE_TOTAL_SIZE_MB="7500"
MENDER_DATA_PART_SIZE_MB="1000"
IMAGE_ROOTFS_SIZE="-1"
MENDER_ADDON_CONNECT_INSTALL="y"

source configs/raspberrypi_config

MENDER_STORAGE_TOTAL_SIZE_MB — общий размер SD полученный ранее

MENDER_DATA_PART_SIZE_MB — размер раздела /data

MENDER_ADDON_CONNECT_INSTALL — флаг установки mender-connect [11] (позволит запускать командную строку на удалённом устройстве и передавать файлы)

Создаём директорию ./rootfs_overlay/etc/mender. Это оверлей файловой системы который будет записан на наш эталонный образ при запуске mender-convert.

Создаём файл конфигурации mender-client ./rootfs_overlay/etc/mender/mender.conf:

{
  "ServerURL": "https://hosted.mender.io/",
  "TenantToken": "XXXX",
  "UpdatePollIntervalSeconds": 300,
  "InventoryPollIntervalSeconds":  300
}

TenantToken - токен который нужно посмотреть [12] в hosted.mender.io (Settings->Organization and billing->Organization token).

Создаём файл конфигурации mender-connect ./rootfs_overlay/etc/mender/mender-connect.conf:

{
  "ShellCommand": "/bin/bash",
  "User": "pi"
}

Создаём директорию ./input и кладём в неё образ golden-image-1.img полученный ранее.

Запускаем mender-convert.  

sudo MENDER_ARTIFACT_NAME=release-1 ./docker-mender-convert --disk-image input/golden-image-1.img --config configs/raspberrypi3_custom_config --overlay rootfs_overlay/

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МБ) и потом скачивается устройствами.

5. Подготовка устройства (provisioning)

Записываем образ golden-image-1-raspberrypi3-mender.img на SD-карту:

sudo dd if=./deploy/golden-image-1-raspberrypi3-mender.img of=/dev/sdX bs=4M oflag=sync status=progress

Теперь разделы выглядят так:

/dev/sda           8:0    1   7,4G  0 disk
├─/dev/sda1        8:1    1   256M  0 part
├─/dev/sda2        8:2    1     3G  0 part
├─/dev/sda3        8:3    1     3G  0 part
└─/dev/sda4        8:4    1  1000M  0 part
Вывод uart при загрузке (у нас теперь есть U-Boot): 
U-Boot 2020.01-g83cf4883ec (Jul 09 2021 - 14:23:27 +0000)

DRAM:  948 MiB
RPI 3 Model B (0xa02082)
MMC:   mmc@7e202000: 0, sdhci@7e300000: 1
Loading Environment from MMC... OK
In:    serial
Out:   serial
Err:   serial
Net:   No ethernet found.
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
568 bytes read in 10 ms (54.7 KiB/s)
## Executing script at 02400000
switch to partitions #0, OK
mmc0 is current device
6320888 bytes read in 538 ms (11.2 MiB/s)
Kernel image @ 0x080000 [ 0x000000 - 0x6072f8 ]
## Flattened Device Tree blob at 2eff8c00
   Booting using the fdt blob at 0x2eff8c00
   Using Device Tree in place at 2eff8c00, end 2f002f2b

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0

6. Авторизация устройства

Через пару минут после включения устройства на главной странице hosted.mender.io должно появиться сообщение о том, что новое устройство ожидает аутентификации. После подтверждения статус устройства поменяется с pending на accepted.

OTA обновление устройств с Linux - 2

Через раздел Troubleshoot можно запустить удалённый терминал на устройстве (работает через mender-connect). При этом, на устройстве не включен ssh-сервер. Есть возможность передавать файлы через вкладку File transfer.

OTA обновление устройств с Linux - 3

Теперь мы можем обновлять устройство по воздуху и физический доступ к нему больше не понадобится.

7. Подготовка пакета обновления (artifact)

Возвращаемся к нашему эталонному образу (golden-image-1.img). Загружаем ОС и вносим необходимые изменения. Я, например, сделаю MQTT-клиента, который шлёт на брокер температуру процессора (под спойлером).

MQTT-клиент

Устанавливаем пакеты:

sudo apt-get update
sudo apt install -y mosquitto mosquitto-clients

Создаём systemd таймер: /etc/systemd/system/mqtt.timer

[Unit]
Description=run mqtt.service every minute

[Timer]
AccuracySec=1
OnCalendar=*:*:0/30
Unit=mqtt.service

[Install]
WantedBy=multi-user.target

Создаём сервис, который будет вызываться таймером mqtt.timer: /etc/systemd/system/mqtt.service

[Unit]
Description=mqtt publisher service

[Service]
Type=simple
ExecStart=/home/pi/mosquitto_pub.sh

[Install]
WantedBy=multi-user.target

Скрипт, который будет вызываться сервисом mqtt.service: /home/pi/mosquitto_pub.sh

#!/bin/bash
tcpu=$(</sys/class/thermal/thermal_zone0/temp)
mosquitto_pub -h test.mosquitto.org -t "habr/$(cat /data/important_file.txt)" -m "{"tcpu": $((tcpu/1000))}"

Делаем скрипт исполняемым:

chmod +x /home/pi/mosquitto_pub.sh

Запускаем таймер:

sudo systemctl enable mqtt.timer
sudo systemctl start mqtt.timer

После внесения изменений снова считываем образ с карты:

sudo dd if=/dev/sda of=golden-image-2.img bs=4M status=progress

Преобразовываем образ при помощи mender-convert:

sudo MENDER_ARTIFACT_NAME=release-2 ./docker-mender-convert --disk-image input/golden-image-2.img --config configs/raspberrypi3_custom_config --overlay rootfs_overlay/

Загружаем в hosted.mender.io новый релиз golden-image-2-raspberrypi3-mender.mender. Заодно можно загрузить первый релиз, если захотим откатиться.

8. Deploy

Развёртывание (deploy) можно создать для отдельного устройства, группы устройств или сразу для всех. После создания развёртывания в течении пяти минут устройство проверит есть ли для него доступное обновление и начнёт загрузку.

OTA обновление устройств с Linux - 4

После обновления проверим, начало ли устройство отправлять сообщения по MQTT (под спойлером):

MQTT Explorer

Установите MQTT Explorer [13].

Создайте подключение к mqtt://test.mosquitto.org, порт: 1883.

Подпишитесь на топик habr/#

Наблюдаем, как устройство остывает после недавнего апдейта:

OTA обновление устройств с Linux - 5

Выводы

Mender позволяет довольно легко добавить функцию обновления образа системы по воздуху в существующее устройство.

Внедрение Mender никак не повлияло на процесс разарботки эталонного образа и последующих обновлений. Эталонный образ служит лишь источником для создания пакетов обновления.

Open-source версия Mender позволяет делать намного больше, чем показано в этой статье, например, state-scripts [14], identy [15] и inventory [16] устройств и т.д. Open-source версию сервера Mender можно самостоятельно развернуть в облаке используя Kubernetes [17].

Рекомендую внимательно изучить список фич [18] доступных в open-source и коммерческих версиях. Open-source версия вполне работоспособна, но её может не хватить для того чтобы закрыть все потребности крупного проекта (нет автоматического перезапуска процесса обновления, дельта-апдейтов [19], мониторинга сервисов и т.д.).

Было бы интересно сравнить Mender c RAUC [20] или swupdate [21] в качестве клиента и hawkBit [22] в качестве бэкенда.

На этом все, спасибо за внимание.

Автор:
bao-eng

Источник [23]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/linux/368614

Ссылки в тексте:

[1] Mender: https://mender.io/

[2] работает: https://mender.io/how-it-works

[3] статье: https://habr.com/ru/company/deutschetelekomitsolutions/blog/520406/

[4] @MooooM: https://www.pvsm.ru/users/moooom

[5] hosted.mender.io: https://hosted.mender.io

[6] подход: https://docs.mender.io/3.0/system-updates-debian-family/convert-a-mender-debian-image#recommended-workflow

[7] Raspberry Pi OS Lite: https://www.raspberrypi.org/software/operating-systems/

[8] инструкции: https://www.raspberrypi.org/documentation/computers/getting-started.html#installing-images-on-linux

[9] mender-convert: https://github.com/mendersoftware/mender-convert

[10] Docker: https://docs.mender.io/system-updates-debian-family/convert-a-mender-debian-image#docker

[11] mender-connect: https://docs.mender.io/add-ons/overview

[12] посмотреть: https://hosted.mender.io/ui/#/settings/organization-and-billing

[13] MQTT Explorer: http://mqtt-explorer.com/

[14] state-scripts: https://docs.mender.io/artifact-creation/state-scripts

[15] identy: https://docs.mender.io/client-installation/identity

[16] inventory: https://docs.mender.io/client-installation/inventory

[17] Kubernetes: https://docs.mender.io/3.0/server-installation/production-installation-with-kubernetes

[18] список фич: https://mender.io/plans/features

[19] дельта-апдейтов: https://docs.mender.io/3.0/overview/delta-update

[20] RAUC: https://github.com/rauc/rauc

[21] swupdate: https://github.com/sbabic/swupdate

[22] hawkBit: https://github.com/eclipse/hawkbit

[23] Источник: https://habr.com/ru/post/582554/?utm_source=habrahabr&utm_medium=rss&utm_campaign=582554