diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 7aeaeae..7c5a1f9 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,18 +4,10 @@
-
+
-
-
-
-
-
-
-
-
@@ -32,6 +24,11 @@
+
{}
@@ -60,46 +57,46 @@
- {
+ "keyToString": {
+ "DefaultGoTemplateProperty": "Go File",
+ "Go Build.agent-wdd运行.executor": "Run",
+ "Go Build.go build agent-wdd.executor": "Run",
+ "Go Test.3580-cmii镜像.executor": "Run",
+ "Go Test.DCU-CMII.executor": "Run",
+ "Go Test.DCU-RKE-35.80.executor": "Run",
+ "Go Test.DCU-中间件.executor": "Run",
+ "Go Test.DCU全部CMII镜像.executor": "Run",
+ "Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator (1).executor": "Run",
+ "Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator.executor": "Run",
+ "Go Test.TestCmiiEnvDeploy_XiongAnJianGuanPingTai in wdd.io/agent-operator.executor": "Run",
+ "Go Test.TestCmiiEnvDeploy_XiongAnKongNengYuan in wdd.io/agent-operator.executor": "Run",
+ "Go Test.TestCmiiEnvDeploy_ZhejiangErjiPingTai in wdd.io/agent-operator.executor": "Run",
+ "Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image (1).executor": "Run",
+ "Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image.executor": "Run",
+ "Go Test.TestHarborOperator_RepoListAll in wdd.io/agent-operator/image.executor": "Run",
+ "Go Test.查询可删除Tag3580.executor": "Run",
+ "Go Test.清理CMII镜像-35.80.executor": "Run",
+ "Go Test.院内Harbor清理-35.80.executor": "Run",
+ "PowerShell.one-build-and-upload.ps1 (1).executor": "Run",
+ "PowerShell.one-build-and-upload.ps1.executor": "Run",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.git.unshallow": "true",
+ "RunOnceActivity.go.formatter.settings.were.checked": "true",
+ "RunOnceActivity.go.migrated.go.modules.settings": "true",
+ "RunOnceActivity.typescript.service.memoryLimit.init": "true",
+ "git-widget-placeholder": "main",
+ "go.import.settings.migrated": "true",
+ "last_opened_file_path": "C:/Users/wddsh/Documents/IdeaProjects/WddSuperAgent/agent-common/SplitProject/监管平台-Doris-k8s",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "settings.editor.selected.configurable": "Errors",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
+}
@@ -107,7 +104,7 @@
-
+
@@ -130,6 +127,7 @@
+
@@ -142,6 +140,8 @@
+
+
@@ -243,7 +243,10 @@
-
+
+
+
+
@@ -285,19 +288,39 @@
1768788677741
-
+
+
+ 1768811251589
+
+
+
+ 1768811251589
+
+
+
+
+
-
+
+
diff --git a/agent-deploy/c_middle/CmiiEmqxTemplate.go b/agent-deploy/c_middle/CmiiEmqxTemplate.go
index 8dd94f3..981583f 100644
--- a/agent-deploy/c_middle/CmiiEmqxTemplate.go
+++ b/agent-deploy/c_middle/CmiiEmqxTemplate.go
@@ -2,6 +2,26 @@ 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:
@@ -9,155 +29,336 @@ metadata:
namespace: {{ .Namespace }}
---
-apiVersion: v1
-kind: ConfigMap
+# ============== Role - RBAC ==============
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
metadata:
- name: helm-emqxs-env
+ 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 }}
-data:
- # 集群相关
- EMQX_CLUSTER__DISCOVERY: "k8s"
- EMQX_CLUSTER__K8S__APISERVER: "https://kubernetes.default.svc.cluster.local:443"
- EMQX_CLUSTER__K8S__APP_NAME: "helm-emqxs"
- EMQX_CLUSTER__K8S__SERVICE_NAME: "helm-emqxs-headless"
- EMQX_CLUSTER__K8S__ADDRESS_TYPE: "dns"
- EMQX_CLUSTER__K8S__NAMESPACE: "{{ .Namespace }}"
- EMQX_CLUSTER__K8S__SUFFIX: "svc.cluster.local"
- # 关闭匿名,默认 ACL 不匹配拒绝
- EMQX_AUTH__ALLOW_ANONYMOUS: "false"
- EMQX_AUTHZ__NO_MATCH: "deny"
- # Dashboard 初始管理员密码(只在第一次启动时生效)
- EMQX_DASHBOARD__DEFAULT_PASSWORD: "{{ .EmqxPassword }}"
+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: helm-emqxs-init-script
+ name: emqx-bootstrap-config
namespace: {{ .Namespace }}
labels:
cmii.type: middleware
cmii.app: helm-emqxs
data:
- init-mqtt-user.sh: |
- #!/bin/sh
+ # 主配置文件 - 覆盖默认配置
+ 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="{{ .EmqxPassword }}"
- MQTT_USER="admin"
- MQTT_PASS="{{ .EmqxPassword }}"
- # 等待 EMQX 本地 API 就绪
+ DASHBOARD_PASS="${DASHBOARD_ADMIN_PASSWORD}"
EMQX_API="http://localhost:18083/api/v5"
- echo "等待 EMQX API 就绪..."
- for i in $(seq 1 120); do
+ 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
- echo "EMQX API 已就绪"
+ log "✓ EMQX API 已就绪"
break
fi
- echo "等待中... ($i/120)"
+ if [ $i -eq 60 ]; then
+ log "✗ EMQX API 启动超时"
+ exit 1
+ fi
sleep 5
done
- # 修改 Dashboard 管理员密码
- echo "修改 Dashboard 管理员密码..."
- /opt/emqx/bin/emqx ctl admins passwd "${DASHBOARD_USER}" "${DASHBOARD_PASS}" || echo "密码可能已设置"
- echo "Dashboard 密码设置完成"
- # 获取 Dashboard Token
- echo "获取 Dashboard Token..."
- TOKEN=$(curl -s -X POST "${EMQX_API}/login" \
+
+ # ----------------------------------------------------------------
+ # 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\":\"${DASHBOARD_PASS}\"}" \
- | grep -o '"token":"[^"]*' | cut -d'"' -f4)
- if [ -z "$TOKEN" ]; then
- echo "ERROR: 无法获取 Token"
- exit 1
+ -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
- echo "Token 获取成功"
- # 创建内置数据库认证器(使用 listeners 作用域)
- echo "检查并创建内置数据库认证器..."
- # 为 tcp:default listener 添加认证器
- echo "为 listener tcp:default 配置认证器..."
- curl -s -X POST "${EMQX_API}/authentication/tcp:default" \
- -H "Authorization: Bearer ${TOKEN}" \
+
+ # ----------------------------------------------------------------
+ # 3. 导入 ACL 规则
+ # ----------------------------------------------------------------
+ echo "[3/3] 导入ACL规则..."
+
+ # 重新登录获取最新 Token
+ LOGIN_RESP=$(curl -sS -X POST "${EMQX_API}/login" \
-H 'Content-Type: application/json' \
- -d '{
- "mechanism": "password_based",
- "backend": "built_in_database",
- "user_id_type": "username",
- "password_hash_algorithm": {
- "name": "sha256",
- "salt_position": "suffix"
- }
- }' 2>/dev/null || echo "tcp:default 认证器可能已存在"
- # 为 ws:default listener 添加认证器
- echo "为 listener ws:default 配置认证器..."
- curl -s -X POST "${EMQX_API}/authentication/ws:default" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d '{
- "mechanism": "password_based",
- "backend": "built_in_database",
- "user_id_type": "username",
- "password_hash_algorithm": {
- "name": "sha256",
- "salt_position": "suffix"
- }
- }' 2>/dev/null || echo "ws:default 认证器可能已存在"
- # 等待认证器创建完成
- sleep 2
- # 创建 MQTT 用户
- echo "创建 MQTT 用户: ${MQTT_USER}..."
- curl -s -X POST "${EMQX_API}/authentication/password_based:built_in_database/users?listener_id=tcp:default" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d "{\"user_id\":\"${MQTT_USER}\",\"password\":\"${MQTT_PASS}\",\"is_superuser\":true}" \
- 2>/dev/null || echo "用户可能已存在,尝试更新..."
- # 尝试更新密码
- curl -s -X PUT "${EMQX_API}/authentication/password_based:built_in_database/users/${MQTT_USER}?listener_id=tcp:default" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d "{\"password\":\"${MQTT_PASS}\",\"is_superuser\":true}" \
- 2>/dev/null || true
- echo "MQTT 用户创建/更新完成"
- # 创建授权规则
- echo "配置授权规则..."
- # 创建内置数据库授权源
- curl -s -X POST "${EMQX_API}/authorization/sources" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d '{
- "type": "built_in_database",
- "enable": true
- }' 2>/dev/null || echo "授权源可能已存在"
- sleep 2
- # 为 admin 用户添加授权规则(使用数组格式)
- echo "为 ${MQTT_USER} 用户添加 ACL 规则..."
- curl -s -X POST "${EMQX_API}/authorization/sources/built_in_database/rules/users" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d "[{\"username\":\"${MQTT_USER}\",\"rules\":[{\"action\":\"all\",\"permission\":\"allow\",\"topic\":\"#\"}]}]" \
- 2>/dev/null && echo "ACL 规则创建成功" || echo "规则可能已存在,尝试更新..."
- # 尝试更新规则(PUT 请求需要单个对象,不是数组)
- curl -s -X PUT "${EMQX_API}/authorization/sources/built_in_database/rules/users/${MQTT_USER}" \
- -H "Authorization: Bearer ${TOKEN}" \
- -H 'Content-Type: application/json' \
- -d "{\"rules\":[{\"action\":\"all\",\"permission\":\"allow\",\"topic\":\"#\"}]}" \
- 2>/dev/null && echo "ACL 规则更新成功" || true
- echo "ACL 规则配置完成"
- echo "初始化完成!MQTT 用户: ${MQTT_USER}"
- echo "可通过以下方式连接:"
- echo " - MQTT: localhost:1883"
- echo " - WebSocket: localhost:8083"
- echo " - Dashboard: http://localhost:18083"
- echo " - 用户名: ${MQTT_USER}"
+ -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:
@@ -173,6 +374,7 @@ metadata:
spec:
replicas: 1
serviceName: helm-emqxs-headless
+ podManagementPolicy: Parallel
updateStrategy:
type: RollingUpdate
selector:
@@ -180,6 +382,7 @@ spec:
cmii.type: middleware
cmii.app: helm-emqxs
cmii.emqx.architecture: cluster
+
template:
metadata:
labels:
@@ -203,106 +406,246 @@ spec:
{{- 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
+ - 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:
- - name: helm-emqxs
- {{- if .HarborPort }}
- image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/emqx:5.8.8
- {{- else }}
- image: {{ .HarborIPOrCustomImagePrefix }}emqx:5.8.8
- {{- end }}
- imagePullPolicy: Always
- ports:
- - name: mqtt
- containerPort: 1883
- - name: mqttssl
- containerPort: 8883
- - name: mgmt
- containerPort: 8081
- - name: ws
- containerPort: 8083
- - name: wss
- containerPort: 8084
- - name: dashboard
- containerPort: 18083
- - name: ekka
- containerPort: 4370
- envFrom:
- - configMapRef:
- name: helm-emqxs-env
- # 添加生命周期钩子
- lifecycle:
- postStart:
- exec:
- command:
- - /bin/sh
- - -c
- - |
- # 后台执行初始化脚本,避免阻塞容器启动
- nohup /bin/sh /scripts/init-mqtt-user.sh > /tmp/init.log 2>&1 &
- # 添加健康检查,确保 initContainer 执行时 API 已就绪
- livenessProbe:
- httpGet:
- path: /status
- port: 18083
- initialDelaySeconds: 60
- periodSeconds: 30
- readinessProbe:
- httpGet:
- path: /status
- port: 18083
- initialDelaySeconds: 10
- periodSeconds: 5
- resources: {}
- volumeMounts:
- # 5.x 默认 data 目录,包含所有持久化数据
- - name: emqx-data
- mountPath: "/opt/emqx/data"
- readOnly: false
- - name: init-script
- mountPath: /scripts
+ # 主容器 - 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: emqx-data
- persistentVolumeClaim:
+ - 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
- - name: init-script
- configMap:
- name: helm-emqxs-init-script
- defaultMode: 0755
---
-kind: Role
-apiVersion: rbac.authorization.k8s.io/v1
+# ============== Service - Headless ==============
+apiVersion: v1
+kind: Service
metadata:
- name: helm-emqxs
+ name: helm-emqxs-headless
namespace: {{ .Namespace }}
-rules:
-- apiGroups: [""]
- resources:
- - endpoints
- verbs:
- - get
- - watch
- - list
-
----
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-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
+ 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:
@@ -322,66 +665,19 @@ spec:
cmii.app: helm-emqxs
cmii.emqx.architecture: cluster
ports:
- - port: 1883
- name: mqtt
- targetPort: 1883
- nodePort: {{ .EmqxNodePort }}
- - port: 18083
- name: dashboard
- targetPort: 18083
- nodePort: {{ .EmqxDashboardNodePort }}
- - port: 8083
- name: mqtt-websocket
- targetPort: 8083
- nodePort: {{ .EmqxWebSocketNodePort }}
-
----
-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
- selector:
- cmii.type: middleware
- cmii.app: helm-emqxs
- cmii.emqx.architecture: cluster
- ports:
- - name: mqtt
- port: 1883
- protocol: TCP
- targetPort: 1883
- - name: mqttssl
- port: 8883
- protocol: TCP
- targetPort: 8883
- - name: mgmt
- port: 8081
- protocol: TCP
- targetPort: 8081
- - name: websocket
- port: 8083
- protocol: TCP
- targetPort: 8083
- - name: wss
- port: 8084
- protocol: TCP
- targetPort: 8084
- - name: dashboard
- port: 18083
- protocol: TCP
- targetPort: 18083
- - name: ekka
- port: 4370
- protocol: TCP
- targetPort: 4370
+ - 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
`
diff --git a/agent-deploy/d_app/CmiiImageConfig.go b/agent-deploy/d_app/CmiiImageConfig.go
index 3ba4aa3..85784f1 100644
--- a/agent-deploy/d_app/CmiiImageConfig.go
+++ b/agent-deploy/d_app/CmiiImageConfig.go
@@ -186,11 +186,11 @@ var MiddlewareAmd64 = []string{
"harbor.cdcyy.com.cn/cmii/nfs-subdir-external-provisioner:v4.0.2",
"docker.m.daocloud.io/jerrychina2020/rke-tools:v0.175-linux",
"docker.m.daocloud.io/jerrychina2020/rke-tools:v0.175",
- "harbor.cdcyy.com.cn/cmii/busybox:1.37",
"harbor.cdcyy.com.cn/cmii/doris.be-ubuntu:2.1.6",
"harbor.cdcyy.com.cn/cmii/doris.fe-ubuntu:2.1.6",
"harbor.cdcyy.com.cn/cmii/doris.k8s-operator:1.3.1",
- "harbor.cdcyy.com.cn/cmii/alpine:3.23.0",
+ "harbor.cdcyy.com.cn/cmii/tools:1.0",
+ "harbor.cdcyy.com.cn/cmii/curl:8.18.0",
"harbor.cdcyy.com.cn/cmii/nginx:1.27.0",
}