🦔

YoctoとRAUCでアップデート環境を構築してみる

2024/03/19に公開

Yoctoのビルドができるようになったので、RAUCでソフトウェアアップデートが行える環境を構築してみました。

環境の準備

今回はRaspberry Pi 4Bで試してみます。
以下の記事に従ってYoctoのビルド環境を構築してください。
https://zenn.dev/kobayutapon/articles/30e38cf076a01b
https://zenn.dev/kobayutapon/articles/a586249c89d42b

※Ubuntu 22.04の環境では、ファイルの取得で先に進まなくなってしまいました。その場合はDockerを使うのが良いと思います。

ディレクトリ構成は以下のようにしています。

|- poky
    |
    |- pi-build (build directory)

RAUCのレシピを追加

以下のコマンドを実行し、RAUCに関連するレイヤー、レシピを追加します。

bitbake-layers layerindex-fetch meta-rauc

# pokyディレクトリ以下で実行
git clone https://github.com/rauc/meta-rauc-community.git -b kirkstone
cd pi-build
bitbake-layers add-layer ../meta-rauc-community/meta-rauc-raspberrypi

証明書などの作成

必要なレイヤーを取得、追加出来たらRAUCのバンドル作成に使う証明書などを作成します。
以下のコマンドを実行し、生成します。

# pi-build以下で実行
../meta-rauc-community/create-example-keys.sh

このコマンドを実行するとpi-build以下にexample-caというディレクトリが作成され、ここに必要な署名が作成されます。

$ ls -al ./example-ca/
合計 68
drwxr-xr-x 4 kobayashi kobayashi 4096  319 09:30 .
drwxr-xr-x 8 kobayashi kobayashi 4096  319 11:12 ..
-rw-r--r-- 1 kobayashi kobayashi 4387  319 09:30 ca.cert.pem
-rw-r--r-- 1 kobayashi kobayashi  944  319 09:30 ca.csr.pem
drwxr-xr-x 2 kobayashi kobayashi 4096  319 09:30 certs
-rw-r--r-- 1 kobayashi kobayashi 4370  319 09:30 development-1.cert.pem
-rw-r--r-- 1 kobayashi kobayashi  936  319 09:30 development-1.csr.pem
-rw-r--r-- 1 kobayashi kobayashi  142  319 09:30 index.txt
-rw-r--r-- 1 kobayashi kobayashi   21  319 09:30 index.txt.attr
-rw-r--r-- 1 kobayashi kobayashi   21  319 09:30 index.txt.attr.old
-rw-r--r-- 1 kobayashi kobayashi   74  319 09:30 index.txt.old
-rw-r--r-- 1 kobayashi kobayashi 1731  319 09:30 openssl.cnf
drwxr-xr-x 2 kobayashi kobayashi 4096  319 09:30 private
-rw-r--r-- 1 kobayashi kobayashi    3  319 09:30 serial
-rw-r--r-- 1 kobayashi kobayashi    3  319 09:30 serial.old

設定でこれらの署名を指定する必要があります。

RAUCを使う設定

local.confを修正し、RAUCを使えるようにします。
以下local.confの修正部分を記載します。

# Kernel 6.1系列を使う
PREFERRED_VERSION_linux-raspberrypi = "6.1%"

# UARTを使用し、u-bootを使用する(RAUCでu-bootが必要)
ENABLE_UART = "1"
RPI_USE_U_BOOT = "1"

# systemdを使用する
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# Settings for meta-rauc-raspberry-pi
IMAGE_INSTALL:append = " rauc"
IMAGE_FSTYPES:append = " ext4"
WKS_FILE = "sdimage-dual-raspberrypi.wks.in"

DISTRO_FEATURES:append = " rauc"

# 証明書関連の設定
RAUC_KEY_FILE="/build/poky/pi-build/example-ca/private/development-1.key.pem"
RAUC_CERT_FILE="/build/poky/pi-build/example-ca/development-1.cert.pem"

#RAUC_KEYRING_FILE ?= "ca.cert.pem"
#RAUC_KEYRING_URI ?= "file:///build/poky/pi-build/example-ca/${RAUC_KEYRING_FILE}"

