更新EMQX为5.8.8可运行版本

This commit is contained in:
zeaslity
2026-01-20 11:28:59 +08:00
parent ccdd3227c1
commit 01d78dd7f6
3 changed files with 648 additions and 329 deletions

127
.idea/workspace.xml generated
View File

@@ -4,18 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="6047a167-18d5-4f8e-a170-63c3fd101bda" name="Changes" comment="优化镜像同步的内容"> <list default="true" id="6047a167-18d5-4f8e-a170-63c3fd101bda" name="Changes" comment="优化镜像同步,新增雄安集团监管平台项目">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.run/DCU-中间件.run.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.run/DCU-中间件-35.80.run.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.run/DCU全部CMII镜像.run.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.run/DCU-CMII-35.80.run.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.run/Middle镜像-35.70.run.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.run/Middle镜像-35.70.run.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.run/Middle镜像-ARM-11.8.run.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/agent-deploy/a_dashboard/TemplateK8SDashboard.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/a_dashboard/TemplateK8SDashboard.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiEmqxTemplate.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiEmqxTemplate.go" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiEmqxTemplate.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiEmqxTemplate.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiRedisTemplate.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/c_middle/CmiiRedisTemplate.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-deploy/d_app/CmiiImageConfig.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/d_app/CmiiImageConfig.go" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-deploy/d_app/CmiiImageConfig.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-deploy/d_app/CmiiImageConfig.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-operator/CmiiDeployOperator_test.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-operator/CmiiDeployOperator_test.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-operator/CmiiImageSyncOperator_test.go" beforeDir="false" afterPath="$PROJECT_DIR$/agent-operator/CmiiImageSyncOperator_test.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" afterDir="false" /> <change beforePath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" beforeDir="false" afterPath="$PROJECT_DIR$/agent-wdd/build/agent-wdd_linux_amd64" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@@ -32,6 +24,11 @@
</component> </component>
<component name="GOROOT" url="file://$PROJECT_DIR$/../../../../../Program Files/Go" /> <component name="GOROOT" url="file://$PROJECT_DIR$/../../../../../Program Files/Go" />
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="master-260116" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="KubernetesApiPersistence">{}</component> <component name="KubernetesApiPersistence">{}</component>
@@ -60,46 +57,46 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"DefaultGoTemplateProperty": "Go File", &quot;DefaultGoTemplateProperty&quot;: &quot;Go File&quot;,
"Go Build.agent-wdd运行.executor": "Run", &quot;Go Build.agent-wdd运行.executor&quot;: &quot;Run&quot;,
"Go Build.go build agent-wdd.executor": "Run", &quot;Go Build.go build agent-wdd.executor&quot;: &quot;Run&quot;,
"Go Test.3580-cmii镜像.executor": "Run", &quot;Go Test.3580-cmii镜像.executor&quot;: &quot;Run&quot;,
"Go Test.DCU-CMII.executor": "Run", &quot;Go Test.DCU-CMII.executor&quot;: &quot;Run&quot;,
"Go Test.DCU-RKE-35.80.executor": "Run", &quot;Go Test.DCU-RKE-35.80.executor&quot;: &quot;Run&quot;,
"Go Test.DCU-中间件.executor": "Run", &quot;Go Test.DCU-中间件.executor&quot;: &quot;Run&quot;,
"Go Test.DCU全部CMII镜像.executor": "Run", &quot;Go Test.DCU全部CMII镜像.executor&quot;: &quot;Run&quot;,
"Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator (1).executor": "Run", &quot;Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator (1).executor&quot;: &quot;Run&quot;,
"Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator.executor": "Run", &quot;Go Test.TestCmiiEnvDeploy_WddSuperCluster in wdd.io/agent-operator.executor&quot;: &quot;Run&quot;,
"Go Test.TestCmiiEnvDeploy_XiongAnJianGuanPingTai in wdd.io/agent-operator.executor": "Run", &quot;Go Test.TestCmiiEnvDeploy_XiongAnJianGuanPingTai in wdd.io/agent-operator.executor&quot;: &quot;Run&quot;,
"Go Test.TestCmiiEnvDeploy_XiongAnKongNengYuan in wdd.io/agent-operator.executor": "Run", &quot;Go Test.TestCmiiEnvDeploy_XiongAnKongNengYuan in wdd.io/agent-operator.executor&quot;: &quot;Run&quot;,
"Go Test.TestCmiiEnvDeploy_ZhejiangErjiPingTai in wdd.io/agent-operator.executor": "Run", &quot;Go Test.TestCmiiEnvDeploy_ZhejiangErjiPingTai in wdd.io/agent-operator.executor&quot;: &quot;Run&quot;,
"Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image (1).executor": "Run", &quot;Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image (1).executor&quot;: &quot;Run&quot;,
"Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image.executor": "Run", &quot;Go Test.TestHarborOperator_ArtifactListAll in wdd.io/agent-operator/image.executor&quot;: &quot;Run&quot;,
"Go Test.TestHarborOperator_RepoListAll in wdd.io/agent-operator/image.executor": "Run", &quot;Go Test.TestHarborOperator_RepoListAll in wdd.io/agent-operator/image.executor&quot;: &quot;Run&quot;,
"Go Test.查询可删除Tag3580.executor": "Run", &quot;Go Test.查询可删除Tag3580.executor&quot;: &quot;Run&quot;,
"Go Test.清理CMII镜像-35.80.executor": "Run", &quot;Go Test.清理CMII镜像-35.80.executor&quot;: &quot;Run&quot;,
"Go Test.院内Harbor清理-35.80.executor": "Run", &quot;Go Test.院内Harbor清理-35.80.executor&quot;: &quot;Run&quot;,
"PowerShell.one-build-and-upload.ps1 (1).executor": "Run", &quot;PowerShell.one-build-and-upload.ps1 (1).executor&quot;: &quot;Run&quot;,
"PowerShell.one-build-and-upload.ps1.executor": "Run", &quot;PowerShell.one-build-and-upload.ps1.executor&quot;: &quot;Run&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"RunOnceActivity.git.unshallow": "true", &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
"RunOnceActivity.go.formatter.settings.were.checked": "true", &quot;RunOnceActivity.go.formatter.settings.were.checked&quot;: &quot;true&quot;,
"RunOnceActivity.go.migrated.go.modules.settings": "true", &quot;RunOnceActivity.go.migrated.go.modules.settings&quot;: &quot;true&quot;,
"RunOnceActivity.typescript.service.memoryLimit.init": "true", &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
"git-widget-placeholder": "main", &quot;git-widget-placeholder&quot;: &quot;main&quot;,
"go.import.settings.migrated": "true", &quot;go.import.settings.migrated&quot;: &quot;true&quot;,
"last_opened_file_path": "C:/Users/wddsh/Documents/IdeaProjects/WddSuperAgent/agent-common/SplitProject/监管平台-Doris-k8s", &quot;last_opened_file_path&quot;: &quot;C:/Users/wddsh/Documents/IdeaProjects/WddSuperAgent/agent-common/SplitProject/监管平台-Doris-k8s&quot;,
"node.js.detected.package.eslint": "true", &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
"node.js.detected.package.tslint": "true", &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
"node.js.selected.package.eslint": "(autodetect)", &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
"node.js.selected.package.tslint": "(autodetect)", &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
"nodejs_package_manager_path": "npm", &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
"settings.editor.selected.configurable": "Errors", &quot;settings.editor.selected.configurable&quot;: &quot;Errors&quot;,
"vue.rearranger.settings.migration": "true" &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}]]></component> }</component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS"> <key name="CopyFile.RECENT_KEYS">
<recent name="C:\Users\wddsh\Documents\IdeaProjects\WddSuperAgent\agent-common\SplitProject\监管平台-Doris-k8s" /> <recent name="C:\Users\wddsh\Documents\IdeaProjects\WddSuperAgent\agent-common\SplitProject\监管平台-Doris-k8s" />
@@ -107,7 +104,7 @@
<recent name="C:\Users\wddsh\Documents\IdeaProjects\WddSuperAgent\agent-common\real_project\pre_pro" /> <recent name="C:\Users\wddsh\Documents\IdeaProjects\WddSuperAgent\agent-common\real_project\pre_pro" />
</key> </key>
</component> </component>
<component name="RunManager" selected="Go Test.DCU-CMII-35.80"> <component name="RunManager" selected="PowerShell.one-build-and-upload.ps1">
<configuration name="one-build-and-upload.ps1 (1)" type="PowerShellRunType" factoryName="PowerShell" temporary="true" scriptUrl="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" executablePath="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe"> <configuration name="one-build-and-upload.ps1 (1)" type="PowerShellRunType" factoryName="PowerShell" temporary="true" scriptUrl="$PROJECT_DIR$/agent-wdd/a_run/one-build-and-upload.ps1" executablePath="$PROJECT_DIR$/../../../../../Windows/System32/WindowsPowerShell/v1.0/powershell.exe">
<envs /> <envs />
<method v="2" /> <method v="2" />
@@ -130,6 +127,7 @@
</configuration> </configuration>
<list> <list>
<item itemvalue="Go Build.agent-wdd运行" /> <item itemvalue="Go Build.agent-wdd运行" />
<item itemvalue="Go Test.Middle镜像-35.70" />
<item itemvalue="Go Test.DCU-中间件-35.80" /> <item itemvalue="Go Test.DCU-中间件-35.80" />
<item itemvalue="Go Test.DCU-RKE-35.80" /> <item itemvalue="Go Test.DCU-RKE-35.80" />
<item itemvalue="Go Test.DCU-CMII-35.80" /> <item itemvalue="Go Test.DCU-CMII-35.80" />
@@ -142,6 +140,8 @@
</list> </list>
<recent_temporary> <recent_temporary>
<list> <list>
<item itemvalue="PowerShell.one-build-and-upload.ps1 (1)" />
<item itemvalue="PowerShell.one-build-and-upload.ps1" />
<item itemvalue="PowerShell.one-build-and-upload.ps1" /> <item itemvalue="PowerShell.one-build-and-upload.ps1" />
</list> </list>
</recent_temporary> </recent_temporary>
@@ -243,7 +243,10 @@
<workItem from="1768785685963" duration="596000" /> <workItem from="1768785685963" duration="596000" />
<workItem from="1768788634424" duration="1474000" /> <workItem from="1768788634424" duration="1474000" />
<workItem from="1768790433453" duration="1946000" /> <workItem from="1768790433453" duration="1946000" />
<workItem from="1768794675745" duration="2424000" /> <workItem from="1768794675745" duration="2661000" />
<workItem from="1768874379183" duration="75000" />
<workItem from="1768876032901" duration="8000" />
<workItem from="1768879526468" duration="182000" />
</task> </task>
<task id="LOCAL-00001" summary="git"> <task id="LOCAL-00001" summary="git">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -285,19 +288,39 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1768788677741</updated> <updated>1768788677741</updated>
</task> </task>
<option name="localTasksCounter" value="6" /> <task id="LOCAL-00006" summary="优化镜像同步,新增雄安集团监管平台项目">
<option name="closed" value="true" />
<created>1768811251589</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1768811251589</updated>
</task>
<option name="localTasksCounter" value="7" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" /> <option name="version" value="3" />
</component> </component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="git" /> <MESSAGE value="git" />
<MESSAGE value="uas-agent yaml" /> <MESSAGE value="uas-agent yaml" />
<MESSAGE value="新增xa空能院项目新增大量的更新内容" /> <MESSAGE value="新增xa空能院项目新增大量的更新内容" />
<MESSAGE value="升级EMQX的版本为5.8.8" /> <MESSAGE value="升级EMQX的版本为5.8.8" />
<MESSAGE value="优化镜像同步的内容" /> <MESSAGE value="优化镜像同步的内容" />
<option name="LAST_COMMIT_MESSAGE" value="优化镜像同步的内容" /> <MESSAGE value="优化镜像同步,新增雄安集团监管平台项目" />
<option name="LAST_COMMIT_MESSAGE" value="优化镜像同步,新增雄安集团监管平台项目" />
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState"> <component name="XSLT-Support.FileAssociations.UIState">
<expand /> <expand />

