pi-builder - это удобный и расширяемый инструмент для сборки образов Arch Linux ARM для Raspberry Pi с использованием Docker.
Обычно для сборки операционок разработчики дистрибутивов используют набор шелл-скриптов. У каждого дистрибутива они, как правило, свои. С их помощью создается чрут с нужными пакетами, правятся конфиги, добавляются пользователи и выполняются иные операции. Таким образом обеспечивается необходимый минимум для успешной загрузки, работы и дальнейшей кастомизации оси руками конечного пользователя.
Однако если вы создаете какой-то собственный продукт на основе одноплатного компьютера (маленький роутер, IP-камеру или систему управления умным домом, что угодно), то скорее всего вам захочется каким-нибудь способом задокументировать все изменения, которые вы внесли в свежеустановленную операционную систему, и обеспечить себе возможность повторить эти настройки, не боясь забыть о каком-нибудь важном действии, типа настройки sysctl
.
Типичное решение в данном случае - написать большой и страшный скрипт, выполняющий все необходимые действия либо над развернутым на разработческой машине корнем, либо прямо на устройстве. При использовании chroot
и binfmt_misc, а так же при необходимости сохранения промежуточных стадий сборки сложность подобных скриптов сразу возрастает на порядок. А со временем они становятся абсолютно неподдерживаемыми.
По сути, это новый подход к сборке целевой операционной системы для встраиваемых устройств. Он позволяет собирать образ так, как если бы это была не система для реальной железки, а обычный докер-контейнер. Сборка системы описывается стандартным синтаксисом докерфайлов и выполняется в докере прямо на машине разработчика. Получившийся образ можно экспортировать на SD-карту и загрузить на Raspberry Pi.
- Документирование и повторяемость сборок. Докерфайлы - это практически готовая документация к последовательности действий, необходимых для настройки всей вашей системы.
- Простота. Ну серьезно, что может быть проще, чем написать докерфайл?
- Скорость и кеширование сборок. Сборка целевой системы может состоять из сотен сложных и долго выполняющихся команд. С помощью докера и его кешей вы можете не выполнять все эти команды каждый раз при сборке новой системы; сборка будет начинаться только с изменившихся команд, а результаты предыдущих будут браться из кеша.
- Тестирование на реальном окружении. Если вы разрабатываете какой-то софт, который должен работать на Raspberry Pi, совершенно логично тестировать его в том же окружении, в котором он будет работать на реальной железке - это избавит от многих потенциальных проблем.
Разработчики Arch Linux ARM (да и других систем) предоставляют для своих осей архивы с минимальными корневыми ФС, которые можно развернуть на флешке и загрузиться с них. И поскольку это обычные корни, из них также можно сделать собственный базовый образ для докера с помощю механизма FROM scratch. Однако этот образ будет содержать исполняемые файлы и библиотеки с архитектурой ARM
, и если ваша машина работает под другой архитектурой (скажем, x86_64
), то ни одна команда внутри этого образа у вас не запустится.
Для того, чтобы иметь возможность исполнять файлы с другой архитектурой, ядро Linux имеет специальный механизм binfmt_misc, который позволяет установить кастомный интерпретатор для архитектуры, отличной от системной. Таким образом, можно настроить binfmt_misc
для запуска ARM-бинарников с помощью эмулятора (в нашем случае - qemu-arm-static
для x86_64
). Pi-builder содержит небольшой скрипт, настраивающий в хост-системе binfmt_misc, чтобы иметь возможность запускать исполняемые файлы на ARM.
Сборка операционной системы в терминологии pi-builder делится на последовательные стейжи, представляющие какой-либо отдельный аспект настройки оси. Например, стейж ro включает в себя Dockerfile.part
с необходимыми инструкциями, чтобы сделать на системе read-only корень, и конфиги для этого. Другой пример - стейж watchdog, включающий все необходимое для настройки вачдога с оптимальными параметрами на Raspberry Pi.
Полный список стейжей, идущих в комплекте с pi-builder, можно посмотреть тут или в списке ниже. При сборке системы вы сами решаете, какие стейжи вам нужны, и просто включаете их в вашу конфигурацию. По сути, стейжи - это кусочки докерфайла которые при сборке склеиваются в указанной последовательности в один большой докерфайл и содержат все инструкции, которые будут выполнены на собираемой системе. Вы можете сами создать собственные стейжи по аналогии с имеющимися.
Последовательность сборки выглядит так:
- pi-builder скачивает статически скомпилированный
qemu-arm-static
от Debian и настраиваетbinfmt_misc
глобально на вашей машине. - Далее скачивается образ Arch Linux ARM и заряжется в докер в качестве базового образа.
- Производится сборка конейнера с необходимыми стейжами - установка пакетов, настройка конфигов, чистка и так далее.
- В получившемся контейнере можно запустить оболочку с помощью
docker run
(илиmake shell
), чтобы проверить, все ли в порядке. - С помощью утилиты docker-extract, входящей в состав pi-builder, контейнер извлекается из внутреннего хранилища докера и помещается в каталог, как обыкновенная развернутая корневая ФС.
- Готовую ФС можно скопировать на SD-карту и загрузить с нее Raspberry Pi.
Для сборки системы с помощью pi-builder вам понадобится свежий докер с возможностью запуска контейнера в привелегированном режиме (он требуется вспомогательному образу для установки binfmt_misc
, форматирования SD-карты и некоторых других операций).
Вся работа с pi-builder выполняется с помощью главного Makefile в корне репозитория. В его начале перечислены параметры, доступные для переопределения, которое можно выполнить, создав файл config.mk
с новыми значениями. Дефолтные значения таковы:
# Пространство имен для промежуточных образов, просто назовите как нравится
PROJECT ?= common
# Целевая платформа Raspberry Pi
BOARD ?= rpi
# Список необходимых стейжей, об этом подробнее ниже
STAGES ?= __init__ os pikvm-repo watchdog no-bluetooth no-audit ro ssh-keygen __cleanup__
# Имя хоста для получившейся системы
HOSTNAME ?= pi
# Локаль будущей системы (UTF-8)
LOCALE ?= en_US
# Таймзона будущей системы
TIMEZONE ?= Europe/Moscow
# Путь к карте памяти
CARD ?= /dev/mmcblk0
Самые важные параметры - это BOARD
, определяющий, под какую плату нужно собрать систему, STAGES
, указывающий, какие стейжи необходимо включить и CARD
, содержащий путь к устройству SD-карты. Вы можете переопределить их, передав новые значание вместе с вызовом make
, или создав файл config.mk
с новыми значениями.
Стейж __init__
всегда должен идти первым: он содержит инициализирующие инструкции для создания базового образа системы (FROM scratch
). Далее идут стейжи для "обживания" системы - установки полезных пакетов, настройки вачдога, приведения системы к ридонли, настройки ключей SSH для рута и очистки от временных файлов.
Вы можете создать собственные стейжи и включить их в сборку наравне с комплектными. Для этого просто заведите каталог для вашего стейжа в папке stages
и разместите в нем файл Dockerfile.part
по аналогии с любым другим стейжем. Как вариант, можно сделать так, как это устроено в проекте Pi-KVM (для которого, собственно, pi-builder и был разработан).
__init__
- главный стейж, формирующий базовый образ на основе корневой ФС Arch Linux ARM. Он ВСЕГДА должен идти первым в спискеSTAGES
.os
- просто ставит некоторые пакеты и настраивает систему, чтобы в ней было несколько более комфортно жить. Просто посмотрите его содержимое.ro
- превращает систему в ридонли-ось. В таком режиме Raspberry Pi можно просто выключать из розетки без предварительной подготовки, не боясь повредить файловоую систему. Для того, чтобы временно включить систему на запись (например, для обновления), используйте командуrw
; после всех изменений выполните командуro
для обратного перемонтирования в ридонли.pikvm-repo
- добавляет ключ и репозиторий проекта Pi-KVM. Нужно для вачдога, содержит другие дополнительные пакеты. Подключать не обязательно.watchdog
- настраивает аппаратный вачдог.no-bluetooth
- отключает блютуз и восстанавливает работоспособность UART0/ttyAMA0 на 14 и 15 пинах GPIO.no-audit
- отключает ядерный аудит.ssh-root
- удаляет пользователяalarm
, блокирует парольroot
и добавляет в его~/.ssh/authorized_keys
ключи из каталога stages/ssh-root/pubkeys. По умолчанию там лежат ключи разработчика pi-builder, так что обязательно их замените. Кроме того, этот стейж блокирует возможность логина через UART. Если вам требуется эта возможность, напишите свой собственный стейж с аналогичными функциями.ssh-keygen
- генерирует хостовые SSH-ключи. На этом стейже ВСЕГДА будет происходить пересборка системы. В обычной ситуации ручная генерация ключей не требуется, но если система загружается в ридонли, у SSH нет возможности сгенерировать ключи самостоятельно даже при первой загрузке.__cleanup__
- удаляет всякий мусор во временных папках, оставшийся от сборки.
Некоторые файлы, такие как /etc/host
и /etc/hostname
, автоматически заполняются докером и все изменения, вносимые в них из докерфайла, будут потеряны. В случае с именем хоста в Makefile
добавлен специальный костыль, которые записывает имя хоста в экспортируемую систему, или назначает это имя при запуске make run
. Так что если вам потребуется изменить что-нибудь в подобных файлах, то придется дописать это аналогичным образом в Makefile
.
Как собрать систему под Raspberry Pi 3 и поставить ее на SD-карту:
$ git clone https://github.com/pikvm/pi-builder
$ cd pi-builder
$ make rpi3
$ make install
Как собрать систему со своим списком стейжей:
$ make os BOARD=rpi3 STAGES="__init__ os __cleanup__"
Остальные команды и заданную сборочную конфигурацию можно посмотреть так:
$ make
===== Available commands =====
make # Print this help
rpi|rpi2|rpi3|rpi4|zero|zerow|zero2w # Build Arch-ARM rootfs with pre-defined config
make shell # Run Arch-ARM shell
make binfmt # Before build
make scan # Find all RPi devices in the local network
make clean # Remove the generated rootfs
make format # Format /dev/mmcblk0 to /dev/mmcblk0p1 (vfat), /dev/mmcblk0p2 (ext4)
make install # Install rootfs to partitions on /dev/mmcblk0
===== Running configuration =====
PROJECT = common
BOARD = rpi
STAGES = __init__ os watchdog no-bluetooth ro ssh-keygen __cleanup__
BUILD_OPTS =
HOSTNAME = pi
LOCALE = en_US
TIMEZONE = Europe/Moscow
REPO_URL = http://mirror.yandex.ru/archlinux-arm
CARD = /dev/mmcblk0
QEMU_PREFIX =
QEMU_RM = 1
- Важно: проверьте в Makefile путь к SD-карте в переменнjq
CARD
и отключите автомонтирование, чтобы свежеотформатированная карта памяти не прицепилась к вашей системе, и скрипт установки не зафейлился. - Очень важно: положите в каталог stages/ssh-root/pubkeys свой SSH-ключ, иначе не сможете потом залогиниться в систему, или не используйте стейж
ssh-root
. - Еще более важно: прочитайте весь этот README целиком, чтобы понимать, что и зачем вы все-таки делаете.
Copyright (C) 2018 by Maxim Devaev [email protected]
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.