この最初の部分はイメージにRAUCを組み込むための設定で、後の証明書関連の設定がバンドルの署名に使われる証明書関連の設定です。パスなどは自分の環境に合わせて適宜修正します。

※最後の2行のコメント抜けていたので修正しました。

レシピの修正

実際に使用するためにはレシピをいくつか修正しないといけません。
以下に修正する内容をまとめます。

ビルド時に使用する証明書

イメージを作成する際に、meta-rauc-community/meta-rauc-raspberrypi/recipes-core/rauc/files/にある証明書(ca.cert.pem)を使います。先ほど生成したモノとは異なるため、アップデートしようとすると証明書のチェックエラーで停止します。このファイルを先ほど作成した/example-ca/ca.cert.pemを使うようにします。
きちんとレシピファイルで対応するのが良いと思いますが、今回は面倒なのでコピーして使っています。

# pi-build上で実行
cp example-ca/ca.cert.pem ../meta-rauc-community/meta-rauc-raspberrypi/recipes-core/rauc/files

レシピファイルの指定の修正

/meta-rauc-community/meta-rauc-raspberrypi/recipes-core/bundles/update-bundle.bbの最後に署名に使うファイルの指定があります。ここの設定をコメントアウトします。

DESCRIPTION = "RAUC bundle generator"

inherit bundle

RAUC_BUNDLE_COMPATIBLE = "RaspberryPi4"
RAUC_BUNDLE_VERSION = "v20200703"
RAUC_BUNDLE_DESCRIPTION = "RAUC Demo Bundle"
RAUC_BUNDLE_SLOTS = "rootfs"
RAUC_SLOT_rootfs = "core-image-minimal"
RAUC_SLOT_rootfs[fstype] = "ext4"

# 以下2行をコメントアウト
#RAUC_KEY_FILE = "${THISDIR}/files/development-1.key.pem"
#RAUC_CERT_FILE = "${THISDIR}/files/development-1.cert.pem"

イメージのビルド

イメージを作成します。今回はcore-image-minimalを指定してビルドします。

bitbake core-image-minimal

./tmp/deploy/images/raspberrypi4-64/core-image-minimal-raspberrypi4-64.wic.bz2にイメージが作成されるので、これをSDカードに書き込みます。

Updaterの作り方

以下のコマンドでアップデートに使うバンドルを作成します。

bitbake update-bundle

正常に実行されると、./tmp/deploy/images/raspberrypi4-64/update-bundle-raspberrypi4-64.raucbというファイルが作成されます。これをアップデートの際に使用します。

動作確認

起動状態の確認

SDカードから起動したら以下のコマンドでRAUCが正常に動作しているか確認します。

rauc status

実行すると以下のように現在の状況が確認できます。

=== System Info ===
Compatible:  RaspberryPi4
Variant:
Booted from: rootfs.0 (A)

=== Bootloader ===
Activated: rootfs.0 (A)

=== Slot States ===
o [rootfs.1] (/dev/mmcblk0p3, ext4, inactive)
        bootname: B
        boot status: good

x [rootfs.0] (/dev/mmcblk0p2, ext4, booted)
        bootname: A
        mounted: /
        boot status: good

今回の例ではBootloaderは1面を持ち、システム領域はA/Bの2面持っています。A面から起動していることがわかります。

Updateの確認

先ほど作成したupdaterのバンドルを使ってOSをアップデートしてみます。
USBメモリに作成したraucbファイルをコピーし、マウント後にアップデートを行います。

# USBメモリを/mntにマウント
mount /dev/sda /mnt

# アップデートファイルをインストール
rauc install /mnt/rauc install /mnt/update-bundle-raspberrypi4-64.raucb

実行すると以下のようにメッセージが出て今起動している面とは別の面にアップデータがインストールされます。

