この記事は fukuoka.ex Elixir/Phoenix Advent Calendar 2020 の4日目です.
3日目は,@torifukukaiouさんの「ElixirでAtCoderのABC123を解いてみる!」でした.awesome!!
はじめに
どうも最近は開発環境厨みが増してきている気がします.
ElixirでIoT!の連載記事も久々な気がするんですが,今回も開発環境な記事です^^;
これまでの実績はこんな感じです.
- ElixirでIoT#4.1:Nerves開発環境の準備
- ElixirでIoT#4.1.1:WSL 2でNerves開発環境を整備する
- ElixirでIoT#3.1:ESP32やSTM32でElixirが動く!AtomVMという選択肢
なんか新しいものを導入するたびにホスト環境はいろいろ汚れるわけですが,それを解消するために最近はDockerにハマりつつあります.
@matsujirushi さんがこんな記事を公開していました!
こんなcoolなsolution,もうちょい綺麗にできそう!ってことで, @matsujirushi さんにリポジトリの権限をいただきつつ,Docker(とVS Code)だけで素敵な開発環境を整えてみました!!
この記事では整備した環境について,ユーザ目線での使い方を主に紹介します.
中身の解説はまた機会を改めて^^;
つくったもの
- Dockerfile: https://github.com/NervesJP/docker-nerves
- Docker Hub (pre-built image): https://hub.docker.com/r/nervesjp/nerves
- VS Code dev-container: https://github.com/NervesJP/nerves-devcontainer
なにが嬉しいの?いつ使うの?
- Dockerを使えば,数ステップだけでNervesの開発環境が整います.ElixirでIoT#4.1で紹介したみたいに,Nervesの開発環境の準備って,いろいろライブラリを入れたり,いろいろErlangインストールにハマったり,いろいろ大変なんですよね,,, そんなシチュエーションが気楽に回避できます.
- 特に入門者にとっては嬉しいですし,知り合いにすぐ試してもらいたい!場合にも紹介しやくなるかと思います.
- ハンズオンの開催を計画する時にすごく頭を悩ませるのが,参加者の環境を揃えることです.DockerfileとかVS Codeの各種設定ファイルを調整すれば,これもお手軽に解消できます!!
- |> [PR]参考例[広告]
- |> この例の導入方法[ステマ]
- すでにNervesを導入済みの方でも,最新のバージョンや機能を味見で試してみたいことは多いです.そんなときにDockerを使えば,ホストの環境は汚さずにお手軽に最新版を試すことができます.asdfでErlang/Elixirのバージョンを切り替えて
mix archive.install hex nerves_bootstrap
のバージョンも,,, って煩わしさも無くなります. - Docker Hubにビルド済みのイメージを公開しています.これを使えば,さらに効率よくNerves開発環境が手に入ります(ただし最新版じゃないことがありますので,ご注意ください.全てはメンテナの @takasehideki の頑張り次第です^^;
ツラいことは??
- Dockerを動かすので,CPU/メモリの負荷がそれなりに掛かります.あとイメージ展開のためのディスク容量も必要です.
-
mix burn
でNervesファームウェアをmicroSDカードに書き込む作業ができません,,, ホスト上でfwup
を実行する必要があります
導入手順
インストールが必要なものは下記です.
- Docker Desktop
- VS Codeを使用する場合:Visual Studio Code と拡張機能 Remote - Containers
- fwup(後述)
DockerとVS Codeの詳しい導入方法は「ALGYAN x Seeed x NervesJPハンズオン!に向けた開発環境の準備方法」の記事を参照してください.
Docker単体で動かす
Docker Hubリポジトリから
ビルド済みのDockerイメージを使用します.pull
してrun
するだけです.
$ docker pull nervesjp/nerves
$ docker run -it -w /workspace nervesjp/nerves
root@6e304327bd2e:/workspace#
GitHubリポジトリから
GitHubで公開しているDockerfileを使ってローカルでビルドします.自分好みにDockerfileをカスタマイズすることもできます.
$ git clone https://github.com/NervesJP/docker-nerves
$ cd docker-nerves
$ docker build -t docker-nerves .
$ docker run -it -w /workspace docker-nerves
root@9bc88d0fc7b8:/workspace# pwd
/workspace
root@9bc88d0fc7b8:/workspace# echo ${HOME}
/root
root@9bc88d0fc7b8:/workspace# ls ~/.mix/*
/root/.mix/rebar /root/.mix/rebar3
/root/.mix/archives:
hex-0.20.6 nerves_bootstrap-1.10.0
Docker単体動作でのTips
ファイルシステムのマウント
Dockerはイメージの再構築時/実行時に,そのファイルシステムが消えてしまいます.このため,Nervesプロジェクトのファイルを保持するためにホストにボリュームをマウントしておくのが便利です.
-v $ {PWD}:/ workspace
によって,ホスト上の現在のディレクトリをDockerイメージにマウントできます.
$ docker run -it -w /workspace -v ${PWD}:/workspace docker-nerves
Elixir/Nervesに関連する設定ファイルをマウントしておくのも効率的です. ~/.hex
, ~/.nerves
, .ssh/
があります.
以下は,ホストとイメージ間で設定ファイルを共有する例です.
$ docker run -it -w /workspace -v ${PWD}:/workspace \\
-v ~/.hex:/root/.hex -v ~/.nerves:/root/.nerves -v ~/.ssh:/root/.ssh \\
docker-nerves
環境変数の設定
Dockerコンテナの立ち上げ時にシェルの環境変数を設定することができます.
Nerves開発時に必須の環境変数として ${MIX_TARGET}
があります.
開発対象とするNervesのtargetがすでに決まっていて固定されているなら,この変数を設定したほうが楽になります.
次の例ではrpi3
に設定してます.
$ docker run -it -w /workspace -e MIX_TARGET=rpi3 docker-nerves
root@deda9932d7e3:/workspace# echo $MIX_TARGET
rpi3
複数の環境変数を同時に設定したい場合は --env-file
を使うと良いでしょう.
例えば,vintage_net_wifiのWiFi接続設定を環境変数で与える方法があります.
下記のように env.list
を作成してオプションで与えるだけです.
$ cat env.list
MIX_TARGET=rpi3
WIFI_SSID=xxxxxxxx
WIFI_PSK=yyyyyyyy
$ docker run -it -w /workspace --env-file env.list docker-nerves
root@cf815278594a:/workspace# echo $MIX_TARGET
rpi3
root@cf815278594a:/workspace# echo $WIFI_SSID
xxxxxxxx
root@cf815278594a:/workspace# echo $WIFI_PSK
yyyyyyyy
環境変数を用いたVintageNetのWiFiの設定方法は,次の記事をご参照ください(どちらも両記事!!
- [Elixir/Nerves] Get started with LED Blinking on Raspberry Pi - DEV
- ウェブチカでElixir/Nervesに入門する(2020年12月版) - Qiita
VS Codeでより便利に!
みんな大好きVisual Studio Codeを使うと,さらに快適な開発環境が手に入ります.
通称dev-containerという拡張機能 Remote - Containers を利用します.
詳しくは下記の記事などをご参照ください〜
- 公式の資料:Developing inside a Container using Visual Studio Code Remote Development
- Qiita記事:VSCode Remote Containerが良い
使用方法
1. リポジトリをclone
git clone https://github.com/NervesJP/nerves-devcontainer
Gitに慣れていなければ,下記から直接ダウンロードもできます.
https://github.com/NervesJP/nerves-devcontainer/archive/main.zip
2. VS Codeをdev-container機能で開く
VS Codeを起動して,クイックアクションのステータスバー項目(左下の緑の >< となっているところ)かF1
をクリックします.
コマンドパレットが開きますので,**Remote-Containers: Open Folder in Container...**を選択し,手順1でcloneしてきたディレクトリを選択します.
3. コーヒーを淹れる
Dockerイメージのダウンロードと展開がよしなに始まります.PCスペックとネットワーク環境によっては10分くらい掛かるかもしれません.コーヒーでも呑みながら,落ち着いてお待ちください
うまくいかない?場合は,Docker Desktopのアプリが起動していないことが考えられます.
Windowsだと,デスクトップ右下のタスクトレイにこんな感じのクジラのアイコンが表示されているか確認してください(Macだとメニューバーにいてます)
ちゃんと進んでいるか気になる方は, 右下の青字の "Starting Dev Container (show log)" をクリックすると,進捗のログが表示できます.
ということで,こんな感じに出来上がりっ♪
左下の緑色なところが
>< Dev Container: Nerves
な表示になっていることを確認してください.
(画像は途中で "Starting Dev Container (show log)" をクリックして進捗を表示した場合のものです)
メニューの [ターミナル] > [新しいターミナル](ショートカットキーは Ctrl+Shift+`
)でターミナルを開くと, Dockerイメージ内でNerves開発環境の整ったターミナルを良い感じに利用できます.
(起動直後は[新しいターミナル]が選択できないことがあるようです.その場合は左側[エクスプローラー]で右クリックして[統合ターミナルで開く]を選択してみてください)
root@ebc5e1a19ae3:/workspaces/nerves-devcontainer# ls
LICENSE.txt README.md
root@ebc5e1a19ae3:/workspaces/nerves-devcontainer# ls ~/.mix/*
/root/.mix/rebar /root/.mix/rebar3
/root/.mix/archives:
hex-0.20.6 nerves_bootstrap-1.10.0
root@ebc5e1a19ae3:/workspaces/nerves-devcontainer# elixir --version
Erlang/OTP 23 [erts-11.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Elixir 1.11.2 (compiled with Erlang/OTP 23)
root@ebc5e1a19ae3:/workspaces/nerves-devcontainer# iex
Erlang/OTP 23 [erts-11.1.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
Interactive Elixir (1.11.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
4. SSH鍵を作成する
Nervesのファームウェア開発とネットワーク接続には,SSH鍵交換方式が使われます.
下記のように,いちばん代表的であるRSA鍵を作成しておきます.
ssh-keygen -t rsa -N "" -f .ssh/id_rsa
Tips a.k.a コダワリどころ
ローカルでのイメージの手動ビルド
GitHubで公開しているVS Codeのディレクトリは,Docker Hubでビルド済みのイメージのを使用しています.
手元でカスタマイズしてビルドしたい場合は,もともとのDockerfileを ./.devcontainer
に配置して, ./.devcontainer/devcontainer.json
の //"dockerFile": "Dockerfile",
の行のコメントを解除してください.
{
"name": "Nerves",
// Pull Docker image from DockerHub https://hub.docker.com/r/nervesjp/nerves
//"image": "nervesjp/nerves:0.1.1",
// NOTE: original Dockerfile is maintained at https://github.com/NervesJP/docker-nerves/blob/main/Dockerfile
// You can also build Docker image locally by locating above file to here and uncomment next line
"dockerFile": "Dockerfile",
〜〜(省略)〜〜
Nerves設定に関するファイルのマウント
先ほどのTIPSと同じく,イメージの再構築時/実行時に,そのファイルシステムが消えてしまいます.
VS Code/GitHubでは docker run
時のオプションも統一できるので,これらのファイルが含まれるディレクトリをカレントに保持するようにしました.
(これらはどこにマウントするのがいいのか,割りと悩ましかったです.${HOME}
のほうがええんちゃうかという気もします.ご意見いただけたら嬉しいです)
1つめは,Dockerコンテナ内の ~/.hex
にマウントされる ${PWD}/.hex
です.ElixirのHexパッケージが保持されます.
2つめは,Dockerコンテナ内の ~/.nerves
にマウントされる ${PWD}/.nerves
です.このディレクトリでは,Nervesのツールチェーンとnerves_system_brのアーカイブが保持されます.
Dockerコンテナの再起動のたびに mix deps.get
でこのアーカイブのダウンロード/展開は面倒ですし時間が掛かります.なので,このディレクトリをマウントするようにしています.
ホストとコンテナのファイルシステム間のバインディングはパフォーマンスが悪いため,最初の mixdeps.get
の実行時には多少の時間が掛かります.ですが,Docker起動のたびにダウンロード/展開に待たされるよりはマシじゃね?と判断しました.
最後に ${PWD}/.ssh
です.
ステップ4で作成した id_rsa
と id_rsa.pub
のSSHキーペアが含まれます.これらは,Nervesファームウェアの構築とNervesデバイスへのSSH接続のために使用されます.
さらに,VS Code拡張機能の自動設定で,Nervesのプロジェクトファイルも現在のディレクトリに保持されます.
環境変数の設定
これまたVS Code拡張機能の便利なところで, ./.devcontainer/devcontainer.json
にてコンテナ内のシェル環境変数を設定することができます.
今回はこんな感じで設定してあります.お好みに合わせて編集してからご利用ください.
(省略)
// This section sets environment variables for Nerves development
"remoteEnv": {
"MIX_TARGET": "rpi3",
"WIFI_SSID": "xxxxxxxx",
"WIFI_PSK": "yyyyyyyy"
}
(省略)
制約事項,,, mix burnできないorz
すっげー便利やん!と思うのですが,冒頭にも挙げている欠点がひとつだけあります.
Docker環境からはmicroSDカードへのアクセスができません,,, このため,せっかくDocker内でビルドしたNervesファームウェアを,mix burn
でそのままmicroSDカードに書き込めません.
代案として,Nervesファームウェアの書込みのためのユーティリティである fwup
をホストにインストールして実行します.
https://github.com/fhunleth/fwup
fwupのインストール
Windowsの場合
Chocolateryを使われている方は,下記でインストールできます.
choco install fwup
そうでない方は,下記からバイナリを直接ダウンロードして,ダウンロード先にPath環境変数を設定してください.
https://github.com/fhunleth/fwup/releases/download/v1.8.3/fwup.exe
上記URLのv1.8.3
のバージョン番号は,最新リリースに合わせて変更してください.
macOSの場合
brewでインストールできます.
brew install fwup
Linuxの場合
プラットフォームに合わせて,パッケージのダウンロードとインストールを行ってください.
https://github.com/fhunleth/fwup#installing
例えばDebian/Ubuntuならこんな感じです.
$ wget https://github.com/fhunleth/fwup/releases/download/v1.8.3/fwup_1.8.3_amd64.deb
$ sudo dpkg -i fwup_1.8.3_amd64.deb
上記URLのv1.8.3
のバージョン番号は,最新リリースに合わせて変更してください.
fwupによるファームウェアの書込み
インストールが完了したら,ターミナルを開いてNervesのプロジェクトのディレクトリに移動して,下記のとおり実行してください.
Windowsの方は,PowerShellを**「管理者として実行する」**で開く必要があります.
$ cd <your_nerves_project_dir>
$ fwup _build/${MIX_TARGET}_dev/nerves/images/<project_name>.fw
Dockerだから仕方ない話しではあるのですが,なんかうまいことできたら嬉しいところです.
例えばmicroSDの /dev/diskX
を書き込み可能でアクセスできたり,ホストにシェルプロセスの立ち上げをそこで実行したり,,, (WSL 2ではそんな機能があるらしい??
良い方法をご存じの方がいましたら,ここのissue#1かコメント欄で教えてください〜
おわりに
この記事の初稿は,実は英語で書きました.
よっしゃElixir Forumに投稿してやんぜ!世界のみんなを楽にしてやんぜ!Advent Calendarも英語記事を登録やっ!!
って息巻いていたんですが,どうもElixir ForumはModeratorsの審査承認作業があるらしく,,,
敢えなく日本語で書き直す,そんな不毛な作業の果てでした^^;
↓ この1時間後,,, 無事にapprovedされて公開されました!!
fukuoka.ex Elixir/Phoenix Advent Calendar 2020 の5日目は @hisaway さんによる「[Elixir]匿名関数をパターンマッチする」です.ASTの世界をチラ見しましょっ