684 lines
19 KiB
Go
684 lines
19 KiB
Go
package c_middle
|
||
|
||
const CmiiEmqxTemplate = `
|
||
---
|
||
# ============== Secret - 密码管理 ==============
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: emqx-credentials
|
||
namespace: {{ .Namespace }}
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
app.kubernetes.io/managed-by: octopus-control
|
||
app.kubernetes.io/version: {{ .TagVersion }}
|
||
type: Opaque
|
||
stringData:
|
||
# Dashboard管理员密码
|
||
dashboard-admin-password: "{{ .EmqxPassword }}"
|
||
# MQTT用户密码
|
||
mqtt-admin-password: "{{ .EmqxPassword }}"
|
||
|
||
---
|
||
# ============== ServiceAccount ==============
|
||
apiVersion: v1
|
||
kind: ServiceAccount
|
||
metadata:
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
|
||
---
|
||
# ============== Role - RBAC ==============
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: Role
|
||
metadata:
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
rules:
|
||
- apiGroups: [""]
|
||
resources:
|
||
- endpoints
|
||
- pods
|
||
verbs:
|
||
- get
|
||
- watch
|
||
- list
|
||
|
||
---
|
||
# ============== RoleBinding ==============
|
||
apiVersion: rbac.authorization.k8s.io/v1
|
||
kind: RoleBinding
|
||
metadata:
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
subjects:
|
||
- kind: ServiceAccount
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
roleRef:
|
||
kind: Role
|
||
name: helm-emqxs
|
||
apiGroup: rbac.authorization.k8s.io
|
||
|
||
---
|
||
# ============== ConfigMap - Bootstrap配置文件 ==============
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: emqx-bootstrap-config
|
||
namespace: {{ .Namespace }}
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
data:
|
||
# 主配置文件 - 覆盖默认配置
|
||
emqx.conf: |
|
||
# 节点配置
|
||
node {
|
||
name = "emqx@${POD_NAME}.helm-emqxs-headless.{{ .Namespace }}.svc.cluster.local"
|
||
cookie = "emqx-cluster-cookie-secret"
|
||
data_dir = "/opt/emqx/data"
|
||
}
|
||
|
||
# 集群配置
|
||
cluster {
|
||
name = emqxcl
|
||
# 单节点 建议为 manual 多节点为k8s
|
||
discovery_strategy = manual
|
||
k8s {
|
||
apiserver = "https://kubernetes.default.svc.cluster.local:443"
|
||
service_name = "helm-emqxs-headless"
|
||
# 这里可以改为 hostname
|
||
address_type = dns
|
||
namespace = "{{ .Namespace }}"
|
||
suffix = "svc.cluster.local"
|
||
}
|
||
}
|
||
|
||
# 日志配置
|
||
log {
|
||
console {
|
||
enable = true
|
||
level = info
|
||
}
|
||
file {
|
||
enable = true
|
||
level = warning
|
||
path = "/opt/emqx/log"
|
||
}
|
||
}
|
||
|
||
# Dashboard配置
|
||
dashboard {
|
||
listeners.http {
|
||
bind = "0.0.0.0:18083"
|
||
}
|
||
default_username = "admin"
|
||
default_password = "public"
|
||
}
|
||
|
||
# 监听器配置
|
||
listeners.tcp.default {
|
||
bind = "0.0.0.0:1883"
|
||
max_connections = 1024000
|
||
}
|
||
|
||
listeners.ws.default {
|
||
bind = "0.0.0.0:8083"
|
||
max_connections = 1024000
|
||
websocket.mqtt_path = "/mqtt"
|
||
}
|
||
|
||
listeners.ssl.default {
|
||
bind = "0.0.0.0:8883"
|
||
max_connections = 512000
|
||
}
|
||
|
||
# 认证配置 - 使用内置数据库
|
||
authentication = [
|
||
{
|
||
mechanism = password_based
|
||
backend = built_in_database
|
||
user_id_type = username
|
||
password_hash_algorithm {
|
||
name = sha256
|
||
salt_position = suffix
|
||
}
|
||
# Bootstrap文件路径 - 用于初始化用户
|
||
bootstrap_file = "/opt/emqx/data/bootstrap_users.json"
|
||
bootstrap_type = plain
|
||
}
|
||
]
|
||
|
||
# 授权配置
|
||
authorization {
|
||
no_match = deny
|
||
deny_action = disconnect
|
||
|
||
sources = [
|
||
{
|
||
type = built_in_database
|
||
enable = true
|
||
}
|
||
]
|
||
}
|
||
|
||
# MQTT协议配置
|
||
mqtt {
|
||
max_packet_size = "1MB"
|
||
max_clientid_len = 65535
|
||
max_topic_levels = 128
|
||
max_qos_allowed = 2
|
||
max_topic_alias = 65535
|
||
retain_available = true
|
||
wildcard_subscription = true
|
||
shared_subscription = true
|
||
}
|
||
|
||
---
|
||
# ============== ConfigMap - Users & ACL (严格 JSON 格式) ==============
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: emqx-bootstrap-users
|
||
namespace: {{ .Namespace }}
|
||
data:
|
||
bootstrap_users.json: |
|
||
[
|
||
{ "user_id": "admin", "password": "{{ .EmqxPassword }}", "is_superuser": true },
|
||
{ "user_id": "cmlc", "password": "{{ .EmqxPassword }}", "is_superuser": false }
|
||
]
|
||
|
||
# 【修改点】既然有jq,这里使用标准的 JSON 数组格式,最不容易出错
|
||
bootstrap_acl.json: |
|
||
[
|
||
{
|
||
"username": "admin",
|
||
"rules": [
|
||
{"action": "all", "permission": "allow", "topic": "#"}
|
||
]
|
||
},
|
||
{
|
||
"username": "cmlc",
|
||
"rules": [
|
||
{"action": "publish", "permission": "allow", "topic": "#"},
|
||
{"action": "subscribe", "permission": "allow", "topic": "#"}
|
||
]
|
||
}
|
||
]
|
||
|
||
---
|
||
# ============== ConfigMap - 初始化脚本 (修正版) ==============
|
||
apiVersion: v1
|
||
kind: ConfigMap
|
||
metadata:
|
||
name: emqx-init-dashboard
|
||
namespace: {{ .Namespace }}
|
||
data:
|
||
init-dashboard.sh: |
|
||
#!/bin/bash
|
||
set -e
|
||
|
||
DASHBOARD_USER="admin"
|
||
DASHBOARD_PASS="${DASHBOARD_ADMIN_PASSWORD}"
|
||
EMQX_API="http://localhost:18083/api/v5"
|
||
ACL_FILE="/bootstrap/bootstrap_acl.json"
|
||
|
||
# 辅助函数:打印带时间戳的日志
|
||
log() {
|
||
echo "[$(date +'%H:%M:%S')] $1"
|
||
}
|
||
|
||
log "======================================"
|
||
log "初始化 Dashboard 与 ACL (Debug Version)"
|
||
log "======================================"
|
||
|
||
# ----------------------------------------------------------------
|
||
# 1. 等待 EMQX API 就绪
|
||
# ----------------------------------------------------------------
|
||
log "[1/4] 等待 EMQX API 就绪..."
|
||
for i in $(seq 1 60); do
|
||
if curl -s -f -m 5 "${EMQX_API}/status" > /dev/null 2>&1; then
|
||
log "✓ EMQX API 已就绪"
|
||
break
|
||
fi
|
||
if [ $i -eq 60 ]; then
|
||
log "✗ EMQX API 启动超时"
|
||
exit 1
|
||
fi
|
||
sleep 5
|
||
done
|
||
|
||
# ----------------------------------------------------------------
|
||
# 2. 修改 Dashboard 密码
|
||
# ----------------------------------------------------------------
|
||
log "[2/4] 检查/更新 Dashboard 密码..."
|
||
|
||
# 获取 Token (尝试默认密码)
|
||
LOGIN_RESP=$(curl -s -X POST "${EMQX_API}/login" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{\"username\":\"${DASHBOARD_USER}\",\"password\":\"public\"}")
|
||
|
||
TOKEN=$(echo "$LOGIN_RESP" | jq -r '.token // empty')
|
||
|
||
if [ -n "$TOKEN" ]; then
|
||
log " 检测到默认密码,正在更新..."
|
||
curl -s -f -X POST "${EMQX_API}/users/${DASHBOARD_USER}/change_pwd" \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{\"old_pwd\":\"public\",\"new_pwd\":\"${DASHBOARD_PASS}\"}"
|
||
log " ✓ Dashboard 密码已更新"
|
||
else
|
||
log " ℹ 无法使用默认密码登录,跳过更新(可能已修改)"
|
||
fi
|
||
|
||
# ----------------------------------------------------------------
|
||
# 3. 导入 ACL 规则
|
||
# ----------------------------------------------------------------
|
||
echo "[3/3] 导入ACL规则..."
|
||
|
||
# 重新登录获取最新 Token
|
||
LOGIN_RESP=$(curl -sS -X POST "${EMQX_API}/login" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "{\"username\":\"${DASHBOARD_USER}\",\"password\":\"${DASHBOARD_PASS}\"}")
|
||
|
||
TOKEN=$(echo "$LOGIN_RESP" | jq -r '.token // empty')
|
||
|
||
if [ -z "$TOKEN" ]; then
|
||
echo " ✗ 无法获取Token,请检查密码设置"
|
||
exit 0
|
||
fi
|
||
|
||
if [ -f "$ACL_FILE" ]; then
|
||
echo " 正在解析 ACL 文件: $ACL_FILE"
|
||
|
||
if ! jq -e . "$ACL_FILE" >/dev/null 2>&1; then
|
||
echo " ✗ ACL 文件 JSON 格式错误,跳过处理"
|
||
exit 0
|
||
fi
|
||
|
||
jq -c '.[]' "$ACL_FILE" | while read -r user_config; do
|
||
USERNAME=$(echo "$user_config" | jq -r '.username // empty')
|
||
|
||
# ✅ PUT/POST 都需要 username + rules(username 是 required)
|
||
REQ_BODY=$(echo "$user_config" | jq -c '{username: .username, rules: .rules}')
|
||
|
||
if [ -z "$USERNAME" ]; then
|
||
echo " ✗ ACL 条目缺少 username,跳过"
|
||
continue
|
||
fi
|
||
|
||
echo " 配置用户 ${USERNAME} 的ACL规则..."
|
||
|
||
# 1) 优先 PUT(覆盖更新)
|
||
http_code=$(curl -sS -o /tmp/emqx_acl_resp.json -w '%{http_code}' \
|
||
-X PUT "${EMQX_API}/authorization/sources/built_in_database/rules/users/${USERNAME}" \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "$REQ_BODY")
|
||
|
||
if [ "$http_code" = "204" ]; then
|
||
echo " ✓ PUT 更新成功"
|
||
elif [ "$http_code" = "404" ]; then
|
||
# 2) 不存在则 POST 创建
|
||
http_code2=$(curl -sS -o /tmp/emqx_acl_resp.json -w '%{http_code}' \
|
||
-X POST "${EMQX_API}/authorization/sources/built_in_database/rules/users" \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
-H 'Content-Type: application/json' \
|
||
-d "$REQ_BODY")
|
||
|
||
if [ "$http_code2" = "204" ]; then
|
||
echo " ✓ POST 创建成功"
|
||
else
|
||
echo " ✗ POST 失败 (HTTP ${http_code2}):$(cat /tmp/emqx_acl_resp.json 2>/dev/null || true)"
|
||
exit 1
|
||
fi
|
||
else
|
||
echo " ✗ PUT 失败 (HTTP ${http_code}):$(cat /tmp/emqx_acl_resp.json 2>/dev/null || true)"
|
||
exit 1
|
||
fi
|
||
|
||
# 3) 导入后验证(可选但强烈建议保留)
|
||
verify_code=$(curl -sS -o /tmp/emqx_acl_verify.json -w '%{http_code}' \
|
||
-H "Authorization: Bearer ${TOKEN}" \
|
||
"${EMQX_API}/authorization/sources/built_in_database/rules/users/${USERNAME}")
|
||
|
||
if [ "$verify_code" = "200" ]; then
|
||
echo " ✓ 验证成功:$(cat /tmp/emqx_acl_verify.json | jq -c '.')"
|
||
else
|
||
echo " ✗ 验证失败 (HTTP ${verify_code}):$(cat /tmp/emqx_acl_verify.json 2>/dev/null || true)"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
echo " ✓ ACL 规则导入完成"
|
||
else
|
||
echo " ℹ 未找到 ACL 文件"
|
||
fi
|
||
|
||
---
|
||
# ============== StatefulSet ==============
|
||
apiVersion: apps/v1
|
||
kind: StatefulSet
|
||
metadata:
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
helm.sh/chart: emqx-1.1.0
|
||
app.kubernetes.io/managed-by: octopus-control
|
||
app.kubernetes.io/version: {{ .TagVersion }}
|
||
spec:
|
||
replicas: 1
|
||
serviceName: helm-emqxs-headless
|
||
podManagementPolicy: Parallel
|
||
updateStrategy:
|
||
type: RollingUpdate
|
||
selector:
|
||
matchLabels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
|
||
template:
|
||
metadata:
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
helm.sh/chart: emqx-1.1.0
|
||
app.kubernetes.io/managed-by: octopus-control
|
||
app.kubernetes.io/version: {{ .TagVersion }}
|
||
spec:
|
||
affinity:
|
||
nodeAffinity:
|
||
requiredDuringSchedulingIgnoredDuringExecution:
|
||
nodeSelectorTerms:
|
||
- matchExpressions:
|
||
- key: uavcloud.env
|
||
operator: In
|
||
values:
|
||
{{- if .TenantEnv }}
|
||
- {{ .TenantEnv }}
|
||
{{- else }}
|
||
- {{ .Namespace }}
|
||
{{- end }}
|
||
podAntiAffinity:
|
||
preferredDuringSchedulingIgnoredDuringExecution:
|
||
- weight: 100
|
||
podAffinityTerm:
|
||
labelSelector:
|
||
matchExpressions:
|
||
- key: cmii.app
|
||
operator: In
|
||
values:
|
||
- helm-emqxs
|
||
topologyKey: kubernetes.io/hostname
|
||
|
||
imagePullSecrets:
|
||
- name: harborsecret
|
||
|
||
serviceAccountName: helm-emqxs
|
||
|
||
securityContext:
|
||
fsGroup: 1000
|
||
runAsUser: 1000
|
||
|
||
# InitContainer - 准备bootstrap文件
|
||
initContainers:
|
||
- name: prepare-bootstrap
|
||
# 动态选择 tools 镜像
|
||
{{- if .HarborPort }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/tools:1.0
|
||
{{- else }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}cmii/tools:1.0
|
||
{{- end }}
|
||
imagePullPolicy: IfNotPresent
|
||
# =========================================================
|
||
# 权限: 必须以 root 身份运行才能 chown
|
||
# =========================================================
|
||
securityContext:
|
||
runAsUser: 0
|
||
command:
|
||
- /bin/sh
|
||
- -c
|
||
- |
|
||
echo "准备bootstrap文件..."
|
||
|
||
# 创建数据目录
|
||
mkdir -p /opt/emqx/data
|
||
|
||
# 复制bootstrap文件到数据目录
|
||
# 只在文件不存在时复制,避免覆盖已有数据
|
||
if [ ! -f /opt/emqx/data/bootstrap_users.json ]; then
|
||
cp /bootstrap-src/bootstrap_users.json /opt/emqx/data/
|
||
echo "✓ 已复制用户bootstrap文件"
|
||
else
|
||
echo "ℹ 用户bootstrap文件已存在,跳过"
|
||
fi
|
||
|
||
# 设置权限 (现在有root权限,可以成功)
|
||
chown -R 1000:1000 /opt/emqx/data
|
||
|
||
echo "✓ Bootstrap准备完成"
|
||
volumeMounts:
|
||
- name: emqx-data
|
||
mountPath: /opt/emqx/data
|
||
- name: bootstrap-users
|
||
mountPath: /bootstrap-src
|
||
|
||
containers:
|
||
# 主容器 - EMQX
|
||
- name: emqx
|
||
# 动态选择 emqx 镜像
|
||
{{- if .HarborPort }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/emqx:5.8.8
|
||
{{- else }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}emqx:5.8.8
|
||
{{- end }}
|
||
imagePullPolicy: IfNotPresent
|
||
|
||
env:
|
||
# Pod信息
|
||
- name: POD_NAME
|
||
valueFrom:
|
||
fieldRef:
|
||
fieldPath: metadata.name
|
||
- name: EMQX_DATA_DIR
|
||
value: "/opt/emqx/data"
|
||
|
||
ports:
|
||
- name: mqtt
|
||
containerPort: 1883
|
||
- name: mqttssl
|
||
containerPort: 8883
|
||
- name: ws
|
||
containerPort: 8083
|
||
- name: dashboard
|
||
containerPort: 18083
|
||
- name: ekka
|
||
containerPort: 4370
|
||
|
||
resources:
|
||
requests:
|
||
cpu: "500m"
|
||
memory: "512Mi"
|
||
limits:
|
||
cpu: "2000m"
|
||
memory: "2Gi"
|
||
|
||
livenessProbe:
|
||
httpGet:
|
||
path: /status
|
||
port: 18083
|
||
initialDelaySeconds: 60
|
||
periodSeconds: 30
|
||
timeoutSeconds: 10
|
||
failureThreshold: 3
|
||
|
||
readinessProbe:
|
||
httpGet:
|
||
path: /status
|
||
port: 18083
|
||
initialDelaySeconds: 10
|
||
periodSeconds: 10
|
||
timeoutSeconds: 5
|
||
failureThreshold: 3
|
||
|
||
startupProbe:
|
||
httpGet:
|
||
path: /status
|
||
port: 18083
|
||
initialDelaySeconds: 10
|
||
periodSeconds: 5
|
||
failureThreshold: 30
|
||
|
||
volumeMounts:
|
||
- name: emqx-data
|
||
mountPath: /opt/emqx/data
|
||
# 使用 subPath 挂载单个配置文件,避免覆盖目录
|
||
- name: bootstrap-config
|
||
mountPath: /opt/emqx/etc/emqx.conf
|
||
subPath: emqx.conf
|
||
|
||
# Sidecar - 初始化Dashboard密码和ACL
|
||
- name: init-dashboard
|
||
# 动态选择 tools 镜像
|
||
{{- if .HarborPort }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/tools:1.0
|
||
{{- else }}
|
||
image: {{ .HarborIPOrCustomImagePrefix }}cmii/tools:1.0
|
||
{{- end }}
|
||
imagePullPolicy: IfNotPresent
|
||
|
||
command:
|
||
- /bin/sh
|
||
- -c
|
||
- |
|
||
# 等待主容器启动
|
||
echo "等待EMQX启动..."
|
||
sleep 20
|
||
|
||
# 执行初始化
|
||
/bin/sh /scripts/init-dashboard.sh
|
||
|
||
# 保持运行
|
||
echo "初始化完成,进入守护模式..."
|
||
while true; do sleep 3600; done
|
||
|
||
env:
|
||
- name: DASHBOARD_ADMIN_PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: emqx-credentials
|
||
key: dashboard-admin-password
|
||
|
||
resources:
|
||
requests:
|
||
cpu: "100m"
|
||
memory: "64Mi"
|
||
limits:
|
||
cpu: "200m"
|
||
memory: "128Mi"
|
||
|
||
volumeMounts:
|
||
- name: init-script
|
||
mountPath: /scripts
|
||
- name: bootstrap-users
|
||
mountPath: /bootstrap
|
||
|
||
volumes:
|
||
- name: bootstrap-config
|
||
configMap:
|
||
name: emqx-bootstrap-config
|
||
- name: bootstrap-users
|
||
configMap:
|
||
name: emqx-bootstrap-users
|
||
- name: init-script
|
||
configMap:
|
||
name: emqx-init-dashboard
|
||
defaultMode: 0755
|
||
- name: emqx-data
|
||
persistentVolumeClaim:
|
||
claimName: helm-emqxs
|
||
|
||
---
|
||
# ============== Service - Headless ==============
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: helm-emqxs-headless
|
||
namespace: {{ .Namespace }}
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
helm.sh/chart: emqx-1.1.0
|
||
app.kubernetes.io/managed-by: octopus-control
|
||
app.kubernetes.io/version: {{ .TagVersion }}
|
||
spec:
|
||
type: ClusterIP
|
||
clusterIP: None
|
||
publishNotReadyAddresses: true
|
||
selector:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
ports:
|
||
- name: mqtt
|
||
port: 1883
|
||
targetPort: 1883
|
||
- name: mqttssl
|
||
port: 8883
|
||
targetPort: 8883
|
||
- name: ws
|
||
port: 8083
|
||
targetPort: 8083
|
||
- name: dashboard
|
||
port: 18083
|
||
targetPort: 18083
|
||
- name: ekka
|
||
port: 4370
|
||
targetPort: 4370
|
||
|
||
---
|
||
# ============== Service - NodePort ==============
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: helm-emqxs
|
||
namespace: {{ .Namespace }}
|
||
labels:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
helm.sh/chart: emqx-1.1.0
|
||
app.kubernetes.io/managed-by: octopus-control
|
||
app.kubernetes.io/version: {{ .TagVersion }}
|
||
spec:
|
||
type: NodePort
|
||
selector:
|
||
cmii.type: middleware
|
||
cmii.app: helm-emqxs
|
||
cmii.emqx.architecture: cluster
|
||
ports:
|
||
- name: mqtt
|
||
port: 1883
|
||
targetPort: 1883
|
||
nodePort: {{ .EmqxNodePort }}
|
||
- name: dashboard
|
||
port: 18083
|
||
targetPort: 18083
|
||
nodePort: {{ .EmqxDashboardNodePort }}
|
||
- name: ws
|
||
port: 8083
|
||
targetPort: 8083
|
||
nodePort: {{ .EmqxWebSocketNodePort }}
|
||
- name: mqttssl
|
||
port: 8883
|
||
targetPort: 8883
|
||
`
|