installing
  0% Installing
  0% Determining slot states
 10% Determining slot states done.
 10% Checking bundle
 10% Verifying signature
 20% Verifying signature done.
 20% Checking bundle done.
 20% Checking manifest contents
 30% Checking manifest contents done.
 30% Determining target install group
 40% Determining target install group done.
 40% Updating slots
 40% Checking slot rootfs.1
 46% Checking slot rootfs.1 done.
 46% Copying image to rootfs.1
 47% Copying image to rootfs.1
 48% Copying image to rootfs.1
 49% Copying image to rootfs.1
 50% Copying image to rootfs.1
 51% Copying image to rootfs.1
 52% Copying image to rootfs.1
 .
 .
 .
 81% Copying image to rootfs.1
 82% Copying image to rootfs.1
 83% Copying image to rootfs.1
 84% Copying image to rootfs.1
 85% Copying image to rootfs.1
 86% Copying image to rootfs.1
 87% Copying image to rootfs.1
 88% Copying image to rootfs.1
 89% Copying image to rootfs.1
 90% Copying image to rootfs.1
 91% Copying image to rootfs.1
 92% Copying image to rootfs.1
 93% Copying image to rootfs.1
 94% Copying image to rootfs.1
 95% Copying image to rootfs.1
 96% Copying image to rootfs.1
 97% Copying image to rootfs.1
 98% Copying image to rootfs.1
 99% Copying image to rootfs.1
 99% Copying image to rootfs.1 done.
 99% Updating slots done.
100% Installing done.
idle
Installing `/mnt/update-bundle-raspberrypi4-64.raucb` succeeded

インストールが終わったらリブートして動作を確認します。

=== System Info ===
Compatible:  RaspberryPi4
Variant:
Booted from: rootfs.1 (B)

=== Bootloader ===
Activated: rootfs.1 (B)

=== Slot States ===
x [rootfs.1] (/dev/mmcblk0p3, ext4, booted)
        bootname: B
        mounted: /
        boot status: good

o [rootfs.0] (/dev/mmcblk0p2, ext4, inactive)
        bootname: A
        boot status: good

正常にアップデートが行われたときはB面から起動しています。
アップデートを行うたびにA/B交互に使われてアップデートを行っていきます。

その他の注意事項

bitbakeで指定するイメージについて

updaterのバンドルを作成するrootfsは、./meta-rauc-community/meta-rauc-raspberrypi/recipes-core/bundles/update-bundle.bbに直接記載されています。ほかのイメージを指定した場合はここを適宜修正する必要があります。

DESCRIPTION = "RAUC bundle generator"

inherit bundle

RAUC_BUNDLE_COMPATIBLE = "RaspberryPi4"
RAUC_BUNDLE_VERSION = "v20200703"
RAUC_BUNDLE_DESCRIPTION = "RAUC Demo Bundle"
RAUC_BUNDLE_SLOTS = "rootfs"

# bitbakeのイメージを変えた場合、ここも合わせて変更する
RAUC_SLOT_rootfs = "core-image-minimal"
RAUC_SLOT_rootfs[fstype] = "ext4"

#RAUC_KEY_FILE = "${THISDIR}/files/development-1.key.pem"
#RAUC_CERT_FILE = "${THISDIR}/files/development-1.cert.pem"

Partitionの構成を変更する

./meta-rauc-community/meta-rauc-raspberrypi/wic/にsdimage-dual-raspberrypi.wks.inという設定ファイルがあります。これを必要に応じて修正します。

デフォルトのパーティション構成はこのようになっています。

パーティション番号 サイズ FS形式 説明
Partition 1 130MByte VFAT 起動用パーティション
Partition 2 (可変) ext4 システムパーティション(A面)
Partition 3 (可変) ext4 システムパーティション(B面)
Partition 4 (可変) Extd 拡張パーティション
Partition 5 100MByte ext4 データパーティション
Partition 6 (可変) ext4 home用パーティション

データパーティションにはRAUCの起動情報が保存されています。起動時、/dataに自動でマウントされます。各種情報は/data/central.raucsファイルに保存されます。これを壊さないように管理する必要があります。

これでYocto上でソフトウェアアップデートの環境が構築できました。
次はHqwkbitと組み合わせたアップデータの配布システムを構築してみます。

Discussion