欢迎光临
我们一直在努力

1核2G服务器也能跑!Docker下ThingsBoard+EMQX超低配部署实战(附避坑指南)

在1核2G的“小钢炮”服务器上,搭建ThingsBoard+EMQX物联网平台实战

手里只有一台1核2G的入门级云服务器,却想搭建一个完整的物联网平台来测试自己的智能硬件项目?这听起来像是让一辆小排量家用车去跑拉力赛,但事实证明,只要调校得当,它不仅能跑,还能跑得相当稳健。今天,我们就来挑战这个极限,用Docker在1核2G的服务器上,部署ThingsBoard物联网平台和EMQX消息中间件。这不是一篇照搬官方文档的教程,而是融合了多次“爆内存”教训后,总结出的资源压榨方案和避坑指南。你会发现,限制往往能激发出最精巧的解决方案。

1. 战前准备:理解我们的“战场”与武器

在开始敲命令之前,我们必须清醒地认识手中的资源。1核2G的云服务器,意味着什么?2GB内存,除去操作系统(约200-300MB)和必要的系统进程,留给我们的“自由内存”可能只有1.5GB左右。而我们要部署的ThingsBoard、PostgreSQL数据库、EMQX以及tb-gateway,每一个都不是省油的灯。

为什么不用ThingsBoard自带的数据库? 官方Docker镜像确实提供了All-in-One的选项,内部集成了PostgreSQL。但在极限资源环境下,这常常是第一个“坑”。集成环境虽然方便,但进程间资源隔离性差,一个组件异常可能拖垮整个容器。更重要的是,在资源紧张时,我们需要更精细的控制权——比如为数据库单独设置内存限制,或者方便地备份、迁移数据。因此,我们的核心策略是:解耦与隔离。为每个核心服务(数据库、应用、消息中间件)分配独立的容器,通过Docker的资源限制功能进行管控。

注意:本文所有操作均基于Linux服务器(如CentOS 7/8或Ubuntu 20.04+),并假设你已具备基础的Linux命令和Docker使用知识。请确保你的云服务器安全组已开放后续需要用到的端口。

首先,检查并确保Docker已正确安装。如果尚未安装,可以使用以下命令快速安装:

# 以CentOS为例,安装Docker
sudo yum install -y yum-utils
sudo yum-config-manager –add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker

2. 基石先行:部署轻量级PostgreSQL数据库

数据库是平台的基石,必须优先确保其稳定。我们不使用ThingsBoard镜像内置的数据库,而是独立部署一个PostgreSQL容器,并对其进行内存限制。

创建数据持久化目录:为了避免容器重启后数据丢失,我们首先创建宿主机上的数据目录。

mkdir -p /opt/iot-stack/postgres/data

启动PostgreSQL容器:这里的关键是使用 –memory 和 –memory-swap 参数来限制容器使用的最大内存。

docker run -d \\
–name postgres-for-tb \\
–restart=unless-stopped \\
–memory=512m \\
–memory-swap=512m \\
-e POSTGRES_PASSWORD=your_strong_password \\
-e POSTGRES_DB=thingsboard \\
-p 5432:5432 \\
-v /opt/iot-stack/postgres/data:/var/lib/postgresql/data \\
postgres:13-alpine

命令解析:

  • –memory=512m:限制该容器最多使用512MB的物理内存。
  • –memory-swap=512m:将内存交换(Swap)总量也限制为512MB,这实际上意味着禁止使用Swap。在内存极度紧张的环境下,频繁的Swap交换会导致I/O瓶颈,系统卡死。我们宁可让容器因内存不足(OOM)被终止,也不希望整个服务器失去响应。
  • postgres:13-alpine:我们选择了基于Alpine Linux的镜像版本。alpine镜像体积通常只有标准镜像的几分之一,非常适合资源受限的环境。
  • -v …:/var/lib/postgresql/data:将容器内的数据目录挂载到宿主机,实现数据持久化。

启动后,你可以进入容器验证数据库是否正常运行:

docker exec -it postgres-for-tb psql -U postgres -d thingsboard

如果成功进入psql命令行,输入 \\l 查看数据库列表,应该能看到名为 thingsboard 的数据库。退出请使用 \\q。

3. 核心部署:优化ThingsBoard容器配置

ThingsBoard是资源消耗的大户。我们将通过环境变量和Docker Compose来精细控制其行为。

首先,安装Docker Compose。虽然我们可以用多个docker run命令,但Compose能更好地管理多容器应用的依赖关系和配置。

# 下载Docker Compose二进制文件(请检查官网获取最新版本号)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose –version # 验证安装

创建专属的Docker Compose文件:在/opt/iot-stack目录下创建docker-compose.yml。

