使用 Docker 架設 MQTT 伺服器 (Mosquitto MQTT Broker)
伺服器MQTT (Message Queuing Telemetry Transport) 是一種輕量且高效的通訊協定,被廣泛應用於各種通訊需求中,尤其在物聯網和即時通訊領域。 MQTT 採用發布/訂閱模型,當一個設備發布訊息到特定主題時,所有訂閱該主題的設備都能夠接收該訊息。 此外,MQTT 提供了多種不同的 QoS (Quality of Service) 等級,這確保了訊息的可靠性和一致性,同時允許根據應用情境進行適度的調整。
MQTT 軟體有非常多選擇,包含客戶端與伺服器端,但需要注意的是有些軟體僅是客戶端或者僅是伺服器端。 本文主要架設的是 Mosquitto Broker,其他 MQTT Broker 還有 EMQX、moquette、HiveMQ、EMQ X Broker...等等。
備註:MQTT 伺服器通常稱為 Broker,比較少看到用 Server
安裝 Mosquitto Broker
在 Ubuntu 安裝 Mosquitto Broker 相當容易,只需要使用 apt-get 安裝即可。
# 安裝 Mosquitto Broker
sudo apt install mosquitto
# 安裝 Mosquitto Client
sudo apt install mosquitto-clients
但本文並不打算詳細說明這種方式,我自己習慣使用 docker 運行 Mosquitto Broker,因此接下來我會一步一步介紹如何使用 docker 安裝 Mosquitto Broker。
Step 1: 準備映像檔
第一步當然是從 Docker Hub 下載 Mosquitto 映像檔。
# 將映像檔下載至本機
docker pull eclipse-mosquitto
# 查看映像檔資訊
docker inspect --type=image eclipse-mosquitto
Step 2: 建立本機目錄
Mosquitto 映像檔有三個目錄需要掛載至容器,分別是 config、data、及 log。
# 存放設定檔及密碼檔
# 這個目錄中需要有 mosquitto.conf 及 passwd_file
mkdir -p ~/docker/mosquitto/config
# 存放 SSL 憑證
mkdir -p ~/docker/mosquitto/config/ssl
# 存放 .db 資料
mkdir -p ~/docker/mosquitto/data
# 存放 log 檔
# 這個目錄需要有 mosquitto.log
mkdir -p ~/docker/mosquitto/log
Step 3: 建立 mosquitto.conf
mosquitto.conf 是 Mosquitto 重要的設定檔,有關 mosquitto.conf 的內容請參考下方。
# 啟動持久化訊息
persistence true
persistence_file mosquitto.db
persistence_location /mosquitto/data
# 設定 Log 檔
log_dest file /mosquitto/log/mosquitto.log
# 不允許匿名登入,必須透過帳密才能登入
allow_anonymous false
password_file /mosquitto/config/passwd_file
# 不需要使用證書進行身份驗證
require_certificate false
# 啟用 TCP 模式
listener 1883
protocol mqtt
# 啟用 WebSocket 模式
listener 9001
protocol websockets
# 啟用 TCP 模式 (SSL)
listener 8883
protocol mqtt
keyfile /mosquitto/config/ssl/server.key
certfile /mosquitto/config/ssl/server.crt
cafile /mosquitto/config/ssl/ca.crt
# 啟用 WebSocket 模式 (SSL)
listener 8884
protocol websockets
keyfile /mosquitto/config/ssl/server.key
certfile /mosquitto/config/ssl/server.pem
cafile /mosquitto/config/ssl/root.cer
提醒您,千萬不要把註解寫在設定值的後面,會出錯,請使用獨立一行撰寫註解。 還有設定檔中的路徑是檔案在容器中的路徑,不是本機路徑,這份設定檔後續會掛載至容器中使用。
設定檔中的 1883、9001、8883 及 8884 port 都是慣用的預設 port,如果沒有特殊需求就使用預設 port 就好,並不需要四個 port 都啟動,請根據需求調整。 上方設定檔是最基本的一些設定,其他更多詳細的設定,請參考官網說明。
Step 4: 建立 docker 容器
使用以下指令建立 docker 容器。
# -d: 背景執行,建立後返回容器 ID
# --restart=always: 開機自動啟動
# -u: 使用特定帳號執行
# -p: 設定本機 PORT 對應至容器中的 PORT
# -v: 設定本機目錄對應至容器中的目錄
docker run -d --name mosquitto \
--restart=always \
-u 501:20 \
-p 1883:1883 -p 9001:9001 \
-v ~/docker/mosquitto/data:/mosquitto/data:rw \
-v ~/docker/mosquitto/log:/mosquitto/log:rw \
-v ~/docker/mosquitto/config:/mosquitto/config:rw \
eclipse-mosquitto
Step 5: 建立 Mosquitto 帳號
由於 Mosquitto 安裝在容器內,因此建立帳號需要先進入 docker 中,再透過 mosquitto_passwd 指令新增帳號。
# 進入容器
docker exec -it mosquitto /bin/sh
# 建立帳號
mosquitto_passwd /mosquitto/config/passwd_file username
Password: xxxx
Reenter password: xxxx
# 如果 passwd_file 檔案不存在可以使用 -c 參數
# 但要特別注意,如果 passwd_file 檔案存在,又使用 -c,這樣檔案會被蓋掉
mosquitto_passwd -c /mosquitto/config/passwd_file username
Step 6: 測試 Mosquitto Broker
Mosquitto 提供 mosquitto_sub 指令用來訂閱主題,以及 mosquitto_pub 指令用來發布訊息,只是因為我們是在 docker 中安裝 Mosquitto,所以這兩個指令也存在 docker 中。
# 進入容器
docker exec -it mosquitto /bin/sh
# 訂閱主題
# -d: debug 模式
# -v: 詳細列印收到的訊息
# -h: Broker 的 IP
# -p: Broker 的 Port (預設為 1883 或 8883)
# -t: 訂閱的主題
mosquitto_sub -d -v -h [IP] -p [Port] -t topic
# 發布訊息到特定主題 (必需在另外再開一個終端機)
# -d: debug 模式
# -h: Broker 的 IP
# -p: Broker 的 Port (預設為 1883 或 8883)
# -t: 發布的主題
# -m: 發布的訊息
mosquitto_pub -d -h [IP] -p [Port] -t topic -m "Hello"
建議大家可以更多工具 MQTT 客戶端工具測試看看,從外面連進 docker 中的 Mosquitto 更能確保 MQTT 是否正確運行。 推薦使用 MQTT Explorer,該工具支援測試 TCP 模式及 WebSocket 模式。
探討 passwd_file 檔
在建立 MQTT 帳號密碼時,我們可以使用 mosquitto_passwd 指令將帳號及生成的加密密碼保存在 passwd_file 檔案中。但 mosquitto_passwd 只有在容器中使用,因此每次新增帳密時,都需要進入容器中進行操作,這樣的方式顯然相當不方便。
根據官網文件,密碼是由 PBKDF2-SHA512 演算法生成,因此我們完全可以自己撰寫程式生成,以下提供 python 及 php 的程式碼提供參考。
<?php
$password = '654321';
$salt = substr(md5(mt_rand()), 0, 12);
$iterations = 101;
$hash = hash_pbkdf2('sha512', $password, $salt, $iterations, 0, true);
echo '$7$' . $iterations . '$' . base64_encode($salt) . '$' . base64_encode($hash);
from hashlib import pbkdf2_hmac
from base64 import b64encode
import secrets
password = b'123456'
iterations = 101
salt = secrets.token_bytes(12)
hashString = pbkdf2_hmac('sha512', password, salt, iterations)
print("$7$" + str(iterations) + "$" + b64encode(salt).decode() + "$" + b64encode(hashString).decode())
以上程式僅是生成加密密碼而已,但在 passwd_file 檔案中是以[帳號]:[加密密碼]格式儲存,請自己在前方加入自己想要設定的密碼。當修改完 passwd_file 檔之後,docker 需要重啟才會生效。
關於 mosquitto.db
這個檔案以 .db 結尾,乍看之下會誤以為是 SQLite 檔,其實不是。根據官方的回覆,這個檔是用來儲存持久化資料,僅能給 Mosquitto 使用,不適用 Mosquitto 以外的用途,所以裡面不是儲存歷史訊息,不用嘗試想辦法打開它。
認識 QoS
QoS(Quality of Service)是用來確保訊息的可靠性和傳遞的保證級別。
- QoS 0
- 訊息只送出一次,且不管訂閱者是否收到。因此可能發生遠端沒收到的狀況,效能較好。
- QoS 1
- 確保訊息至少被接收一次,當訊息送出後,等待訂閱者回傳訊息,如果沒收到回傳訊息,就會再送出訊息,直到收到訂閱者回傳訊息為止。該模式所以遠端可能會重複收到相同訊息。
- QoS 2
- 訊息只送出一次,但保證遠端會收到訊息,這是最可靠的傳遞方式,但也最耗費效能。
0 則留言