複数のラズパイと通信する方法は色々考えられると思いますが、せっかくElixir・Nervesでファームウエア開発をしているので分散Erlangに挑戦したいと思います。
準備
ラズパイのhostnameまたはIPアドレスを調べる
nerves_pack v0.5.0以降のバージョンをお使いであれば、nerves_motdで表示させるのが手っ取り早いです。
DNS Bridgeを設定する
ネットワーク関係に疎いので詳しくはよくわかりませんが、mdns_lite - DNS Bridge configurationドキュメントによると、Erlang/OTPのビルトインDNSリゾルバーにmDNSについての情報を教えてあげなければならないそうです。
Underjordのデモ(YouTube)が参考になりました。
Erlangノードを起動
- やり方はnerves_pack - Erlang distributionドキュメントに説明されています。
- ここでは2つのラズパイを用意しました。それぞれのホスト名は
nerves-mn00.local
とnerves-mn02.local
です。 - ホスト名の代わりにIPアドレスを使用することも可能です。
- 共通のErlang magic cookieを使用することが重要です。
ターミナルを開き、ラズパイA(nerves-mn00.local)にSSHします。
❯ ssh nerves-mn00.local
# OS上でepmdを起動
iex> System.cmd("epmd", ["-daemon"])
# Erlangノードを起動
iex> Node.start(:"nerves@nerves-mn00.local")
# クッキーをセット
iex(nerves@nerves-mn00.local)> Node.set_cookie(:securecookie)
新たにターミナルを開き、ラズパイB(nerves-mn02.local)にSSHします。
❯ ssh nerves-mn02.local
# OS上でepmdを起動
iex> System.cmd("epmd", ["-daemon"])
# Erlangノードを起動
iex> Node.start(:"nerves@nerves-mn02.local")
# クッキーをセット
iex(nerves@nerves-mn02.local)> Node.set_cookie(:securecookie)
Erlangノードを接続
-
nerves-mn02.local
をnerves-mn00.local
に接続します。
iex(nerves@nerves-mn02.local)> Node.connect(:"nerves@nerves-mn00.local")
true
iex(nerves@nerves-mn02.local)> Node.list()
[:"nerves@nerves-mn00.local"]
別のノード(別のラズパイで)関数を実行
-
nerves-mn02.local
からnerves-mn00.local
の中で関数を実行してみます。 - 例として
Node.spawn/2
を使って、Toolshed.Nerves.uname/0
を実行して、デバイスの情報を確認してみます。
Node.spawn(
# 相手のノード名
:"nerves@nerves-mn00.local",
# 実行したい関数
fn -> Toolshed.Nerves.uname() end
)
iex(nerves@nerves-mn02.local)> Node.spawn(:"nerves@nerves-mn00.local", fn -> Toolshed.Nerves.uname() end)
Nerves nerves-mn00 hello_nerves 0.1.0 (240d82e1-1e6c-5800-0ef9-63cba9efc212) arm
#PID<51667.6840.0>
やった〜
分散Erlangを利用して別のラズパイで関数を実行することができました。
別のやり方として、phoenix_pubsubを利用して別のラズパイにメッセージを送りつけることも可能です。こちらのほうが扱いやすいかもしれません。
今回学んだ内容をkantan_cluster
というElixirパッケージにまとめました。自分用のツールですが、もしよかったら遊んでみてください。
資料
- Elixir Node
- Forming an Erlang cluster of Pi Zeros by underjord
- mdns_lite - DNS Bridge configuration
- nerves_pack - Erlang distribution
-
nerves_pack(vintage_net含む)を使ってNerves起動時に
Node.connect()
するようにした by @nishiuchikazuma - クラウドの外でエッジサーバを作るためのElixir技術スタック(+立てた予定を仲間と実現できるようになる思考パターン) by @piacerex
- はじめてNerves(8) 単一ホストで動くシステムを複数ホストに分散する by @kikuyuta