EMQX を Kubernetes 上にデプロイするには、Helm チャートを利用した簡易手法と、カスタムリソースで完全制御する手法の2通りがあります。以下では、実用的な構成を段階的に解説します。
Helm を用いた迅速なデプロイ
EMQX の公式 Helm リポジトリを追加し、デフォルト設定でクラスタを起動します。
helm repo add emqx https://repos.emqx.io/charts
helm repo update
helm install emqx-cluster emqx/emqx --set service.type=NodePort --set service.nodePorts.dashboard=30083
デプロイ後、Pod の状態とクラスタの接続状況を確認します。
kubectl get pods -l app.kubernetes.io/instance=emqx-cluster
kubectl exec emqx-cluster-0 -- emqx_ctl status
kubectl exec emqx-cluster-0 -- emqx_ctl cluster status
サービスのエンドポイントを確認すると、NodePort で外部アクセス可能なポートが割り当てられています。
kubectl get svc emqx-cluster
# 出力例: emqx-cluster NodePort 10.96.23.45 <none> 1883:31000/TCP,18083:30083/TCP
クラスタのスケールアップは、`helm upgrade` で簡単に実行できます。
helm upgrade emqx-cluster emqx/emqx --set replicaCount=5
永続化クラスタの構築
EMQX のメッセージ状態やクライアントセッションを永続化するには、/opt/emqx/data/mnesia ディレクトリを PVC にマウントします。StorageClass が事前に定義されている前提で、以下のように設定します。
helm install emqx-persistent emqx/emqx \
--set persistence.enabled=true \
--set persistence.storageClassName=fast-ssd \
--set persistence.size=2Gi
各 Pod は、自動的に個別の PVC を生成し、Pod の再スケジュール時にもデータを保持します。
kubectl get pvc -l app.kubernetes.io/instance=emqx-persistent
# 出力例:
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# emqx-data-emqx-persistent-0 Bound pvc-7a1b2c3d-4e5f-6789-0123-456789abcdef 2Gi RWO fast-ssd 2m
# emqx-data-emqx-persistent-1 Bound pvc-8b2c3d4e-5f67-8901-2345-6789abcdef01 2Gi RWO fast-ssd 1m
カスタムリソースによる完全制御
StatefulSet と Headless Service の構成
EMQX クラスタは、ノード間の安定した通信と一意のホスト名が必要です。そのため、StatefulSet と Headless Service を組み合わせて構成します。
Headless Service(ClusterIP: None)は、各 Pod に一意の DNS 名を提供します。
apiVersion: v1
kind: Service
metadata:
name: emqx-headless
spec:
clusterIP: None
selector:
app: emqx
ports:
- name: mqtt
port: 1883
targetPort: 1883
- name: dashboard
port: 18083
targetPort: 18083
StatefulSet では、Pod の名前が emqx-0、emqx-1 のように順序付きで生成され、DNS 名は emqx-0.emqx-headless.default.svc.cluster.local の形式になります。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: emqx
spec:
serviceName: emqx-headless
replicas: 3
selector:
matchLabels:
app: emqx
template:
metadata:
labels:
app: emqx
spec:
containers:
- name: emqx
image: emqx/emqx:5.7.1
ports:
- containerPort: 1883
- containerPort: 18083
env:
- name: EMQX_NAME
value: "emqx"
- name: EMQX_CLUSTER__DISCOVERY_STRATEGY
value: "k8s"
- name: EMQX_CLUSTER__K8S__APISERVER
value: "https://kubernetes.default.svc:443"
- name: EMQX_CLUSTER__K8S__SERVICE_NAME
value: "emqx-headless"
- name: EMQX_CLUSTER__K8S__NAMESPACE
value: "default"
- name: EMQX_CLUSTER__K8S__ADDRESS_TYPE
value: "hostname"
- name: EMQX_CLUSTER__K8S__SUFFIX
value: "svc.cluster.local"
volumeMounts:
- name: emqx-data
mountPath: /opt/emqx/data/mnesia
volumeClaimTemplates:
- metadata:
name: emqx-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
RBAC 設定による API アクセス権限付与
EMQX は Kubernetes API を利用してクラスターノードを自動検出するため、ServiceAccount に適切な権限を付与する必要があります。
apiVersion: v1
kind: ServiceAccount
metadata:
name: emqx-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: emqx-role
rules:
- apiGroups: [""]
resources: ["endpoints", "pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: emqx-binding
subjects:
- kind: ServiceAccount
name: emqx-sa
namespace: default
roleRef:
kind: Role
name: emqx-role
apiGroup: rbac.authorization.k8s.io
StatefulSet のテンプレートにこの ServiceAccount を指定します。
spec:
template:
spec:
serviceAccountName: emqx-sa
ConfigMap による設定分離
環境ごとの設定差異を管理するため、EMQX の設定は ConfigMap で外部化します。
apiVersion: v1
kind: ConfigMap
metadata:
name: emqx-config
data:
EMQX_LISTENER__TCP__DEFAULT: "1883"
EMQX_DASHBOARD__LISTENER__HTTP: "18083"
EMQX_CLUSTER__DISCOVERY_STRATEGY: "k8s"
EMQX_CLUSTER__K8S__APISERVER: "https://kubernetes.default.svc:443"
EMQX_CLUSTER__K8S__SERVICE_NAME: "emqx-headless"
EMQX_CLUSTER__K8S__NAMESPACE: "default"
EMQX_CLUSTER__K8S__ADDRESS_TYPE: "hostname"
EMQX_CLUSTER__K8S__SUFFIX: "svc.cluster.local"
StatefulSet のコンテナに環境変数としてマウントします。
envFrom:
- configMapRef:
name: emqx-config
永続化ストレージの運用
StatefulSet の volumeClaimTemplates は、各 Pod に対して個別の PVC を自動生成します。これにより、ノードが再起動しても、そのノード固有のメッセージデータとセッション情報が保持されます。
StorageClass が local-ssd などの高性能ストレージに設定されている場合、I/O 性能が向上し、高負荷時の安定性が確保されます。
volumeClaimTemplates:
- metadata:
name: emqx-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: local-ssd
resources:
requests:
storage: 5Gi
クラスタを削除しても、PVC はデフォルトで保持されるため、データ復旧が必要な場合に備えて、明示的に削除する必要があります。
kubectl delete statefulset emqx
kubectl delete pvc -l app=emqx
EMQX Edge と EMQX Enterprise の差異
EMQX Edge は軽量版で、リソース制約のあるエッジデバイス向けです。イメージ名を変更するだけでデプロイ可能です。
helm install emqx-edge emqx/emqx \
--set image.repository=emqx/emqx-edge \
--set image.tag=5.7.1
EMQX Enterprise はライセンスキーが必要です。Secret にライセンスファイルを登録し、デプロイ時に指定します。
kubectl create secret generic emqx-license --from-file=./emqx.lic
helm install emqx-enterprise emqx/emqx-ee \
--set emqxLicenseSecretName=emqx-license
運用上の注意点
- EMQX のクラスタサイズは奇数ノード(3, 5, 7)が推奨。偶数ではクォーラム形成が不安定になる可能性があります。
- NodePort は環境ごとに変動するため、プロダクションでは Ingress や LoadBalancer を使用してください。
- TLS 証明書は、Ingress や外部ロードバランサで終端するのがセキュリティ上推奨です。
- EMQX 5.7 以降では、
cluster.discoveryがcluster.discovery_strategyに変更されています。設定名の変更を忘れずに。
これらの構成により、EMQX は Kubernetes 上で高可用性かつスケーラブルな MQTT ブローカーとして運用可能になります。