View File

@@ -2,6 +2,26 @@ package c_middle
const CmiiEmqxTemplate = ` 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 apiVersion: v1
kind: ServiceAccount kind: ServiceAccount
metadata: metadata:
@@ -9,155 +29,336 @@ metadata:
namespace: {{ .Namespace }} namespace: {{ .Namespace }}
--- ---
apiVersion: v1 # ============== Role - RBAC ==============
kind: ConfigMap apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: metadata:
name: helm-emqxs-env name: helm-emqxs
namespace: {{ .Namespace }} namespace: {{ .Namespace }}
labels: rules:
cmii.type: middleware - apiGroups: [""]
cmii.app: helm-emqxs resources:
cmii.emqx.architecture: cluster - endpoints
helm.sh/chart: emqx-1.1.0 - pods
app.kubernetes.io/managed-by: octopus-control verbs:
app.kubernetes.io/version: {{ .TagVersion }} - get
data: - watch
# 集群相关 - list
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 }}"
--- ---
# ============== 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 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: helm-emqxs-init-script name: emqx-bootstrap-config
namespace: {{ .Namespace }} namespace: {{ .Namespace }}
labels: labels:
cmii.type: middleware cmii.type: middleware
cmii.app: helm-emqxs cmii.app: helm-emqxs
data: 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 set -e
DASHBOARD_USER="admin" DASHBOARD_USER="admin"
DASHBOARD_PASS="{{ .EmqxPassword }}" DASHBOARD_PASS="${DASHBOARD_ADMIN_PASSWORD}"
MQTT_USER="admin"
MQTT_PASS="{{ .EmqxPassword }}"
# 等待 EMQX 本地 API 就绪
EMQX_API="http://localhost:18083/api/v5" EMQX_API="http://localhost:18083/api/v5"
echo "等待 EMQX API 就绪..." ACL_FILE="/bootstrap/bootstrap_acl.json"
for i in $(seq 1 120); do
# 辅助函数:打印带时间戳的日志
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 if curl -s -f -m 5 "${EMQX_API}/status" > /dev/null 2>&1; then
echo "EMQX API 已就绪" log "✓ EMQX API 已就绪"
break break
fi fi
echo "等待中... ($i/120)" if [ $i -eq 60 ]; then
sleep 5 log "✗ EMQX API 启动超时"
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" \
-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 exit 1
fi fi
echo "Token 获取成功" sleep 5
# 创建内置数据库认证器(使用 listeners 作用域) done
echo "检查并创建内置数据库认证器..."
# 为 tcp:default listener 添加认证器 # ----------------------------------------------------------------
echo "为 listener tcp:default 配置认证器..." # 2. 修改 Dashboard 密码
curl -s -X POST "${EMQX_API}/authentication/tcp:default" \ # ----------------------------------------------------------------
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 "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{ -d "{\"old_pwd\":\"public\",\"new_pwd\":\"${DASHBOARD_PASS}\"}"
"mechanism": "password_based", log " ✓ Dashboard 密码已更新"
"backend": "built_in_database", else
"user_id_type": "username", log " 无法使用默认密码登录,跳过更新(可能已修改)"
"password_hash_algorithm": { fi
"name": "sha256",
"salt_position": "suffix" # ----------------------------------------------------------------
} # 3. 导入 ACL 规则
}' 2>/dev/null || echo "tcp:default 认证器可能已存在" # ----------------------------------------------------------------
# 为 ws:default listener 添加认证器 echo "[3/3] 导入ACL规则..."
echo "为 listener ws:default 配置认证器..."
curl -s -X POST "${EMQX_API}/authentication/ws:default" \ # 重新登录获取最新 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 + rulesusername 是 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 "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{ -d "$REQ_BODY")
"mechanism": "password_based",
"backend": "built_in_database", if [ "$http_code" = "204" ]; then
"user_id_type": "username", echo " ✓ PUT 更新成功"
"password_hash_algorithm": { elif [ "$http_code" = "404" ]; then
"name": "sha256", # 2) 不存在则 POST 创建
"salt_position": "suffix" http_code2=$(curl -sS -o /tmp/emqx_acl_resp.json -w '%{http_code}' \
} -X POST "${EMQX_API}/authorization/sources/built_in_database/rules/users" \
}' 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 "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "{\"user_id\":\"${MQTT_USER}\",\"password\":\"${MQTT_PASS}\",\"is_superuser\":true}" \ -d "$REQ_BODY")
2>/dev/null || echo "用户可能已存在,尝试更新..."
# 尝试更新密码 if [ "$http_code2" = "204" ]; then
curl -s -X PUT "${EMQX_API}/authentication/password_based:built_in_database/users/${MQTT_USER}?listener_id=tcp:default" \ 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}" \ -H "Authorization: Bearer ${TOKEN}" \
-H 'Content-Type: application/json' \ "${EMQX_API}/authorization/sources/built_in_database/rules/users/${USERNAME}")
-d "{\"password\":\"${MQTT_PASS}\",\"is_superuser\":true}" \
2>/dev/null || true if [ "$verify_code" = "200" ]; then
echo "MQTT 用户创建/更新完成" echo " ✓ 验证成功:$(cat /tmp/emqx_acl_verify.json | jq -c '.')"
# 创建授权规则 else
echo "配置授权规则..." echo " ✗ 验证失败 (HTTP ${verify_code})$(cat /tmp/emqx_acl_verify.json 2>/dev/null || true)"
# 创建内置数据库授权源 exit 1
curl -s -X POST "${EMQX_API}/authorization/sources" \ fi
-H "Authorization: Bearer ${TOKEN}" \ done
-H 'Content-Type: application/json' \
-d '{ echo " ✓ ACL 规则导入完成"
"type": "built_in_database", else
"enable": true echo " 未找到 ACL 文件"
}' 2>/dev/null || echo "授权源可能已存在" fi
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}"
--- ---
# ============== StatefulSet ==============
apiVersion: apps/v1 apiVersion: apps/v1
kind: StatefulSet kind: StatefulSet
metadata: metadata:
@@ -173,6 +374,7 @@ metadata:
spec: spec:
replicas: 1 replicas: 1
serviceName: helm-emqxs-headless serviceName: helm-emqxs-headless
podManagementPolicy: Parallel
updateStrategy: updateStrategy:
type: RollingUpdate type: RollingUpdate
selector: selector:
@@ -180,6 +382,7 @@ spec:
cmii.type: middleware cmii.type: middleware
cmii.app: helm-emqxs cmii.app: helm-emqxs
cmii.emqx.architecture: cluster cmii.emqx.architecture: cluster
template: template:
metadata: metadata:
labels: labels:
@@ -203,106 +406,246 @@ spec:
{{- else }} {{- else }}
- {{ .Namespace }} - {{ .Namespace }}
{{- end }} {{- end }}
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: cmii.app
operator: In
values:
- helm-emqxs
topologyKey: kubernetes.io/hostname
imagePullSecrets: imagePullSecrets:
- name: harborsecret - name: harborsecret
serviceAccountName: helm-emqxs 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: containers:
- name: helm-emqxs # 主容器 - EMQX
- name: emqx
# 动态选择 emqx 镜像
{{- if .HarborPort }} {{- if .HarborPort }}
image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/emqx:5.8.8 image: {{ .HarborIPOrCustomImagePrefix }}:{{ .HarborPort }}/cmii/emqx:5.8.8
{{- else }} {{- else }}
image: {{ .HarborIPOrCustomImagePrefix }}emqx:5.8.8 image: {{ .HarborIPOrCustomImagePrefix }}emqx:5.8.8
{{- end }} {{- end }}
imagePullPolicy: Always imagePullPolicy: IfNotPresent
env:
# Pod信息
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: EMQX_DATA_DIR
value: "/opt/emqx/data"
ports: ports:
- name: mqtt - name: mqtt
containerPort: 1883 containerPort: 1883
- name: mqttssl - name: mqttssl
containerPort: 8883 containerPort: 8883
- name: mgmt
containerPort: 8081
- name: ws - name: ws
containerPort: 8083 containerPort: 8083
- name: wss
containerPort: 8084
- name: dashboard - name: dashboard
containerPort: 18083 containerPort: 18083
- name: ekka - name: ekka
containerPort: 4370 containerPort: 4370
envFrom:
- configMapRef: resources:
name: helm-emqxs-env requests:
# 添加生命周期钩子 cpu: "500m"
lifecycle: memory: "512Mi"
postStart: limits:
exec: cpu: "2000m"
command: memory: "2Gi"
- /bin/sh
- -c
- |
# 后台执行初始化脚本,避免阻塞容器启动
nohup /bin/sh /scripts/init-mqtt-user.sh > /tmp/init.log 2>&1 &
# 添加健康检查,确保 initContainer 执行时 API 已就绪
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /status path: /status
port: 18083 port: 18083
initialDelaySeconds: 60 initialDelaySeconds: 60
periodSeconds: 30 periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe: readinessProbe:
httpGet:
path: /status
port: 18083
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
httpGet: httpGet:
path: /status path: /status
port: 18083 port: 18083
initialDelaySeconds: 10 initialDelaySeconds: 10
periodSeconds: 5 periodSeconds: 5
resources: {} failureThreshold: 30
volumeMounts: volumeMounts:
# 5.x 默认 data 目录,包含所有持久化数据
- name: emqx-data - name: emqx-data
mountPath: "/opt/emqx/data" mountPath: /opt/emqx/data
readOnly: false # 使用 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 - name: init-script
mountPath: /scripts mountPath: /scripts
- name: bootstrap-users
mountPath: /bootstrap
volumes: 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 - name: emqx-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: helm-emqxs claimName: helm-emqxs
- name: init-script
configMap:
name: helm-emqxs-init-script
defaultMode: 0755
--- ---
kind: Role # ============== Service - Headless ==============
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: v1
kind: Service
metadata: metadata:
name: helm-emqxs name: helm-emqxs-headless
namespace: {{ .Namespace }} namespace: {{ .Namespace }}
rules: labels:
- apiGroups: [""] cmii.type: middleware
resources: cmii.app: helm-emqxs
- endpoints cmii.emqx.architecture: cluster
verbs: helm.sh/chart: emqx-1.1.0
- get app.kubernetes.io/managed-by: octopus-control
- watch app.kubernetes.io/version: {{ .TagVersion }}
- list spec:
type: ClusterIP
--- clusterIP: None
kind: RoleBinding publishNotReadyAddresses: true
apiVersion: rbac.authorization.k8s.io/v1 selector:
metadata: cmii.type: middleware
name: helm-emqxs cmii.app: helm-emqxs
namespace: {{ .Namespace }} cmii.emqx.architecture: cluster
subjects: ports:
- kind: ServiceAccount - name: mqtt
name: helm-emqxs port: 1883
namespace: {{ .Namespace }} targetPort: 1883
roleRef: - name: mqttssl
kind: Role port: 8883
name: helm-emqxs targetPort: 8883
apiGroup: rbac.authorization.k8s.io - name: ws
port: 8083
targetPort: 8083
- name: dashboard
port: 18083
targetPort: 18083
- name: ekka
port: 4370
targetPort: 4370
--- ---
# ============== Service - NodePort ==============
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
@@ -322,66 +665,19 @@ spec:
cmii.app: helm-emqxs cmii.app: helm-emqxs
cmii.emqx.architecture: cluster cmii.emqx.architecture: cluster
ports: 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 - name: mqtt
port: 1883 port: 1883
protocol: TCP
targetPort: 1883 targetPort: 1883
- name: mqttssl nodePort: {{ .EmqxNodePort }}
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 - name: dashboard
port: 18083 port: 18083
protocol: TCP
targetPort: 18083 targetPort: 18083
- name: ekka nodePort: {{ .EmqxDashboardNodePort }}
port: 4370 - name: ws
protocol: TCP port: 8083
targetPort: 4370 targetPort: 8083
nodePort: {{ .EmqxWebSocketNodePort }}
- name: mqttssl
port: 8883
targetPort: 8883
` `

View File

@@ -186,11 +186,11 @@ var MiddlewareAmd64 = []string{
"harbor.cdcyy.com.cn/cmii/nfs-subdir-external-provisioner:v4.0.2", "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-linux",
"docker.m.daocloud.io/jerrychina2020/rke-tools:v0.175", "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.be-ubuntu:2.1.6",
"harbor.cdcyy.com.cn/cmii/doris.fe-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/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", "harbor.cdcyy.com.cn/cmii/nginx:1.27.0",
} }