ポータブルエッジサーバ開発環境の製作
作りたいもの
スマホアプリから使用する、ポータブルエッジサーバの開発環境を作成していきます。スマホとエッジサーバを同一のモバイルルータに接続し、使用時にはホストマシンなしでオペレーションできる構成にします。
ポータブルエッジサーバの概要
ハードウェア
手元にあるRaspberry Pi 4 (RasPi4)を使用します。RasPi4の安全なシャットダウン・サーバ監視等のため、こちらも手元にあるタッチパネル付きの液晶ディスプレイ(LCD)を接続しました。
ソフトウェア
Yoctoを使用してエッジサーバソフトウェアをビルドします。コンセプトとしてはハードウェア関連の機能はホスト上(非コンテナ)に、アプリケーションに関する機能はDockerコンテナ上にPythonで実装していきます。これによりアプリケーション開発時はPC等で行い、ポータブルが必要な屋外テスト時にはDockerイメージをRasPi4にプッシュしてゴーというような環境を作りたいと思います。
なおLCD上のUIはハードウェア関連機能(非コンテナ)に含めます。またUIとアプリケーション間のメッセージングにはMQTTを使用し、コンテナ越し・ネットワーク越しでメッセージングできるようにします。
Build host machine requirements
BSP bringup
まずはYocto 5.2のソースコードを取得します。まずはプロジェクト用のディレクトリを作り、その下にソースコードを取得します。
git clone -b walnascar-5.2 git://git.yoctoproject.org/poky
git clone -b walnascar git://git.yoctoproject.org/meta-raspberrypi
git clone -b walnascar git://git.openembedded.org/meta-openembedded
次にビルド環境を作成します。
cd poky
source oe-init-build-env ../build
これでディフォルトのbuild
ディレクトリが作成、環境変数がセットアップされbuild
ディレクトリに移動しました。../build
部分のディレクトリ名はプロジェクトに応じて変更してください。
次に取得したmeta-raspberryypi
およびmeta-openembedded
のレイヤをビルドに追加します。
bitbake-layers add-layer ../meta-raspberrypi/
bitbake-layers add-layer ../meta-openembedded/meta-oe/
bitbake-layers add-layer ../meta-openembedded/meta-python/
bitbake-layers add-layer ../meta-openembedded/meta-networking/
追加したレイヤは<project top dir>/<build dir>/conf/bblayers.conf
に保存されますが、絶対パスで保存されるため<build dir>
からの相対パスに書き換えます。
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
${TOPDIR}/../poky/meta \
${TOPDIR}/../poky/meta-poky \
${TOPDIR}/../poky/meta-yocto-bsp \
${TOPDIR}/../meta-raspberrypi \
${TOPDIR}/../meta-openembedded/meta-oe \
${TOPDIR}/../meta-openembedded/meta-python \
${TOPDIR}/../meta-openembedded/meta-networking \
"
プロジェクトの構成に合うようカスタマイゼーションします。<project top dir>/<build dir>/conf/local.conf
を編集します。
ターゲットマシンの定義します。
MACHINE ??= "raspberrypi4-64"
今回使用するLCD解像度(800x480)は標準ドライバでは対応されていないため、ブートローダへ設定(/boot/config.txt
)し、Kernelパラメータに追加します。(DMTフォーマットのカスタム解像度です)
# /boot/config.txt
RPI_EXTRA_CONFIG:append = "\n"
RPI_EXTRA_CONFIG:append = "hdmi_group=2\n"
RPI_EXTRA_CONFIG:append = "hdmi_mode=87\n"
RPI_EXTRA_CONFIG:append = "hdmi_cvt=800 480 60 6 0 0 0\n"
RasPiにてWiFiをenableするために、以下を追加します。
# required for wifi
LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"
initをsystemdに変更します。
DISTRO_FEATURES:append = " systemd"
INIT_MANAGER = "systemd"
これでビルドの準備ができました。ディレクトリ構成はこのようになります。
<project root> -+ build/
+ meta-openembedded/
+ meta-raspberrypi/
+ poky/
また、buildディレクトリには中間生成物、最終生成物が保存されます。buildディレクトリをgitで管理する場合は、以下のような.gitignore
ファイルを作るとよいです。
/cache/
/downloads/
/sstate-cache/
/tmp/
/bitbake-cookerdaemon.log
ビルドします。後述の通り
- ウインドウシステムが不要
- WLANスタックが必要
のため、ターゲットはcore-image-base
を使用し、必要な機能を追加していく方針とします。
bitbake core-image-base
ビルド時間はビルドマシンによりますが3時間程度でしょうか。
なお、bitbakeのエラーが発生する場合、このTipが役に立つかもしれません。
これで基本のBSPができました。
Flash and boot
ビルドされたイメージをSDカードにフラッシュします。
イメージファイルは<project top dir>/<build dir>/tmp/deploy/images/<target machine>/<build target>-<target machine>.rootfs-<timestamp>.wic.bz2
となります。
SDカードをUSBリーダ・ライタにセットします。Ubuntu24では自動的にマウントされてしまうため、アンマウントします。
以下のコマンドで書き込みます。ここではSDカードは/dev/sda
とします。
sudo bmaptool copy <project top dir>/<build dir>/tmp/deploy/images/raspberrypi4-64/core-image-base-raspberrypi4-64.rootfs-<timestamp>.wic.bz2 /dev/sda
書き込みが終わったら、SDカードをRasPi4にセットしRasPi4を起動します。
うまくいけばLCDに起動ログが表示され、CLIのログインが表示されます。
UI
MQTTブローカーとMQTTクライアントライブラリをインストールするため、build/conf/local.conf
に以下を追加しています。
IMAGE_INSTALL:append = " mosquitto"
IMAGE_INSTALL:append = " paho-mqtt-c"
IMAGE_INSTALL:append = " paho-mqtt-cpp"
こちらにまとめました。
ビルド対象に含めるため、以下のように追加します。 ${TOPDIR}/../meta-sample-ui \
IMAGE_INSTALL:append = " sample-ui"
IMAGE_INSTALL:append = " sample-ui-touchscreen"
IMAGE_INSTALL:append = " sample-ui-autorun"
WLAN
shellスクリプトが依存するためbashとmqtt_pubコマンドをインストールするため、build/conf/local.conf
に以下を追加しています。
IMAGE_INSTALL:append = " bash"
IMAGE_INSTALL:append = " mosquitto-clients"
こちらにまとめました。
ビルド対象に含めるため、以下のように追加します。 ${TOPDIR}/../meta-sample-connectivity \
IMAGE_INSTALL:append = " wlan-enablers"
IMAGE_INSTALL:append = " wlan-monitor"
ここまでで、こんなものができます。
WLANなし
DISCONNECTED
WLAN(モバイルルータ)の電源を入れて1分ほど待つと
CONNECTEDになりWLANインタフェースのIPが表示された
簡単なアプリケーションのログを表示するためにMQTTをpubすると
mosquitto_pub -d -t ui/state -m "{\"msg\":\"hello world!\"}"
Docker CE環境
Yocto標準の仮想化関連のレシピはmeta-virtualizationに入っています。まずはこれをダウンロードします。
git clone -b walnascar git://git.yoctoproject.org/meta-virtualization
Docker CE関連をビルド対象に含めるため、以下のように追加します。
${TOPDIR}/../meta-openembedded/meta-filesystems \
${TOPDIR}/../meta-virtualization \
DISTRO_FEATURES:append = " virtualization"
IMAGE_INSTALL:append = " packagegroup-docker"
これでターゲットデバイス上にDocker CE環境の準備ができました。
Docker CE環境(追記)
packagegroup-docker
はmeta-virtualization/recipes-core/packagegroups/packagegroup-container.bbで定義されていますが、以前のバージョンでは複数のパッケージで構成されていたようですが、現在はdocker
へのエイリアスになっているだけのようです。
IMAGE_INSTALL:append = " docker"
でもOKですね。
アプリケーションDockerコンテナ
まずはDocker CE環境の上に単独のコンテナを動かします。
こちらにまとめました。
リンク先にもありますが、ターゲットイメージのビルド内でコンテナイメージをビルドする際、コンテナイメージに不要なパッケージを含まないために、local.confのIMAGE_INSTALL:append
をCORE_IMAGE_EXTRA_INSTALL:append
に変更する必要があります。
CORE_IMAGE_EXTRA_INSTALL:append = " bash"
CORE_IMAGE_EXTRA_INSTALL:append = " mosquitto"
CORE_IMAGE_EXTRA_INSTALL:append = " mosquitto-clients"
CORE_IMAGE_EXTRA_INSTALL:append = " paho-mqtt-c"
CORE_IMAGE_EXTRA_INSTALL:append = " paho-mqtt-cpp"
CORE_IMAGE_EXTRA_INSTALL:append = " sample-ui"
CORE_IMAGE_EXTRA_INSTALL:append = " sample-ui-touchscreen"
CORE_IMAGE_EXTRA_INSTALL:append = " sample-ui-autorun"
CORE_IMAGE_EXTRA_INSTALL:append = " wlan-enablers"
CORE_IMAGE_EXTRA_INSTALL:append = " wlan-monitor"
CORE_IMAGE_EXTRA_INSTALL:append = " docker"
CORE_IMAGE_EXTRA_INSTALL:append = " sample-api-autorun"
実行時に必要なディスクスペースの確保
コンテナイメージのインポートなどで実行時にディスクスペースを必要とします。Yoctoでビルドされるwicはパーティション構成も含んでおり、rootfsのパーティションサイズはrootfsのサイズ+余白(IMAGE_OVERHEAD_FACTOR)となり余裕がありません。
そこでドキュメントにあるようにスペースを確保します。
私は64GBのSDカードを使っているので40GiB確保しました。これでrootfsパーティションはトータル52GiBになりました。今後の機能追加を考えても余裕があります。
IMAGE_ROOTFS_EXTRA_SPACE = "41943040"
こちらにまとめました。