EMQTT StatefulSet 與 k8s 服務發現
用 StatefulSet + Headless Service 部署 EMQTT 叢集,叢集成員透過 Kubernetes API 自動發現,不需要手動填 master IP。這是比 Deployment + HPA 那份 更穩定的做法。
檔案
mqtt.yaml— Headless Service 與 StatefulSetDockerfile— 從原始碼建置 EMQ v2.3-rc.2 的 Alpine 映像start.sh— 容器進入點,把環境變數映射成 EMQ 設定
Headless Service
clusterIP: None 讓每個 Pod 都有獨立的 DNS 記錄,Erlang 節點才能直接互相連線:
apiVersion: v1
kind: Service
metadata:
name: emqtt
namespace: emqtt
spec:
clusterIP: None
ports:
- port: 1883
name: mqtt
- port: 4369
name: mapping
selector:
app: emqtt
叢集自動發現
關鍵在這幾個環境變數,EMQ 會去問 Kubernetes API 有哪些同伴:
env:
- name: EMQ_CLUSTER__DISCOVERY
value: "k8s"
- name: EMQ_CLUSTER__K8S__APISERVER
value: "https:\\/\\/kubernetes.default:443"
- name: EMQ_CLUSTER__K8S__SERVICE_NAME
value: "emqtt"
- name: EMQ_CLUSTER__K8S__ADDRESS_TYPE
value: "ip"
- name: EMQ_CLUSTER__AUTOHEAL
value: "on"
- name: EMQ_CLUSTER__AUTOCLEAN
value: "5m"
AUTOHEAL讓網路分裂復原後自動修復叢集AUTOCLEAN5 分鐘後移除離線節點,避免殘留幽靈成員
環境變數如何變成設定
start.sh 掃過所有 EMQ_ 開頭的環境變數,把名稱轉成設定檔的鍵再 sed 進 emq.conf:
VAR_NAME=$(echo "$VAR" | sed -r "s/EMQ_(.*)=.*/\1/g" \
| tr '[:upper:]' '[:lower:]' | sed -r "s/__/\./g")
所以 EMQ_CLUSTER__K8S__APISERVER 對應到設定檔裡的 cluster.k8s.apiserver。雙下底線就是設定層級的分隔符號。
腳本同時做了健康監控:連續 5 次(約 25 秒)偵測到 emqttd 沒在執行就讓容器結束,交給 Kubernetes 重啟,而不是無聲地卡住。
部署
kubectl create namespace emqtt
kubectl apply -f mqtt.yaml
# 確認兩個 Pod 都成為叢集成員
kubectl -n emqtt exec emqtt-0 -- emqttd_ctl cluster status
# 擴展
kubectl -n emqtt scale statefulset emqtt --replicas=5
需要更新的地方
apps/v1beta1的 StatefulSet 已移除,改用apps/v1(需要明確寫spec.selector)EMQ_NODE__COOKIE寫死在清單裡。Erlang cookie 等同叢集的共用密鑰,應該改成 Kubernetes Secret 引用- 查詢 Kubernetes API 需要對應的 ServiceAccount 與 RBAC 授權(讀取 endpoints)
- EMQ v2.3 已相當舊,新版專案改名為 EMQX,設定鍵名有變動
← 回到 EMQTT Autoscale