version: '3.8'
services:
thingsboard:
image: thingsboard/tb-postgres:3.6.1 # 建议使用稳定版本,而非latest
container_name: thingsboard-app
restart: unless-stopped
mem_limit: 800m # 限制ThingsBoard容器内存
ports:
– "8080:9090" # Web UI
– "1884:1883" # MQTT端口,映射到非标准的1884,避免与后续EMQX冲突
– "7070:7070" # HTTP API
– "5683-5688:5683-5688/udp" # CoAP协议端口
environment:
– TB_QUEUE_TYPE=in-memory # 使用内存队列,降低复杂度。生产环境可考虑kafka或rabbitmq。
– SPRING_DATASOURCE_URL=jdbc:postgresql://你的服务器IP:5432/thingsboard
– SPRING_DATASOURCE_USERNAME=postgres
– SPRING_DATASOURCE_PASSWORD=your_strong_password
– JAVA_OPTS=-Xms256m -Xmx512m -XX:MaxRAM=800m # 关键!直接控制JVM堆内存
depends_on:
– postgres-for-tb
networks:
– iot-network

postgres-for-tb:
image: postgres:13-alpine
container_name: postgres-for-tb
restart: unless-stopped
mem_limit: 512m
environment:
– POSTGRES_PASSWORD=your_strong_password
– POSTGRES_DB=thingsboard
volumes:
– ./postgres/data:/var/lib/postgresql/data
networks:
– iot-network

networks:
iot-network:
driver: bridge

