よしたく blog

ほぼ週刊で記事を書いています

HTTPとの対比から学ぶMQTT

Maker Faire TokyoでMQTTを使ったものを展示したが、自分もMaker Faire Tokyoで展示物を作成する前はMQTTについて知らなかった。知り合いのエンジニアに聞いてみても知らない人が多く、基本的なことが中心だが自分なりにまとめてみた。

MQTTとは

簡単な概要であるが、MQTTはMessage Queuing Telemetry Transportと呼ばれる1990年代にIBMが開発したプロトコルである。 通信のプロトコルとしては普段我々がWebで使っているHTTPがメジャーであるが、MQTTはIoTデバイスを中心に広く利用されている。

特徴

特徴は次の3つになる。

  • 非同期通信
  • 1対多、多対多
  • 軽い

非同期通信

MQTTは非同期通信となっている。 HTTPは同期通信であり、この点でまず異なっている。 同期通信は、クライアントが問い合わせ先のサーバへリクエストを発行し、それに対するレスポンスを待つ通信である。 このHTTPのリクエスト/レスポンスの動作が、日頃から使っているWebブラウザは対応できるがIoTデバイスには対応することが難しいのである。 理由は2つあり、我々が普段使っている環境のようにネットワークが安定しているとは限らないこととIoTデバイスが使う通信の帯域幅に制限があるからである。 非同期通信であれば、送る側と受け取り側が相手の反応を待っている必要がないため、IoTにおいては広くMQTTが採用されている。MQTTにおいて非同期通信を実現するために働いているのが「パブリッシャー」「サブスクライバー」「ブローカー」である。

パブリッシャー / サブスクライバー / ブローカー

通信における登場人物は、送る側の「パブリッシャー」、受け取り側の「サブスクライバー」、パブリッシャーとサブスクライバーの仲介をする「ブローカー」である。

f:id:yoshitaku_jp:20190827192450p:plain

通信の流れは、最初にセンサーデータなどを送る側のパブリッシャーが仲介役のブローカーに対してデータを送る。次に受け取る側のサブスクライバーは仲介役のブローカーに対してセンサーデータが届いているか確認しにいく。センサーデータがあれば、その情報を受け取るという流れである。

ここではクライアントとサーバが直接やり取りをしているHTTPとは違い、パブリッシャーとサブスクライバーがブローカーを介している部分が重要である。

1対多、多対多

MQTTは1対多、多対多の通信をおこなえるプロトコルである。 HTTPは1対1の通信をおこなうプロトコルであり、この点で異なっている。 非同期通信の項でも書いたが、クライアントが問い合わせ先のサーバからのレスポンスを待ちデータを受け取る通信であるため、1対1となる。 IoTデバイスは大量のデバイスに対して通信をおこなう場合があり、1対1のHTTPは適しているとは言えない。 そこで仲介役のブローカーにパブリッシャーとサブスクライバーがアクセスしていることを利用し、ブローカー内でメッセージの格納先を決めて1対多、多対多を実現している。 このメッセージの格納先のことをトピックと呼ぶ。

トピック

MQTTは「トピック」でブローカー内でのメッセージの格納先を決めている。 トピックは/(スラッシュ)で階層化をおこない、特定のメッセージだけを操作するように指定できる柔軟性を備えている。

f:id:yoshitaku_jp:20190827192522p:plain

階層化なので、抽象的な粒度から具体的にする。 簡単ではあるが例をあげておく。

/OS
/OS/Ubuntu
/OS/Ubuntu/18.04.3
/OS/Ubuntu/16.04.6
/OS/CentOS
/OS/CentOS/6
/OS/CentOS/7
/IoT
/IoT/RaspberryPi
/IoT/RaspberryPi/3ModelB+
/IoT/RaspberryPi/Zero
/IoT/Arduino
/IoT/Arduino/Nano
/IoT/Arduino/Yun

