この記事はAkerun Advent Calendar 6日目の記事です。
はじめまして、2月にフォトシンスに入社した いとう です。 Akerun入退室管理システムの中のハードウェアを動作させるファームウェアという奴をぼちぼち開発しています。
IoT機器を開発しているフォトシンスでは Zephyr RTOS をやっていこう!という話になり、今回はその開発環境構築の取り組みについて書いてみようと思います。あんまりZephyr本体の話は出てきません。
TL;DR
- 開発環境はコンテナだよ
- GitLabでDockerfile管理してGitLab CIでイメージ生成してGitLab Container Registry でイメージ管理するよ
- VSCode の Remote Development 使えばシャッキリポン
組み込みファームウェアの開発環境について
所感ですが、これまでのファームウェアエンジニアは開発環境について良くも悪くもあまり頭を悩ませずにきたと思います。なぜなら採用したマイコン・SoCベンダーからIDE一式が提供(推奨)され、それをサンプルコードそのまま使うケースがほとんどだからです(観測範囲狭し)。まあ、開発環境を作りたいのではなく製品を作りたいので当たり前といえば当たり前ですが・・・。
これまではそれでよかったのかもしれません。IDEのビルドボタンをポチッと押してビルドして、書き込みできれば仕事はできます。しかし、せっかく環境を一新するのであればこれまであった不満を解消したいじゃないですか。
- 不満① Git管理に向いていない
どこのIDEも同じですがIDEのプロジェクトファイル、Gitで管理しにくいですよね?プロジェクトファイル開いてビルドして閉じただけで差分が出てしまうしデバッガ使っただけで差分が出ます。明らかにプロジェクトファイルに変更がなければコミットしなければいいんですが、ファイルを追加したりインクルードディレクトリ追加したりしたらコミットせざるをえません。自動生成されるファイル類もGitで管理対象とすべきかどうか明文化されていないし。
- 不満② 環境構築に時間がかかる
今はPrallels Desktopで環境構築しているので最初にセットアップすればイメージファイルを移動させるだけで良いのですが、前職ではPCリプレイスするたびに丸1日以上かけて環境を構築していました。ARM純正のコンパイラ入れて、それにパッチ当てて、ライセンス設定して・・・
- 不満③ 気軽に開発体験できない
そして、個人的な1番の不満はこれです。弊社、最近エンジニアが増えてきていて、中にはウェブエンジニアが垣根を超えて組み込み開発やってみたいっていう危篤奇特な人達が何人かいるんですけど、みんな macOS なんですよね。Akerunのファームウェアをいじって遊べれば楽しいと思うんですが、Windowsでしか動作しないIDEやコンパイラ・・・気軽に体験してもらえないんです。
方針
Zephyr RTOS のガイド を見ればわかる通り Zephyr RTOS では Ubuntu, macOS, Windowsがサポートされていてセットアップ方法も懇切丁寧に記載されてます。つまりWindows縛りはありません。しかも cmake + ninja をベースとしたIDEレスな開発環境です。ただ、やはりあれこれとインストールしなければならないのは変わりませんので、これを解決するために開発環境をDockerコンテナで構築することにします。
開発環境をコンテナで
開発環境をDockerコンテナで構築するというのは今となっては珍しい話ではありませんね。Zephyr RTOSでは本家がCI用で使っているDockerfileをGitHubで公開していますし有志の方が公開しているDockerfileもあります。これを使えばいいのですがそのほかに必要なツール類も一括管理するために独自でDockerfileを作成しました。
FROM ubuntu:18.04 ARG SDK_VERSION=0.10.3 ENV ZEPHYR_SDK_SETUP zephyr-sdk-$SDK_VERSION-setup.run ENV ZEPHYR_TOOLCHAIN_VARIANT zephyr ENV ZEPHYR_SDK_INSTALL_DIR /opt/zephyr-sdk ENV PROJECT_DIR /hogehoge RUN apt-get update RUN DEBIAN_FRONTEND=noninteractive apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get install -y git cmake ninja-build gperf \ ccache dfu-util device-tree-compiler wget \ python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ make gcc gcc-multilib \ locales \ clang-format RUN pip3 install cmake west requests docopt RUN cd /tmp && wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${SDK_VERSION}/${ZEPHYR_SDK_SETUP} RUN chmod 755 /tmp/${ZEPHYR_SDK_SETUP} RUN /tmp/${ZEPHYR_SDK_SETUP} -- -d ${ZEPHYR_SDK_INSTALL_DIR} RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN locale-gen en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 ## 中略 〜秘密〜 中略 WORKDIR $PROJECT_DIR ENTRYPOINT ["/bin/bash", "-c"] CMD [ "/bin/bash", "-c" ]
今見返したらほぼ参考にした marshall/zephyr-docker
と同じでした。実はここからUbuntuベースではなくAlpine Linuxベースに変更しようとしたのですがパッケージマネージャから必要なツールが入手できずに断念した結果です(確かdevice-tree-copiler)。Zephyrはお好きなコンパイラ選べるんですが本家がリリースしているSDKを採用しています。(Locale設定しているのはなんでだっけ?)
イメージ生成、配布は GitLabで
さて、Dockerfileができたので皆にこれを使ってもらえばいいのですがまだ問題があります。それはapt-get
、pip
などのパッケージマネージャで取得したパッケージが更新されるとイメージを作る時期によって生成されるイメージが変わってしまい、さらにはパッケージレジストリのメンテが終了するとイメージ自体の生成に失敗してしまいます。この対策としてDockerイメージ生成して、それを共有することにしました。DockerイメージのレジストリはDocker Hubが有名ですが、ちょうど社内に導入した GitLab に Container Registry機能があったため、こちらを使用することとしました。
GitLabはCIが内蔵されており(最近GitHubでもできるようになりましたね)ブランチやタグのpushなどと連動して、GitLab Runnerを走らせているマシンで任意の処理を実行させることができます。試しに開発環境用Dockerfileのプロジェクトファイルのルートに .gitlab-ci.yml
という名称のファイルを作り↓の内容記載してGitLabにプッシュすると、Dockerビルド〜GitLabにDockerイメージをプッシュするところまでできてしまいました。
stages: - build - test - deploy variables: IMAGE_BRUNCH: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_BUILD_TAG before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY build: stage: build script: - docker build -t $IMAGE_BRUNCH . - docker push $IMAGE_BRUNCH tags: - build-docker tag-build: stage: build only: - tags - triggers script: - docker build -t $IMAGE_TAG . - docker push $IMAGE_TAG tags: - build-docker
たったこれだけで下記のように GitLab にイメージが格納されプロジェクトのメンバーであれば誰でもイメージが取得できるようになりました。しかもGit側でタグ打てば連動して Container Registry上でもタグが打たれてタグでバージョン管理ができます。
上記のイメージを引っ張ってきつつdocker runするには↓
docker run --name saituyo-env -it -v ~/host_no_repo/zephyr:/hogehoge odorenotokorono.gitlabnourl.com:5555/hogehoge/dev-env-docker:0.1.1
これでいつでも誰でも使える開発環境+再現可能な開発環境ができました!めでたしめでたし。
一歩進んで VS Code Remote Development
さて、めでたしめでたしなんですが、"みんなで使える"とうたった割には Docker自体の知識が少し必要だったり敷居が高いことは否めません。実際に自分で使ってみて課題も出てきました。
- Dockerの使い方を勉強する必要がある(メンテ用コマンドとか)
- 特定のブランチ、タグがどのバージョンの開発環境に対応しているのか不明
- コンテナ生成初回におまじないがある
- これはZephyr固有の問題ですがセットアップ時にあれだけ色々インストールしているのに、ビルドするためには追加のpythonのパッケージが必要となります。しかもこの必要パッケージのリストはZephyrのソースコードの中にあるため、どうしても開発環境コンテナの中には組込めませんでした。
- あと各種の環境変数をセットアップするのにやはりソースコード内のスクリプトを実行する必要がありこれも開発環境コンテナの中には組込めませんでした。
どうしたか?
世の中便利になったもので VSCode にはDockerコンテナの中でプロジェクトを編集できる VSCode Remote Development 機能拡張があります。この機能拡張をインストールしたVSCodeでプロジェクト直下に.devcontainer/devcontainer.json
を配置していると記載した設定にしたがってプロジェクト全体をDockerコンテナ上でマウントした状態で立ち上げてくれます。そしてdevcontainer.json
に下記のように記載すると、なんと!自動的にイメージをGitLabから取ってきて、さらには Pythonの必要パッケージのインストール、環境変数のセットアップまでやってくれます。
{ "name": "hogehoge firmware", "image": "odorenotokorono.gitlabnourl.com:5555/hogehoge/dev-env-docker:0.1.1", "extensions": [ "ms-vscode.cpptools", "EditorConfig.EditorConfig", "plorefice.devicetree", "twxs.cmake", "eamodio.gitlens", ], "runArgs": [ "-v", "${env:HOME}${env:USERPROFILE}/.ssh:/root/.ssh-localhost:ro" ], "postCreateCommand": "pip3 install -r zephyr/scripts/requirements.txt && echo 'source ./zephyr/zephyr-env.sh' >> ~/.bashrc && mkdir -p ~/.ssh && cp -r ~/.ssh-localhost/* ~/.ssh && chmod 700 ~/.ssh && chmod 600 ~/.ssh/*" }
(sshをごにょごにょしているのはコンテナ内でもホスト環境のssh鍵を継承してgitにアクセスするためです)
そして、この.devcontainer
自体もgit管理プロジェクトとして組み込んでしまえば特定バージョンのソースコードに連動した開発環境をVSCodeが自動的に引っ張ってきてくれるようになります。実際はソースコードのリポジトリに.devcontainer
をコミットしたわけでなく独立したGitLabのプロジェクトとして存在して、Zephyr (west) の複数Gitリポジトリ管理機能でファームウェアソースコードリポジトリと同期させてます。
これでVSCodeを使う限りDockerの知識がなくてもソースコードのディレクトリを開くだけで追加おまじない不要なビルド環境が付いてくる、"みんなで使える"開発環境が用意できました!ただ、開発環境をVSCodeで完全に縛ってしまうと夜道でVimmerにさっくりやられてしまう世知辛い世の中ですので、純Dockerで使える環境はキープするのが全体的に幸せと思われます。
まとめると
- 各自の環境にインストールすのは
git / python3 / west / VSCode / Docker
だけ west init
でリポジトリ取ってきてVSCodeで開き、おもむろにTerminalでwest build hogehoge
とするともうファームウェアが出来ちゃう
という個人的には理想に近い環境が出来上がりました!あとはこの環境でみんなで開発を進めていくだけです。
オチ
回路エンジニア(Windows)の方が環境構築に挑戦したところ、実はWindows HomeではHyper-Vなしのため、VSCode Remote Developmentが使えないことが判明し即刻挫折しました 😩!ケチケチするなよMicr◯s◯ft!Windows 10 Pro ならいけるんじゃないでしょうか?知らんけど。
おわり
・・・
株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co
Akerun Proの購入はこちらから akerun.com