前言
[MQTT] CentOS 7 安裝 Mosquitto 並使用帳密驗證 一文已經介紹如何從 yum 開始一步步地架設 MQTT Broker。這次,我想使用 Docker 來架設 Mosquitto,同時運行 MQTT/MQTTS/WS/WSS 四種通訊協定,順便練習 Docker 的使用方法。
環境
- Ubuntu 20.04 LTS
- Docker 20.10.2
下載官方映像檔
搜尋官方建立的 mqtt Image 並下載
1 | user@pc:~$ sudo docker search mqtt -f is-official=true # 搜尋 Image |
-f is-official=true
:指定過濾出官方提供的 Image。
建立所需目錄與檔案
Container 關閉之後不會把關閉之前的數據與狀態存下來,恢復到與剛下載好的 Image 一樣乾淨 (其實根本就是一樣的東西啦),因此在使用 Container 之前,需要先創立一些目錄與檔案,來存放我們想永久儲存的資料與設定
建立目錄
1 | user@pc:~$ sudo mkdir -p /mosquitto/config # 存放設定檔的目錄 |
建立檔案
/mosquitto/config/mosquitto.conf
1 | persistence true |
persistence
:true
為開啟資料存放在地端,讓通訊更穩定。可參考詳細說明 How to set up persistent storage for Mosquitto MQTT broker 。persistence_location
:指定資料存放於/mosquitto/data/
目錄下。log_dest file
:Log 會被寫到/mosquitto/log/mosquitto.log
檔案內。allow_anonymous
:在 Mosquitto 2.0 之後預設不允許匿名使用者登入,因此要設定此選項為true
才可匿名登入。listener
:掛載服務於 1883 Port。protocol
:1883 Port 的服務為 MQTT。
運行 MQTT Container
啟動 Container
啟動 eclipse-mosquitto 的 Image,並查看運行中的 Container 確定有正常運作 (STATUS
沒有異常訊息)
1 | user@pc:~$ sudo docker run -d --name mqtt -p 1883:1883 \ |
-d
:啟動後於後台工作。--name
:幫此 Container 取名為mqtt
p
:Port 映射host port:container port
。v
:Volumn 映射host directory:contrainer directory
。
到目前為止,初步的設定已經完成,並已讓 Mosquitto Container 運行起來,且沒有出現錯誤訊息。
測試 MQTT Broker
若要測試 Broker 功能是否正常,要使用到 mosquitto_sub
與 mosquitto_pub
兩個指令,因此需先安裝 mosquitto-clients
1 | user@pc:~$ sudo apt-get install mosquitto-clients |
開啟一個新的 Terminal (在此稱 tty1),輸入指令來訂閱主題
1 | user@pc:~$ mosquitto_sub -h localhost -t Try/MQTT/Docker |
mosquitto_sub
:訂閱主題。-h
:指定 MQTT Broker 的 IP 或 FQDN,此為localhost
。-t
:指定訂閱的主題名稱,此為Try/MQTT/Docker
。
開啟另一個新的 Terminal (在此稱 tty2),輸入指令來發布主題
1 | user@pc:~$ mosquitto_pub -h localhost -t Try/MQTT/Docker -m "Test Message" |
mosquitto_pub
:發布主題。-h
:指定 MQTT Broker 的 IP 或 FQDN,此為localhost
。-t
:指定發布的主題,此為Try/MQTT/Docker
。-m
:發布的訊息,此為Test Message
。
這時在 tty1 應該就能看到 Test Message
的訊息,代表 Mosquitto Container 運行正常且 MQTT Broker 功能可以使用!
使用帳密檔
建立帳密檔
建立帳密檔需使用到 mosquitto_passwd 指令,因此需先安裝 mosquitto
,安裝結束時可能會看到錯誤訊息,這錯誤是因為當 mosquitto
安裝好後預設會自動啟動服務且 Port 為 1883,與我們的 Docker 相衝突,因此不需理會。除此之外,這裡我們只是要拿包含在 mosquitto
的 mosquitto_passwd
指令來使用,所以必須將 mosquitto
的服務關閉,避免占用我們 Docker 要使用的 Port
1 | user@pc:~$ sudo apt-get install mosquitto |
安裝好就可以創建帳密檔
1 | user@pc:~$ sudo mosquitto_passwd -c /mosquitto/config/passwd_file joker # 要創建的使用者名稱為 joker |
-c
:將會新建一個帳密檔,會覆蓋現有的檔案。若只是想新增使用者到已經存在的帳密檔,不加此選項即可。/mosquitto/config/passwd_file
:帳密檔的絕對路徑。joker
:要創建的使用者名稱。
讀取帳密檔
建立好之後,需修改 /mosquitto/config/mosquitto.config
,讓 Mosquitto 知道要去讀取帳密檔,並且取消匿名使用者的登入權限 (匿名登入權限依應用情境而定)
1 | persistence true |
重新運行 Container,使 Mosquitto 讀取的設定檔為最新的內容,使用帳號才能發布 (mosquitto_pub
) 或訂閱 (mosquitto_sub
)
1 | user@pc:~$ sudo docker restart mqtt |
測試帳密訂閱與發布
開啟一個新的 Terminal (在此稱 tty1),使用指令來訂閱主題。但由於我們已經設定為不可匿名登入,可以預想到的是會無法正常運作,因為沒有授權 (也就是沒有指定帳號)
1 | user@pc:~$ mosquitto_sub -h localhost -t Try/MQTT/Docker |
tty1 中的指令更改如下
1 | user@pc:~$ mosquitto_sub -h localhost -t Try/MQTT/Docker -u joker -P 1234 |
-u
:指定使用者帳號。-P
:指定密碼,注意是大寫 P。
開啟另一個新的 Terminal (在此稱 tty2)
1 | user@pc:~$ mosquitto_pub -h localhost -t Try/MQTT/Docker -m "Test Message" -u joker -P 1234 |
這時在 tty1 應該就能看到 Test Message
的訊息,代表帳號密碼機制設定完成並且有正常運作!
使用 ACL 檔
建立 ACL 檔
ACL (Access Control List) 存取控制表是用來描述一個物件對一串列的存取權限,Mosquitto 同樣也提供這個功能。第一步與帳密檔同樣,創建一個檔案 /mosquitto/config/acl
,內容如下
1 | user joker |
- 使用者 joker 只可以讀寫符合 pattern 為
joker/#
的 topic,其中#
為多層級 WildCard 字元 (+
為單一層級),因此joker
、joker/Try
與joker/Try/MQTT
都是符合的 topic。
讀取 ACL 檔
修改 /mosquitto/config/mosquitto.config
,讓 Mosquitto 知道要去讀取 ACL 檔
1 | persistence true |
重新運行 Container,使 Mosquitto 讀取的設定檔為最新的內容,知道 ACL 檔案的存在,這時 ACL 功能就正在運行囉
1 | user@pc:~$ sudo docker restart mqtt |
若嘗試以無權限的 topic (例如:john
) 進行發布與訂閱,會發現雖然沒有出現錯誤訊息 (例如:權限不足),但真的發送不出去,也接收不到的哦!
WebSocket MQTT
啟用 WebSocket MQTT
WebSocket 是一種可在單個 TCP 連線上全雙工的通訊協定,只需要交握一次,便能建立永久的連線,進行雙向資料傳輸。對於需要低功耗的 IoT 應用來說,透過 WebSocket 使用 MQTT 的訂閱與發佈可以比傳統單純只使用 MQTT 來的節能,因此知道如何開啟 Mosquitto 的 WebSocket 通訊是必要的。
修改 /mosquitto/config/mosquitto.config
1 | persistence true |
- 一般 MQTT 協定在 1883 Port 服務
- WebSocket MQTT 在 9001 Port 服務
刪除正在運行的 MQTT Container,並建立一個比原先多綁定 Port 9001 的 Container
1 | user@pc:~$ sudo docker rm -f mqtt |
測試 WebSocket MQTT
WebSocket MQTT 不像 MQTT 可使用 mosquitto_pub
/mosquitto_sub
進行測試,因為這兩個指令不支援 WebSocket 通訊協定。這裡要介紹一個 MQTT 開發的好朋友 MQTTBox,MQTTBox 有 Chrome 瀏覽器的擴充套件版本,因此只要有 Chrome 瀏覽器就可以安裝使用!安裝 MQTTBox 並將其開啟,新建一個 MQTT Client,只需填寫 MQTT Client Name
、Protocol
、Host
、Username
、Password
五個欄位即可,其中因為我們要測試的是 WS MQTT 協定,因此 Protocol 要選擇 ws
建立好並存檔,同時確認畫面上方 Connected 按鈕為綠色的,表示連線正常,這時就可以來發布/訂閱測試啦!在 Topic to publish
與 Topic to subscribe
兩個欄位填寫相同的主題名稱,先訂閱再發布,就會再訂閱區塊中看到發布的訊息囉!
確認 WS MQTT 可以正常運行!
MQTTS 與 WSS
Mosquitto 有提供 MQTTS 與 WSS 通訊協定,協定名稱中最後一個字母 S 皆代表 SSL,SSL 能使我們的通訊透過加密防止中間人或竊聽攻擊,要使用 SSL 必須先擁有憑證,然而申請一個正式憑證需要較多手續與耗費許多時日。因此在測試環境中我們可以先自簽憑證,測試加上 SSL 後系統是否能正常運作,若之後系統要上線,再替換為正式的憑證即可。
自簽憑證
詳細步驟與說明可以參考 [SSL] 自簽憑證過程
1 | # 創建目錄 |
- 最最最需要注意的是 CA 的 CN 與 Server 的 CN 不能一樣,否則會出現意想不到的錯誤。
將 ca.crt
、server.key
、server.crt
移至 /mosquitto/config/certs/
目錄下。
1 | # 創建目錄 |
啟用 MQTTS 與 WSS
修改 /mosquitto/config/mosquitto.config
1 | persistence true |
刪除正在運行的 MQTT Container,並建立一個比原先多綁定 Port 8883 與 8884 的 Container
1 | user@pc:~$ sudo docker rm -f mqtt |
測試 MQTTS
MQTTS 可使用指令來測試
開啟一個新的 Terminal (在此稱 tty1),使用指令來訂閱主題
1 | user@pc:~$ mosquitto_sub --cafile /mosquitto/config/certs/ca.crt -t joker/Try/MQTT -h localhost \ |
--cafile
:CA 的憑證。--insecure
:不要驗證憑證合法性。使用此選項是因為這裡我們使用的是自簽憑證,若驗證憑證合法性一定有很多問題會出現,我們的目的只是想先測試 MQTTS 是否可以正常運作,因此不需驗證憑證合法性。-p
:指定要連接的 Port,若沒指定預設為 1883 Port。
開啟另一個新的 Terminal (在此稱 tty2)
1 | user@pc:~$ mosquitto_pub --cafile /mosquitto/config/certs/ca.crt -t joker/Try/MQTT -m "Test Message" -h localhost \ |
這時在 tty1 應該就能看到 Test Message
的訊息,代表 MQTTS 設定完成並且有正常運作!
測試 WSS MQTT
WSS 的測試與 WS 測試相同,利用 MQTTBox 來做測試,但是擴充套件的似乎無法處理 SSL 的部分,不管我如何設定都會出現連線錯誤,因此我使用另一台電腦 (Windows 10) 安裝 MQTTBox 本體來測試連線,WSS 連線設定與 WS 不同的一點是多了 SSL/TLS Version
與 SSL/TLS Certificate Type
欄位,只需更動 Type 選擇 CA Signed server certificate
即可
至此, MQTT/MQTTS/WS/WSS 四個通訊協定都已經正常運作,最終選擇所要使用的通訊協定還是要回歸到應用情境,若沒用到的 Port 可以選擇關閉以釋放系統資源。
結語
這篇文章記錄了如何使用 Docker 輕鬆架設 MQTT Broker (Mosquitto),並且使用身分驗證、ACL 權限控管,啟動 MQTT/MQTTS/WS/WSS 四個協定。當然,還有更多的進階設定沒有在此篇文章中紀載,但架設伺服器的第一步,就是先將基本設定完善,並確認能夠運行,才能繼續下一步的調教。