2022年の秋にAWS IoT CoreでMQTTを使用してから、もう少し使用してみようかなと思い、自分の開発環境にも入れてみようかなと思っていました。ただ、最近はWindowsのアプリのインストールではなくDockerを使用してコンテナ環境を作って他の環境でもすぐに使えるようにしたほうがいいかなと思って、色々試してようやく使えるようになりました。あと、面倒なのでdocker-composeは使用してません。
今回使用しているのはMQTTのオープンソース実装であるMosquittoを使っています。Windowsバイナリもあるので、正直それを使ったほうが楽です😁コンテナにしているので他の処理系でもほぼ同じように使えるのがいい点でしょうか。コンテナを使ってというのであればDockerでなくてもWSLを使用するという手ももちろんありかなと思います。
このMosquittoのDockerイメージは以下にあります。サイズは11MByte程度。このサイズ感ならDockerでいいですよね。
こちらのページのドキュメントにも導入の方法は書いてありますが、ちょっとだけ注意点はありますので、それも含めてメモとしていきます。
設定ファイルの準備
Mosquittoはコンテナのイメージを持ってきて起動するだけではうまくいきません。Mosquittoの設定ファイルであるmosquitto.confファイルを作成する必要があります。設定ファイルの内容については先程のコンテナ説明のページに記載されています。

設定ファイルの内容をMosquitto起動時に読み込まれるようにすればよいのですが、コンテナ起動時に設定ファイルがないとうまく起動できません。そこで今回は以前も使用したローカルファイルシステムのマウント機能(-vオプション)を使用して、Windows側のファイルシステムにMosquittoの設定ファイルを配置して、起動時に読み込まれるようにします。
注意点の1点目はWindowsのパス表記の方法です。特にドライブレターを含んだパスの表記は癖があるので注意しましょう。
参考
今回は設定ファイルをわかりやすくCドライブのルートにmosquittoというフォルダを作成し、マウントしていきます。パスの表記としてはルート部分(ドライブレターがCドライブであれば)が/c/となっているのがポイントになります(Windowsのみのtips😅)
作成したフォルダ

設定ファイルの内容

mosquitto.confの内容(コピー&ペースト用)
persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log
これで設定ファイルの準備ができました。あとはこの設定ファイルを参照するようにコンテナを作成します。
コンテナ構築・起動

実行方法もコンテナのページにかかれていますが、かなり親切にかかれています。

自分がドキュメントから変更した点は先ほどのマウント機能で(-vオプション)ドライブレターを含んだパスにしている点とホストネームの部分になります。起動コマンドに含まれているport番号1883と9001はホスト側からも共有できるようになっているので、Windows版のMosquittoをローカルホストにインストールした場合とほぼ同じように使用できるようになるかと思うのですが、実際は別マシン扱いになるので注意が必要です(後述します)。
以下の様に起動するとMosquittoコンテナが起動します。ホスト名はmymosquittoとしていますが、この名前はお好きなものに変更してください。
コンテナ構築・起動用のコマンド
PS > docker run -it -p 1883:1883 -p 9001:9001 -v /c/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf -v /mosquitto/data -v /mosquitto/log --name mymosquitto eclipse-mosquitto

コンテナ構築・起動が無事に行われたら、あとは通信のテストを行っていきます。
MQTTの実行テスト
コンテナが起動すると自動でMosquittoのbroker(実行プログラム名はmosuquitto)が自動的に起動しています。コンテナ側のpsコマンドを使用するとプロセスの起動状態を確認することができます。ちなみに起動は以下の様にしても行うことができます。
$ mosquitto -v

ブローカの起動が確認できたら、CLIからMosquittoのsubscriber(実行プログラム名はmosquitto_sub)を起動します。テスト用のTopicはtest/topicとしています。後述のpublisher側のTopicとsubscriberのTopicが合致すると、subscriber側にメッセージが受信します。
mosquitto subscriberの起動
$ mosquitto‗sub -t test/topic

あとは別途コンソールを起動し、Mosquittoのpublisher(実行プログラム名はmosquitto_pub)を起動して、メッセージを送信すればsubscriber側でメッセージが受信されます。
mosquitto publisherの起動
$ mosquitto_pub -t test/topic -m ”hello world!”

登録されたTopicのsubscriberが複数存在していれば、brokerがsubscriber側にメッセージを送信してくれます。

今回は同一ホストでsubscriberとpublisherが起動していたので、起動時オプションにホストを指定はしていませんが、オプションスイッチで-hを指定することで起動しているホストも指定できます。Mosquittoコンテナ側はDockerホストとポートの転送設定も行っているので、Windows側のMQTTクライアントからも同様に通信を行うことが可能です。

Windows版のmosquittoからの通信テスト
では、本当にDockerホストとなっているWindows側から通信が確認できるかを試してみます。注意しないとハマります。
Windows版のMosquittoがあるのでそれをWindowsにインストールして動作を確認してみます。
以下からWindows版のMosquittoをダウンロードして、インストールを行っていきます。

ダウンロードし、ファイルを実行するとmosquittoコマンド群のインストールが行われます。
インストール① 【Next >】ボタンをクリック

インストール② 【Next >】ボタンをクリック

インストール③ 【Install】ボタンをクリック

インストール④ 【Finish】ボタンをクリック

注意点としてはmosquitto(broker)が自動起動されている点です(サービス化設定しないと立上がらないのかなと思ったのですが、起動はしているようです)。そのままではDocker側のmosquittoと重複して実行され通信ができません(Docker側に通信が届きません)。もしこの方法で通信を試すのであれば、mosquitto(broker)をPowerShellのGet-Processコマンド(エリアスはps)でプロセスIDの確認を行った後、Stop-Processコマンド(エリアスはkill)で終了させてから試すようにしてください。Windows側でログを確認してもWindows側のsubscriberが起動していなければ、表示も行われないのでどこがおかしいかわかりにくいので、原因を調べるのがかなり大変でした。

PowerShellのAlias機能使用した停止する例
PS > ps -Name mosquitto # mosquittoプロセスのIDが4666であった場合 PS > kill -ID 4666
Windowsプロセスのmosquitto(broker)を終了させれば、Docker側のmosquitto(broker)と通信ができるのですが、まだだめです。Docker側とホスト側は別ホスト扱いになっているため、通信が制限されてしまいます。Mosquittoではデフォルトでは同一ホスト以外のbrokerとの通信しかできないようになっています。
そのため、ほかのホストからのMQTT通信を行う場合には設定ファイルであるmosquitto.conf以下のように編集していきます。最後の2行がはホストとの通信に使用する設定になります。
mosquitto.confの変更内容(コピー&ペースト用)
persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log listener 1883 allow_anonymous true
念のため、先ほどのコンテナを削除し、再度読み込まれるようにコンテナを構築・起動を行います。
(再掲)コンテナ構築・起動用のコマンド
PS > docker run -it -p 1883:1883 -p 9001:9001 -v /c/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf -v /mosquitto/data -v /mosquitto/log --name mymosquitto eclipse-mosquitto
このコンテナを起動し、Windows側のmosquitto_pub(publisher)でメッセージを送信すると、Dockerコンテナ側のmosquitto_sub(subscriber)にデータが受信されています。Dockerコンテナからも通信できているのがわかります。

おわりに
MQTTのオープンソースの実装であるMosquittoをDockerコンテナ上で動作させることができるようになりました。これで、IoT機器などのデバイスとの通信もできるようになりました。RaspberryPiにもMosquittoがあり利用できますし、pythonからでもモジュールを使用することでプログラム内からMQTTを使用できるかと思います。