emqx的docker部署

基本部署就不说了,只是想说一下部署时添加用户密码。

管理用户有多种方式,关系数据库就很简单,按照配置就好。这里说一下使用内置数据库。需要开启内置数据库。然后使用一个py将用户密码初始化导入。减少部署维护。

XML 复制代码
version: '3.8'

services:
  emqx:
    image: emqx/emqx:5.7.0  # 固定版本,避免自动更新
    container_name: emqx
    restart: always
    ports:
      - "1883:1883"   # MQTT TCP
      - "8083:8083"   # MQTT WebSocket
      - "8883:8883"   # MQTT SSL
      - "8084:8084"   # MQTT WebSocket SSL
      - "18083:18083" # Dashboard
    volumes:
      - /opt/emqx/data:/opt/emqx/data
      - /opt/emqx/log:/opt/emqx/log
      - /opt/emqx/conf:/opt/emqx/etc/emqx.conf.d  # 自定义配置挂载
    environment:
      # 核心:启用内置数据库认证
      - EMQX_AUTHENTICATION__1__MECHANISM=password_based
      - EMQX_AUTHENTICATION__1__BACKEND=built_in_database
      - EMQX_AUTHENTICATION__1__ENABLE=true
      # 默认管理员账户(Dashboard 登录)
      - EMQX_DEFAULT_USER__USERNAME=admin
      - EMQX_DEFAULT_USER__PASSWORD=admin123  # 替换为你的管理员密码
      # 可选:调整最大连接数、日志级别
      - EMQX_LISTENER__TCP__DEFAULT__MAX_CONNECTIONS=1024000
      - EMQX_LOG__LEVEL=info
    networks:
      - emqx-network

networks:
  emqx-network:
    driver: bridge

在部署时简化配置,可以用另外一个程序直接导入用户名密码。其实就是直接调用emqx提供的api。

python 复制代码
#!/usr/bin/env python3
"""
EMQX用户批量导入工具 - 重试退出版
登录失败重试3次,还不成功就异常退出
"""

import csv
import time
import sys
import os
import requests

# ============ 配置 ============
EMQX_HOST = os.getenv('EMQX_HOST', 'emqx')
EMQX_PORT = os.getenv('EMQX_PORT', '18083')
BASE_URL = f"http://{EMQX_HOST}:{EMQX_PORT}/api/v5"

LOGIN_URL = f"{BASE_URL}/login"
USER_API = f"{BASE_URL}/authentication/password_based%3Abuilt_in_database/users"

ADMIN_USER = os.getenv('ADMIN_USER', 'admin')
ADMIN_PASS = os.getenv('ADMIN_PASS', 'mq_Admin@2025!Jetlinks#124')

CSV_FILE = os.getenv('CSV_FILE', '/app/users.csv')
# =============================

def fatal_error(message):
    """致命错误,直接退出"""
    print(f"💥 {message}")
    sys.exit(1)

def login_with_retry():
    """登录重试3次,失败就退出"""
    print("🔑 登录EMQX...")
    
    for attempt in range(1, 4):  # 重试3次
        print(f"  尝试 {attempt}/3...")
        
        try:
            response = requests.post(
                LOGIN_URL,
                json={"username": ADMIN_USER, "password": ADMIN_PASS},
                headers={"Content-Type": "application/json"},
                timeout=10,
                verify=False
            )
            
            if response.status_code == 200:
                token = response.json().get("token")
                if token:
                    print("✅ 登录成功")
                    return token
                else:
                    print("❌ 响应中没有Token")
            else:
                print(f"❌ 登录失败: HTTP {response.status_code}")
            
        except Exception as e:
            print(f"❌ 连接异常: {e}")
        
        # 如果不是最后一次尝试,等待5秒
        if attempt < 3:
            print("⏳ 等待5秒后重试...")
            time.sleep(5)
    
    # 3次都失败,退出
    fatal_error("登录失败,等待容器重启")

