一、前置操作:创建命名空间
先为 EMQX 单独创建命名空间,隔离资源,避免与其他服务冲突:
二、核心配置文件:emqx-cluster.yaml
核心配置包含 Headless Service、NodePort Service、ConfigMap、StatefulSet 四部分,需重点关注集群通信、端口映射、存储与部署策略。
1. 配置文件完整内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
| apiVersion: v1 kind: Service metadata: name: emqx-headless namespace: emqx spec: selector: app: emqx clusterIP: None # Headless 服务,无集群IP,用于集群内部通信 publishNotReadyAddresses: true # 允许未就绪节点被发现,保障集群启动 ports: - name: mqtt port: 1883 - name: ws port: 8083 - name: cluster port: 4370 # EMQX 集群通信端口 - name: epmd port: 5369 # Erlang 节点发现端口 --- apiVersion: v1 kind: Service metadata: name: emqx-nodeport namespace: emqx spec: selector: app: emqx type: NodePort # 暴露节点端口,供外部访问 ports: - name: mqtt port: 1883 targetPort: 1883 nodePort: 31883 # 外部访问 MQTT TCP 端口 - name: ws port: 8083 targetPort: 8083 nodePort: 30083 # 外部访问 MQTT WebSocket 端口 - name: dashboard port: 18083 targetPort: 18083 nodePort: 31083 # 外部访问 EMQX 管理页面端口 --- apiVersion: v1 kind: ConfigMap metadata: name: emqx-config namespace: emqx data: emqx.conf: | node { data_dir = "/opt/emqx/data" # 数据存储目录 }
cluster { name = emqxcl # 集群名称 discovery_strategy = static # 静态集群发现(核心,指定节点列表) autoheal = true # 集群自动修复 static { # 静态节点列表,格式:emqx@<pod名>.<headless服务名>.<命名空间>.svc.cluster.local seeds = ["emqx@emqx-0.emqx-headless.emqx.svc.cluster.local", "emqx@emqx-1.emqx-headless.emqx.svc.cluster.local", "emqx@emqx-2.emqx-headless.emqx.svc.cluster.local"] } }
# MQTT 基础配置(端口、连接数等,保持默认即可) mqtt { max_packet_size = 268435455 } listeners.tcp.default { bind = 1883; max_connections = 1024 } listeners.ws.default { enable = true; bind = 8083; max_connections = 1024 } listeners.ssl.default { enable = false } listeners.wss.default { enable = false }
# 管理页面配置 dashboard { listeners.http { bind = 18083 } } --- apiVersion: apps/v1 kind: StatefulSet metadata: name: emqx namespace: emqx spec: serviceName: emqx-headless # 关联 Headless 服务,保障固定网络标识 replicas: 3 # 三节点集群 selector: matchLabels: app: emqx updateStrategy: type: RollingUpdate # 滚动更新(更新顺序:2→1→0) template: metadata: labels: app: emqx spec: # 亲和性配置:避免同一节点部署多个 EMQX 实例,保证高可用 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - emqx topologyKey: "kubernetes.io/hostname" containers: - name: emqx imagePullPolicy: IfNotPresent image: "mydockerregistry.com:5000/emqx:5.8.6" # 替换为你的 EMQX 镜像地址 ports: - containerPort: 1883; name: mqtt - containerPort: 8083; name: ws - containerPort: 18083; name: dashboard - containerPort: 4370; name: cluster - containerPort: 5369; name: epmd # 环境变量:配置节点名称、Cookie、管理页面账号密码 env: - name: POD_NAME valueFrom: { fieldRef: { fieldPath: metadata.name } } - name: EMQX_NODE__NAME value: "emqx@$(POD_NAME).emqx-headless.emqx.svc.cluster.local" # 动态生成节点名 - name: EMQX_NODE__COOKIE value: "emqxsecretcookie" # 集群 Cookie(所有节点需一致) - name: EMQX_DASHBOARD__DEFAULT_USERNAME value: "admin" # 管理页面默认用户名 - name: EMQX_DASHBOARD__DEFAULT_PASSWORD value: "password@123" # 管理页面默认密码(建议部署后修改) # 挂载配置与存储 volumeMounts: - name: emqx-data mountPath: /opt/emqx/data # 数据持久化目录 - name: emqx-config mountPath: /opt/emqx/etc/emqx.conf subPath: emqx.conf # 挂载 ConfigMap 中的 emqx.conf # 健康检查:确保实例正常运行 livenessProbe: tcpSocket: { port: 1883 } initialDelaySeconds: 60 # 启动60秒后开始检查 periodSeconds: 10 # 每10秒检查一次 timeoutSeconds: 5 failureThreshold: 3 volumes: - name: emqx-config configMap: { name: emqx-config } # 关联 ConfigMap podManagementPolicy: OrderedReady # 顺序启动(启动顺序:0→1→2) # 存储声明模板:为每个节点分配独立存储 volumeClaimTemplates: - metadata: name: emqx-data spec: accessModes: [ "ReadWriteOnce" ] # 单节点读写 resources: requests: { storage: 2Gi } # 每个节点申请2Gi存储 storageClassName: "local-path" # 存储类(需提前创建,如 local-path 或云存储)
|
三、部署与验证
1. 应用配置文件
执行部署命令,加载 emqx-cluster.yaml
配置:
1
| kubectl apply -f emqx-cluster.yaml
|
2. 验证部署状态
(1)查看 Pod 状态(需全部为 Running)
1
| kubectl -n emqx get pods -o wide
|
示例输出(三节点均 Running 表示启动成功):
1 2 3 4 5 6 7
| NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
emqx-0 1/1 Running 1 (27m ago) 15h 10.42.3.196 k3s-node3 \<none>
emqx-1 1/1 Running 1 (28m ago) 15h 10.42.0.245 k3s-node1 \<none>
emqx-2 1/1 Running 1 (27m ago) 15h 10.42.1.200 k3s-node2 \<none>
|
(2)查看存储声明(需全部为 Bound)
示例输出(存储均 Bound 表示持久化配置生效):
1 2 3 4 5 6 7
| NAME STATUS VOLUME CAPACITY ACCESS MODES
emqx-data-emqx-0 Bound pvc-caea27ef-28a9-4d68-9c5a-0bdedb3cf819 2Gi RWO
emqx-data-emqx-1 Bound pvc-f4e575df-0411-4892-a6ad-af5adabe8243 2Gi RWO
emqx-data-emqx-2 Bound pvc-17550095-4775-4c59-aade-c095872b0348 2Gi RWO
|
(3)查看 Service 状态(确认端口映射)
1
| kubectl -n emqx get svc -o wide
|
示例输出(NodePort 端口 31883/30083/31083 需正常显示):
1 2 3 4 5
| NAME TYPE CLUSTER-IP PORT(S) AGE
emqx-headless ClusterIP None 1883/TCP,8083/TCP,4370/TCP,5369/TCP 15h
emqx-nodeport NodePort 10.43.96.210 1883:31883/TCP,8083:30083/TCP,18083:31083/TCP 15h
|
四、关键说明与注意事项
端口用途:
1883(TCP)/8083(WebSocket):MQTT 客户端连接端口;
18083:EMQX 管理页面端口(访问地址:http://k8s-node-ip:31083
);
4370/5369:EMQX 集群内部通信端口(无需外部暴露)。
外部访问建议:
安全优化:
部署脚本参考:
完整脚本可查看 GitHub 仓库:https://github.com/PCJ600/emqx-deploy