また、1対多、多対多と書いたがメッセージを置くトピックにはワイルドカードが使える。 /IoT/*とすれば、/IoT/RaspberryPi/IoT/Arduino配下のすべてのものにメッセージを送信でき、/IoT/RaspberryPi/*とすれば、/IoT/RaspberryPi/3ModelB+/IoT/RaspberryPi/Zeroに送信できる。

軽い

MQTTのデータ通信量が軽いことについて説明しようとしたが、自分がやりたかった調査を非常にわかりやすくかつ具体的な数字で解説されているページを見つけたのでリンクを貼らせてもらう。

www.ydc.co.jp

また、消費電力とデータサイズの軽さについて調べている記事もあったのでリンクを張っておく。

qiita.com

まとめ

MQTTについてまとめた。 比較対象にHTTPを使ったことでHTTPについても学ぶことができたし、自分の中で適切な棲み分けが意識できるようになった。 MQTTについて学んだことの整理と、知らない人に対してどう説明したら良いか考えるきっかけになった。

参考

https://kfep.jp/solution/iot-mqtt/mqtt

https://www.ibm.com/developerworks/jp/iot/library/iot-mqtt-why-good-for-iot/index.html

https://qiita.com/darai0512/items/37158f56e9a6b4ce83ed

http://tech-blog.rakus.co.jp/entry/20180912/mqtt/iot/beginner

https://gist.github.com/voluntas/e0a90f3e22316144ed3a

https://blogs.akamai.com/jp/2019/06/iot---iot-egge-connect--.html

https://amg-solution.jp/blog/15787

https://monoist.atmarkit.co.jp/mn/articles/1606/01/news017.html

Raspberry Pi zero WH でk3sはどこまで動くか

Raspberry PiKubernetesを導入し動作確認をしている。 なかなか時間がかかることもあり、その間にRaspberry Pi Zero WHにk3sがどこまで動くか実験してみた。 Raspberry Pi Zero WHに馴染みがない人もいると思うので、OSとスイッチサイエンスさんが載せているスペックを引用させていただく。

  • os
    • Debian Stretch with Raspberry Pi Desktop
    • Version
      • April 2019
    • Release date
      • 2019-04-11
    • Kernel version
      • 4.9
仕様

メモリ: 512 MB RAM
USB 2.0 ポート: microB(OTG接続)
映像出力: miniHDMI(ひとまわり小さいHDMI!!)
ストレージ: microSDメモリーカードスロット(SDIO対応)
低レベル周辺機器: 27 × GPIO、UART、I2C、SPIと二つのチップセレクト、+3.3 V、+5 V、GND
カメラコネクタ: Raspberry Pi Zero用カメラケーブルコネクタ(Raspberry Pi 3とはサイズが異なります)
電源ソース: 5 V / USB Micro-Bコネクタ または GPIOコネクタ
無線通信機能
802.11 b/g/n wireless LAN
Bluetooth 4.1
Bluetooth Low Energy (BLE)

https://www.switch-science.com/catalog/3646/

インストール

rancherのGitHub上にインストール方法が書いてあるので、そのとおり実行する。

https://github.com/rancher/k3s

まずは curl -sfL https://get.k3s.io | sh -

実行

sudo k3s server &

実行してみたが起動しなかった。 Kubernetesより軽いと言われるk3sだが 、流石にZero WHでは難しいようだ。 一回目の調査としてはここまでとするが、解決策が見つかりそうであれば調べて追記していく。 もう少し先までできるのではないかと思っていたので非常に残念だった。

エラーコード

VS Code上でリモートファイルを操作するSSH FSを使ってみた

VS Code上でRaspberry PiやJetsonなどのリモート環境にあるファイルを操作するときに使える「SSH FS」を使ってみた。 設定ファイルの簡単な編集ならばSSHでログインしvimを使って編集していたが、ガッツリとスクリプトファイルを書くタイミングになったときに、普段使っているVS Codeを使いたかったのでプラグインを探した。

github.com

marketplace.visualstudio.com

インストール

VS Codeプラグイン機能なので、VS CodeのExtensionsで検索してインストールボタンを押すだけだった。 Extensionsに「SSH FS」と検索すると一番上に出てくる。今回の記事でのバージョンは1.16.3だった。

接続先設定

SSH FS」のインストールが完了すると、エクスプローラーの最下部に「SSH FILE SYSTEMS」が出現している。

f:id:yoshitaku_jp:20190816122448p:plain

「表示」→「コマンドパレット」をクリックし、「SSH FS: Create a SSH FS configuration」を実行する。

f:id:yoshitaku_jp:20190816122653p:plain

Create new configuration

Create new configuration画面で接続先の名前を設定する。

各種設定

次の4つが設定されていれば、最初に例にしたRaspberry PiやJetsonはすぐに接続できる。ここでは特別解説することはしない。 - Host - Port - Username - Password

その他の設定

上記以外に現時点でよく使う設定の説明を載せておく。

  • Label
  • エクスプローラーの最下部の「SSH FILE SYSTEMS」などの表示名を変更できる。指定しない場合はnameに設定した値が表示される。
  • Group
  • エクスプローラーの最下部の「SSH FILE SYSTEMS」などの表示名をグループでまとめることが出来る。「社内デバイス」「クラウド」といった分け方や、「raspberry pi」「jetson」といったデバイスごとの分け方が考えられる。
  • Root
  • 接続したときにどこのフォルダを開くかを設定する。自分は「/home/pi」を指定することが多い。

まとめ

インストールから設定、接続まで5分かからず完了した。すぐに使えて、設定も難しくないのが好感が持てた。Visual Studio Code Remote - SSHというMicrosoftが作っているものもあるが、まだ0.45.5でプレビューとなっているので今回は見送った。正式リリースとなったら、こちらも使ってみたい。

じぶん Release Notes 0.29.3

f:id:yoshitaku_jp:20190809171314p:plain 7月1日〜30日のあいだの出来事がリリースされました。

技術・開発関連

技術面での取り組みは以下の通りです。

  • Nginxでリバースプロキシを導入しました
  • Node-REDでMakerFaireTokyo出展物の作成をしました

イベント

参加したイベントは以下の通りです。

読んだ

  • インフラ/ネットワークエンジニアのためのネットワーク技術&設計入門
  • 現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法

買ったもの

主要な買い物は下記の通りです。 - 今月は特にありません。

ブログ

リリースノートを除き、次のエントリを書きました。

PV数

7月は3879でした

f:id:yoshitaku_jp:20190809171003p:plain

仕事

  • 部署が変わり出張が多くなりました
  • Azureを多く触ることが多くなりました
  • お客様と接する機会が多くなりました

KPT

K

  • 青森・秋田・山形へ行った
  • ソファを買った
  • 業務を楽しくこなせている
  • 社内イベントに参加した
  • Kubernetesについての理解が深まった
  • 断片的だった知識が業務でいかせた
  • 本を読む時間が取れた

P

  • 業務のキャッチアップが大変でブログが疎かになった
  • 社内イベントの準備で休日出勤を2度した
  • 自分リリースノートを出すのが遅くなった

T

  • ブログを書く際のスタートとゴールを明確にし、TDD方式で書いてみる
  • データ指向アプリケーションデザインを読み終える
  • 次回のリリースは2019/09/01です

Maker Faire Tokyo 2019に自動積荷システム「Salaie」を出展してきた!

毎年見に行っていたMaker Faire Tokyoですが、今年は出展してきました!

makezine.jp

何を出展したの?

「Salaie」 と名付けた、自動積荷システムを社内の有志と作りました。

「Salaie」 は、ベルトコンベアで流れてきた荷物をカメラで撮影します。 次に、撮影した画像を推論し、アーム側へ箱の分類情報を渡します。 最後に箱の推論情報を受け取ったアームが指定の場所へ荷物を運びます。 これで一つの処理が完了し、それを続けていきます。

どのようなシステム構成なの?

f:id:yoshitaku_jp:20190804112003p:plain
saraieのシステム構成図

「Salaie」 のシステム構成ですが、Raspberry Pi上のKubernetes(k3s)がMQTTブローカーの役割と全体の制御をおこなうNode-REDを実行しています。 Kubernetes(k3s)を使用している理由ですが、正直家でRaspberry Piを使用を想定するとクラスタリングをする必要はありませんが、今回は業務用を想定したため「冗長性」「負荷分散」「Infrastructure as Code」の点からKubernetes(k3s)で実装しました。

また、学習済みのモデルはGoogle Colaboratoryを使って作成しました。その学習済みモデルをJetson TX2に配置し、撮影した画像を推論しています。 また、学習済みモデルはFlaskでローカルサーバーをたて、GETリクエストから推論を実行できるようにしておき、デバッグもおこないやすくしておきました。

その他のデバイスは、Arudino YUNを使い制御しています。

トラブルはあったの?

準備段階

準備段階では、学習済みモデルをFlaskで読み込む処理が正常に実施できませんでした。 Tensorflowの特定のバージョンで起こるバグのせいでFlask起動時に学習済みモデルを正常に読み込めず苦労しました。 GitHubのissueに載っていた回避スクリプトを実行したら動きました。 (該当のissueが見当たらないため見つけたら記載) 色んな場所で相談させてくださった方ありがとうございます。

本番当日

本番では、会場の光度と練習していた社内の光度に大きな違いがあり、デモがうまく動きませんでした。 モバイルのライトを緊急で購入し、光センサーの周りの光度をあげて対応しました。

他には、各デバイスが持ってきたルーターに繋がらないところもトラブルとなりました。

IoTにおけるデモ・リハーサルの大切さ

社内で電源を抜き再びつけるところからリハーサルを3回ほど実施したにもかかわらず、想定外のトラブルに合いました。 この3回リハーサルの間にもトラブルがあり、それらを解消できたので当日のトラブルを必要最小限に抑えられたのかなとも思います。素振り大切。 例えば、Kubernetesがコンテナイメージを取得する際、持参予定のルーターが外部へ接続されていないために、コンテナイメージ取得待ちになっていたことがありました。

まとめ

IT企業ではありますが、プログラミングをガリガリ書かない企業であるため、どれだけ簡単に実装できるかにこだわりました。その反面、今回の展示のためではなく、その先の業務用を意識した構成にし最後まで完成させられたところは良かったと思います。

また、会場でのトラブルを見学に来てくれた方に説明すると、「展示会場ではネットワークと光系のトラブルが多い」と教えていただけたり、出展しなければわからないことも多く知れたところが自分にとって多くプラスでした。

興味はあるけど普段の業務では触れない技術も触れて、知的好奇心を大きくくすぐられる準備期間とMaker Faire Tokyo 2019になりました。

見学してくださった方、質問してくださった方、実装に困っていたときに相談に乗ってくださった方、最後まで一緒にやり遂げてくれたメンバーの方、ありがとうございました。

RaspberryPiにHadoopをインストールする

クラウド環境を使うことでHadoopを始めとする分散環境を用意することは簡単だが、内部でどのような処理がおこなわれているか疑問に思った。 今回はHadoopをRaspberryPiにセットアップし、スタンドアローン環境が動作するところまで確認する。

環境

RaspberryPi 3B+

OS:Ubuntu 18.04

セットアップ

まずはupdateをおこなう。

sudo apt-get update
sudo apt-get upgrade

Javaのインストール

Hadoopを動かすためにはJavaが必要なため、openjdkをインストールする。

sudo apt install openjdk-11-jre-headless

Hadoopのセットアップ

Hadoopwgetコマンドでダウンロードする。 2019/07/28時点で最新版は3.1.2である。

wget http://ftp.yz.yamagata-u.ac.jp/pub/network/apache/hadoop/common/hadoop-3.1.2/hadoop-3.1.2.tar.gz
tar xzvf hadoop-3.1.2.tar.gz
mv hadoop-3.1.2 hadoop

hadoop-env.shを編集する。JAVA_HOMEの項目にインストールしたJavaディレクトリを指定する。 vim hadoop-env.sh

JAVA_HOME=/usr/lib/jvm/java-11-openjdk-arm64

確認

hadoopを実行するとUsageが表示される。 Usageが表示されないときはhadoop-env.shのJAVA_HOMEが正しく指定されていないので確認する。

hadoop/bin/hadoop

Usage: hadoop [OPTIONS] SUBCOMMAND [SUBCOMMAND OPTIONS]

(省略)

    Daemon Commands:

kms           run KMS, the Key Management Server

SUBCOMMAND may print help when invoked w/o parameters or with -h.

テスト実行

inputディレクトリを作成し、hadoop-mapreduce-examplesのwordcountを実行する。 結果が帰ってくれば成功。

mkdir hadoop/input
bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.2.jar wordcount input output

まとめ

今回はHadoopをRaspberryPiにセットアップし、スタンドアローン環境が動作するところまで確認した。 クラウドを利用しブラウザでクリックするだけで終わる処理を体験し、今回のスタンドアローンのセットアップ以外にも分散環境のセットアップが入ることを考えると便利な時代になっていると感じる。

Flaskをさわってみた

Maker Faireへの出展物にWeb API化したいものがあり、軽量なFlaskを採用した。 以前Djangoを使用して個人的なプロダクトを作ったことがあったので、比較対象としてFlaskの名前は聞いたことがあったが触るのは初めてだった。 Djangoに比べると軽量に使えるものであり、用途が限定されているものであったらすぐにFlaskで作成し見せられる状態まで持っていくことが可能であると感じた。

自分が触った機能のメモを残しておく。

インストール

Pythonnにはおなじみのpipコマンドでインストールが可能である。

pip install flask

Hello world

公式からのサンプルコードとして載っているものを借りる。 今回は次のコードをserver.pyとして、python server.pyで起動する。 ブラウザからhttp://localhost:5000にアクセスすると、Hello World!が返却される。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello World!"

if __name__ == '__main__':
    app.run()

パラメーターの受け取り

パラメータの受け取りは、from flask import requestを使う必要がある。 自分はpip install requestsで提供されているものと勘違いして躓いてしまった。 request.args.get('search_word')http://localhost:5000/?search_word=hatenaとアクセスされたhatenaが受け取れる。

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route('/')
def hello_world():
    search_word = request.args.get('search_word')
    return search_word

if __name__ == '__main__':
    app.run()

外部からのアクセスに対応する

Flaskはデフォルトで起動すると、localhostからのアクセスしか対応していない。 本番で出展するときはFlaskを動作させているサーバ内部だけで処理が完結するものではあるのだが、テストを容易にするため外部からのアクセスも可能としたい。 このときの対応も非常に簡単で設定ファイルをいじることもなく、app.run()の引数をapp.run(host='0.0.0.0')とするだけでよかった。

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route('/')
def hello_world():
    search_word = request.args.get('search_word')
    return search_word

if __name__ == '__main__':
    app.run(host='0.0.0.0')

これだけの作業でWeb APIが作られることを魅力的に感じた。 リッチなフレームワークを使うと様々なことを実現できることも理解しているが、大量の設定ファイルやコマンドを実行することになり、使用する前段階での理解する時間が大量に必要だった。その結果、本当にやりたい作業までなかなかたどり着けないことがあった。 Flaskを使うと理解する時間の大幅な短縮が見込めるので、まずはどんどん自分のやりたいことを実現し、そのうえで別のフレームワークが必要と感じたら移行を検討していくことが大切であると感じた。

Azure Bastionをさわってみた

現在パブリックプレビューとして公開されている、 「Azure Bastion」 を触ってみた。 「Azure Bastion」 はブラウザ上のAzure Portalから、仮想ネットワーク内の仮想マシンにプライベートIPだけで、リモートデスクトップSSHでアクセスができる。 つまり、仮想マシンにパブリックIPを設定する必要はない。 Bastionという単語は要塞という意味があり、IT業界的には「Bastion Server(踏み台サーバ)」と略されることがある。 読み方は「バッション」

azure.microsoft.com

使用した際のイメージ図は次のようになる。

f:id:yoshitaku_jp:20190712143331p:plain
https://docs.microsoft.com/en-us/azure/bastion/bastion-nsg

必要なもの

  • Virtual Machine
    • 「Azure Bastion」 が利用できるリージョンとVirtual Machineも同じ場所に配置するのが望ましい。
      • West US
      • East US
      • South Central US
      • West Europe
      • West Europe
      • Australia East
      • Japan East
  • Virtual Network
  • Bastion

「Azure Bastion」 は現在パブリックプレビューなので、通常のAzure Portalからでは利用ができない。 次のURLからアクセスする必要がある。アクセスをするとヘッダーがオレンジ色の画面に遷移する。

Azure portal - Bastion Preview

仮想ネットワークの作成

仮想ネットワーク上にBastionをデプロイするためのサブネットを作成する。作成する際の注意は、サブネットの名前を 「AzureBastionSubnet」、アドレス範囲(CIDRブロック)を 「/27」 より大きいものにしなければならない。この2つを指定された値以外にすると「Azure Bastion」 を使うことができない。画像はサブネットを作成したあとのものである。Virtual Machineは 10.0.0.0/24にデプロイしてある。

f:id:yoshitaku_jp:20190712143226p:plain

Bastionの作成

Bastionを作成するが特に難しいことはなく、「サブスクリプション」「リソースグループ」「インスタンス」「仮想ネットワーク」を指定する。 「仮想ネットワーク」は先程の「AzureBastionSubnet」を指定する。

f:id:yoshitaku_jp:20190712144605p:plain

Bastionの作成時のエラー

仮想ネットワークの作成で次のようにと書いた。

作成する際の注意は、サブネットの名前を 「AzureBastionSubnet」、アドレス範囲(CIDRブロック)を 「/27」 より大きいものにしなければならない。

実際に指定の値以外でサブネットを作成したときのエラーメッセージを確認しておく。

To associate a virtual network with a Bastion, 
it must contain a subnet with name AzureBastionSubnet with prefix of at least /27
仮想ネットワークをBastionに関連付けるには、AzureBastionSubnetという名前のサブネットと少なくとも/ 27のプレフィックスを持つサブネットを含める必要があります。

f:id:yoshitaku_jp:20190712150102p:plain

「Azure Bastion」 からログイン

Connectをクリックすると、右側からパネルが出現する。 通常のAzure PortalでConnectをクリックしても出てこない「BASTION」が存在するので、Virtual Machineのユーザ名とパスワードを入力しログインする。 別のタブが開くので、ポップアップブロックに引っかかる可能性がある。動いていないときはポップアップブロックを確認すること。

f:id:yoshitaku_jp:20190712151743p:plain

Jupyter Notebookを外部からアクセスして使う方法

Jupyter Notebookを起動しているサーバーに外部からアクセスして利用する方法をTipsとしてまとめておく。

個人で小さく利用している場合はローカルマシンでJupyter Notebookを使うことで足りるが、企業単位であったり重い処理を実行する場合はクラウドGPUを搭載したマシンを用意し使うことがある。クラウド上で起動しているJupyter Notebookへアクセスし、利用する方法をまとめておく。

設定ファイルの作成

jupyter notebook -- generate-configを実行することでデフォルト設定の設定ファイルを作成できる。 ~/.jupyter/jupyter_notebook_config.pyが作成先になる。

設定ファイル内のc.NotebookApp.ipを変更することで、外部からのアクセスが可能となる。 *だとすべての場所からのアクセスが可能となるため、セキュリティには注意が必要となる。 ポート番号を変更することも可能。

#c.NotebookApp.ip = 'localhost'
#c.NotebookApp.port = 8888
c.NotebookApp.ip = '*'
c.NotebookApp.port = 9999

Jupyter Notebook起動時にブラウザを起動させたくない場合はc.NotebookApp.open_browserの設定を変更する。

c.NotebookApp.open_browser = True
c.NotebookApp.open_browser = False

じぶん Release Notes 0.29.2

f:id:yoshitaku_jp:20190702075126p:plain 6月1日〜30日のあいだの出来事がリリースされました。

技術・開発関連

技術面での取り組みは以下の通りです。

  • write-blog-every-weekのサイトにVuetifyを導入しました。
    • 途中なので今後も継続
  • バケットリストのサイトを作成しました。
    • 途中なので今後も継続

イベント

参加したイベントは以下の通りです。

  • せんべろの旅in池袋
  • フットサルチーム合宿in河口湖

読んだ

買ったもの

主要な買い物は下記の通りです。

  • 今月は特にありません。

ブログ

リリースノートを除き、次のエントリを書きました。

PV数

6月は3,987でした

f:id:yoshitaku_jp:20190702074200p:plain

仕事

  • 部署が変わることもあり、サポート業務が多めでした。
  • 来月からはインプットが多くなりそう…!

KPT

K

  • 週1本映画を見た
  • 運動をして痩せた
  • 漫画を大人買いした

P

  • Podcastを聞く時間が取れなかった
  • 本を読む時間が取れなかった

T

  • 新しい部署に慣れる
  • 次回のリリースは2019/07/01です