核心优化点解析:

  • 端口映射策略:将ThingsBoard的MQTT端口(容器内1883)映射到宿主机的1884。这是为后续部署EMQX(默认使用1883)做的关键铺垫,避免了端口冲突。
  • JVM内存调优:JAVA_OPTS环境变量是重中之重。
    • -Xms256m:设置JVM初始堆内存为256MB。
    • -Xmx512m:设置JVM最大堆内存为512MB。这确保了ThingsBoard的Java进程不会无节制地吞噬内存。
    • -XX:MaxRAM=800m:告知JVM它可用的最大RAM约为800MB,帮助其更好地规划内存使用。
  • 网络隔离:创建一个自定义的Docker网络iot-network,让ThingsBoard和Postgres在独立的网络空间中通信,更安全,也避免了与宿主机或其他服务的网络干扰。
  • 启动与验证:

    cd /opt/iot-stack
    docker-compose up -d # -d 表示后台运行
    docker-compose logs -f thingsboard-app # 查看启动日志,关注是否有数据库连接成功和启动完成的提示

    当看到日志中出现“Started ThingsBoard Server Application”之类的信息时,访问 http://你的服务器IP:8080,应该能看到ThingsBoard的登录界面。默认账号:sysadmin@thingsboard.org,密码:sysadmin。

    4. 消息中枢:部署并精简EMQX

    EMQX作为高性能的MQTT消息中间件,是我们连接海量设备的关键。同样,我们需要一个轻量化的部署方案。

    创建EMQX的持久化目录:

    mkdir -p /opt/iot-stack/emqx/data /opt/iot-stack/emqx/etc /opt/iot-stack/emqx/log

    编写EMQX的Docker启动命令或将其加入Compose。为了更灵活地控制启动参数,我们这里使用单独的docker run命令,并同样进行严格的内存限制。

    docker run -d \\
    –name emqx-broker \\
    –restart=unless-stopped \\
    –memory=400m \\
    –memory-swap=400m \\
    -p 1883:1883 \\
    -p 8083:8083 \\
    -p 8084:8084 \\
    -p 8883:8883 \\
    -p 18083:18083 \\
    -v /opt/iot-stack/emqx/etc:/opt/emqx/etc \\
    -v /opt/iot-stack/emqx/data:/opt/emqx/data \\
    -v /opt/iot-stack/emqx/log:/opt/emqx/log \\
    -e EMQX_NAME=emqx@iot \\
    -e EMQX_NODE__NAME=emqx@iot \\
    -e EMQX_LISTENERS__TCP__EXTERNAL__MAX_CONNECTIONS=1024 \\ # 限制最大连接数,防止过载
    emqx/emqx:5.0.9

    部署要点:

    • 内存限制:同样限制在400MB,并禁用Swap。
    • 端口:1883是标准的MQTT端口,供设备连接。18083是EMQX的管理控制台端口。
    • 环境变量:我们通过环境变量限制了最大TCP连接数(1024),这对于一个测试或小型生产环境已经足够,同时避免了因连接数过多导致的内存溢出。
    • 版本选择:选择了相对稳定的5.0.9版本。EMQX 5.x在资源管理和集群方面有较大改进。

    启动后,访问 http://你的服务器IP:18083,使用默认账号admin和密码public登录管理控制台。你可以在这里查看客户端连接、消息流量等信息。

    5. 连接桥梁:配置tb-gateway实现设备接入

    现在,ThingsBoard和EMQX都已就位,但它们之间是独立的。tb-gateway的作用就是作为一座桥梁,将连接到EMQX的设备数据,转发到ThingsBoard进行管理和可视化。

    启动tb-gateway容器:

    docker run -d \\
    –name tb-gateway \\
    –restart=unless-stopped \\
    –memory=256m \\
    -p 9090:9090 \\
    -v /opt/iot-stack/tb-gateway/config:/thingsboard_gateway/config \\
    -v /opt/iot-stack/tb-gateway/extensions:/thingsboard_gateway/extensions \\
    -v /opt/iot-stack/tb-gateway/logs:/thingsboard_gateway/logs \\
    thingsboard/tb-gateway

    关键步骤:配置tb-gateway。配置文件的修改是核心。进入宿主机挂载的配置目录:

    cd /opt/iot-stack/tb-gateway/config

    你需要修改两个主要文件:tb_gateway.yaml 和 mqtt.json。

    首先,配置 tb_gateway.yaml,主要设置与ThingsBoard的连接:

    thingsboard:
    host: 你的服务器IP
    port: 8080
    remoteShell: false
    remoteConfiguration: false
    security:
    accessToken: YOUR_GATEWAY_ACCESS_TOKEN # 需要在ThingsBoard中创建设备并获取
    storage:
    type: memory
    read_records_count: 100
    max_records_count: 100000
    connectors:
    – name: MQTT Broker Connector
    type: mqtt
    configuration: mqtt.json

    然后,配置 mqtt.json,设置与EMQX的连接及数据映射规则:

    {
    "broker": {
    "name": "Default EMQX Broker",
    "host": "你的服务器IP",
    "port": 1883,
    "security": {
    "type": "anonymous"
    }
    },
    "mapping": [
    {
    "topicFilter": "sensor/+/telemetry",
    "converter": {
    "type": "json",
    "deviceNameTopicExpression": "(?<=sensor/)[^/]+(?=/telemetry)",
    "deviceTypeTopicExpression": "Thermometer",
    "timeout": 60000,
    "attributes": [
    {
    "type": "string",
    "key": "model",
    "value": "default"
    }
    ],
    "timeseries": [
    {
    "type": "double",
    "key": "temperature",
    "value": "${temperature}"
    },
    {
    "type": "double",
    "key": "humidity",
    "value": "${humidity}"
    }
    ]
    }
    }
    ]
    }

    这个配置示例表示:tb-gateway会订阅EMQX上匹配 sensor/+/telemetry 主题的消息(例如sensor/device001/telemetry),并将消息中的temperature和humidity字段作为时序数据,转发给ThingsBoard。设备名将从主题中提取(device001)。

    最后,重启tb-gateway容器使配置生效:

    docker restart tb-gateway
    docker logs -f tb-gateway # 查看日志,确认连接成功

    6. 压力测试与监控:确保系统稳定运行

    部署完成只是第一步,在低配环境下,持续的监控和压力测试至关重要。

    使用Docker内置命令监控资源:

    docker stats –no-stream # 查看各容器实时资源占用(CPU、内存、网络IO)

    定期运行此命令,观察在模拟设备连接和数据上报时,各个容器的内存使用是否接近我们设定的上限。

    模拟MQTT设备进行压力测试:你可以使用 mosquitto_pub 命令行工具或编写简单的Python脚本,模拟设备向EMQX发布消息。

    # 安装mosquitto客户端(在另一台机器或本机)
    # Ubuntu: sudo apt install mosquitto-clients
    # CentOS: sudo yum install mosquitto

    # 模拟设备发布数据到EMQX
    mosquitto_pub -h 你的服务器IP -p 1883 -t "sensor/testDevice/telemetry" -m '{"temperature": 25.5, "humidity": 60}'

    在ThingsBoard中验证数据:登录ThingsBoard,在“设备”页面应该能看到名为testDevice的设备,并在其最新遥测数据中看到上传的温度和湿度值。

    设置内存告警:虽然我们限制了容器内存,但最坏的情况是某个容器发生内存泄漏,不断触发OOM Killer。可以在宿主机上配置简单的监控脚本,或者使用云服务商自带的监控告警功能,当系统内存使用率持续超过85%时发送通知。

    整个部署流程走下来,你会发现,在1核2G的服务器上运行这样一个物联网平台栈,虽然捉襟见肘,但通过严格的资源限制、选择轻量级镜像、优化应用配置(尤其是JVM)、以及合理的端口与网络规划,是完全可行的。这套方案特别适合个人开发者进行原型验证、学习测试,或者运行一个设备数量不多(几十到上百)的小型项目。当你的项目真正需要走向生产环境时,首要任务可能就是升级服务器配置了。不过,这段在资源极限下的部署经历,会让你对每个组件的资源消耗有更深刻的理解,这本身就是一笔宝贵的财富。

    赞(0)
    未经允许不得转载:171主机测评 » 1核2G服务器也能跑!Docker下ThingsBoard+EMQX超低配部署实战(附避坑指南)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址