def import_users():
    """主导入函数"""
    print("=" * 60)
    print("EMQX用户批量导入")
    print("=" * 60)
    print(f"服务器: {EMQX_HOST}:{EMQX_PORT}")
    print(f"管理员: {ADMIN_USER}")
    print("=" * 60)
    
    # 1. 登录(失败就退出)
    token = login_with_retry()
    
    # 2. 读取CSV
    users = []
    try:
        with open(CSV_FILE, 'r') as f:
            
            for line in f:
                line = line.strip()
                if not line or line.startswith('#'):
                    continue
                if not is_header:
                        # 检查是否包含表头关键词
                        username_headers = {'用户', '用户名', 'user', 'username', 'userid'}
                        password_headers = {'密码', 'password'}
                        superuser_headers = {'超级用户', 'is_superuser', 'superuser', '管理员'}
                        
                        parts = [p.strip().lower() for p in line.split(',')]
                        
                        # 检查是否同时包含用户名和密码表头
                        has_username_header = any(h in parts for h in username_headers)
                        has_password_header = any(h in parts for h in password_headers)
                        
                        if has_username_header and has_password_header:
                            # 这是表头行,跳过不处理
                            print(f"📋 检测到表头: {line}")
                            is_header = True
                            
                            # 确定各字段的位置
                            for i, header in enumerate(parts):
                                if header in username_headers:
                                    username_idx = i
                                elif header in password_headers:
                                    password_idx = i
                                elif header in superuser_headers:
                                    superuser_idx = i
                            continue  # 跳过表头行,继续读取下一行
                parts = line.split(',')
                if len(parts) < 2:
                    continue
                
                username = parts[0].strip()
                password = parts[1].strip()
                
                if not username or not password:
                    continue
                
                is_super = False
                if len(parts) > 2:
                    flag = parts[2].strip().lower()
                    is_super = flag in ['true', '1', 'yes', 'y']
                
                users.append({
                    'user_id': username,
                    'password': password,
                    'is_superuser': is_super
                })
        
        if not users:
            print("❌ CSV中没有用户")
            return True  # 没有用户不算失败
            
        print(f"📄 读取到 {len(users)} 个用户")
        
    except FileNotFoundError:
        fatal_error(f"找不到CSV文件: {CSV_FILE}")
    except Exception as e:
        fatal_error(f"读取CSV失败: {e}")
    
    # 3. 导入用户
    print(f"\n🚀 开始导入...")
    
    success = 0
    failed = 0
    
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {token}"
    }
    
    for i, user in enumerate(users, 1):
        username = user['user_id']
        print(f"[{i:3}/{len(users)}] {username:20}", end="", flush=True)
        
        try:
            response = requests.post(
                USER_API,
                json=user,
                headers=headers,
                timeout=30,
                verify=False
            )
            
            if response.status_code in [200, 201, 409]:
                print(" ✅ 成功")
                success += 1
            else:
                print(f" ❌ HTTP {response.status_code}")
                failed += 1
                # 创建用户失败不退出,继续下一个
                
        except Exception as e:
            print(f" ❌ 错误: {str(e)[:30]}")
            failed += 1
            # 网络错误也不退出,继续下一个
        
        if i < len(users):
            time.sleep(0.3)
    
    # 4. 显示结果
    print(f"\n" + "=" * 60)
    print("📊 导入完成!")
    print(f"  总计: {len(users)}")
    print(f"  成功: {success} ✅")
    print(f"  失败: {failed} ❌")
    
    if success > 0:
        print(f"\n💡 验证: http://{EMQX_HOST}:{EMQX_PORT}")
    
    return failed == 0

if __name__ == "__main__":
    try:
        success = import_users()
        if success:
            print("\n🎉 导入成功!")
            sys.exit(0)
        else:
            print("\n⚠️  部分用户导入失败")
            sys.exit(1)  # 有失败,退出码1,触发容器重启
    except KeyboardInterrupt:
        print("\n❌ 用户中断")
        sys.exit(130)
    except SystemExit as e:
        # 重新抛出SystemExit
        raise
    except Exception as e:
        print(f"\n💥 未处理异常: {e}")
        sys.exit(1)  # 异常退出,触发容器重启

py生成一个镜像,部署时自动执行一次,就将user.csv文件中用户密码导入了。

相关推荐
9ilk1 小时前
【Linux】--- 多路转接select / poll / epoll
linux·运维·网络
宇钶宇夕1 小时前
CODESYS V3.5 SP9 Patch 4详细安装说明(关闭杀毒软件)
运维·网络·自动化
IT利刃出鞘1 小时前
Nginx--变量的使用
运维·nginx
云和数据.ChenGuang1 小时前
运维工程师软件之httpd`(Apache HTTP Server)
运维·http·apache
mixboot2 小时前
docker 国内镜像源
docker·镜像源
谷粒.2 小时前
云原生时代的测试策略:Kubernetes环境下的测试实践
运维·网络·云原生·容器·kubernetes
边疆.2 小时前
【Linux】文件系统
linux·运维·服务器·磁盘·文件系统·软硬链接
DevangLic2 小时前
【win的实用官方工具集合】解决:该设备正在使用中,请关闭所有。。。
运维·学习·工具
java_logo2 小时前
Milvus GUI ATTU Docker 容器化部署指南
运维·数据库·docker·容器·eureka·milvus