Ubuntu系统部署 ThingsBoard 4.3.x
本文用 Docker Compose 在 Ubuntu 上部署 ThingsBoard CE 4.3.1.8。每种方式都给出完整可复制的 docker-compose.yml 与初始化命令;Compose 内容已对照 官方 Docker 安装文档(镜像 thingsboard/tb-node:4.3.1.8、postgres:18、bitnamilegacy/kafka:4.0)整理。
官方原生 deb 安装(非 Docker)见:Installing ThingsBoard CE on Ubuntu。本文聚焦 Docker,上手更快、回滚更简单。
0. 推荐环境
操作系统(请按此选型)
| 优先级 | 系统 | 说明 |
|---|---|---|
| 推荐 | Ubuntu 24.04 LTS | 当前长期支持,官方文档明确支持,镜像与包源最省心 |
| 可用 | Ubuntu 22.04 LTS | 同样在官方 Ubuntu 安装指南支持列表中 |
| 可选 | Ubuntu 26.04 LTS | 官方已列入支持,新系统可试用 |
| 不建议 | 非 LTS / 过旧的 20.04 | 包源与 Docker 插件差异大,排错成本高 |
结论:生产与学习都优先选 Ubuntu 24.04 LTS(x86_64)。
硬件参考(官方量级)
| 场景 | CPU | 内存 | 建议组合 |
|---|---|---|---|
| 开发 / PoC | ≥ 1 核 | ≥ 4 GB | TB + PostgreSQL(内存队列) |
| 小生产 | ≥ 2 核 | ≥ 8 GB | TB + PostgreSQL + Kafka |
| 高吞吐 / 混合库 | ≥ 4 核 | ≥ 16 GB | TB + PG + Kafka + Cassandra(Cassandra 很吃内存) |
版本钉死(本文统一)
| 组件 | 版本 |
|---|---|
| ThingsBoard CE | thingsboard/tb-node:4.3.1.8 |
| PostgreSQL | postgres:18 |
| Kafka(可选) | bitnamilegacy/kafka:4.0 |
| Cassandra(可选) | cassandra:5.0 |
四种部署怎么选
| 方式 | 组成 | 适用 |
|---|---|---|
| A | TB + PostgreSQL | 默认推荐:演示、开发、中小规模 |
| B | TB + PG + Kafka | 需要更稳的队列、为扩展做准备 |
| C | TB + PG + Cassandra | 时序进 Cassandra,实体仍在 PG(高写入) |
| D | TB + PG + Kafka + Cassandra | 高吞吐生产向,资源要求最高 |
绝大多数人先跑方式 A。 Cassandra 堆内存默认很大,机器不够请用文末调小 -Xmx。
1. 安装 Docker(Ubuntu 24.04 / 22.04)
以下命令在 root 或带 sudo 的用户下执行。
sudo apt update
sudo apt install -y docker.io docker-compose-v2
sudo systemctl enable --now docker
docker --version
docker compose version把当前用户加入 docker 组(可选,免 sudo;执行后需重新登录):
sudo usermod -aG docker "$USER"若
docker compose version报错,可再试:sudo apt install -y docker-compose-plugin。下文统一使用docker compose(Compose V2),不要用旧的docker-compose。
国内拉镜像(可选)
若拉取 Docker Hub 很慢,可配置镜像加速后重启 Docker(镜像源会失效,请按当时可用源调整):
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'EOF'
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://docker.1panel.live",
"https://hub-mirror.c.163.com"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker工作目录:
mkdir -p ~/thingsboard && cd ~/thingsboard后面所有命令都在 ~/thingsboard 执行。
2. 方式 A:TB + PostgreSQL(推荐入门)
适合学习、PoC、中小流量。队列使用内置 In-Memory(Compose 中不写 TB_QUEUE_TYPE 即为默认)。
2.1 写入 compose
cd ~/thingsboard
cat > docker-compose.yml <<'EOF'
services:
postgres:
restart: always
image: "postgres:18"
ports:
- "5432"
environment:
POSTGRES_DB: thingsboard
POSTGRES_PASSWORD: postgres
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d thingsboard"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
thingsboard-ce:
restart: always
image: "thingsboard/tb-node:4.3.1.8"
ports:
- "8080:8080"
- "7070:7070"
- "1883:1883"
- "8883:8883"
- "5683-5688:5683-5688/udp"
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
environment:
TB_SERVICE_ID: tb-ce-node
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard
SPRING_DATASOURCE_PASSWORD: postgres
depends_on:
postgres:
condition: service_healthy
volumes:
postgres-data:
name: tb-postgres-data
driver: local
EOF核对要点: POSTGRES_PASSWORD 与 SPRING_DATASOURCE_PASSWORD 必须一致;postgres:18 数据目录挂载为 /var/lib/postgresql(与官方一致,不要写成旧的 /var/lib/postgresql/data)。
生产请把 postgres 密码改成强密码,并同步改两处环境变量。
2.2 初始化库表(首次必做)
带演示数据:
docker compose run --rm -e INSTALL_TB=true -e LOAD_DEMO=true thingsboard-ce只要系统数据、不要 demo:
docker compose run --rm -e INSTALL_TB=true thingsboard-ce初始化容器会自动退出。
2.3 启动
docker compose up -d
docker compose logs -f thingsboard-ce日志出现 Started ThingsboardServerApplication 后,浏览器打开:
http://服务器IP:8080默认账号(登录后立刻改密):
| 角色 | 邮箱 | 密码 | 需 LOAD_DEMO |
|---|---|---|---|
| 系统管理员 | sysadmin@thingsboard.org | sysadmin | 否 |
| 租户管理员 | tenant@thingsboard.org | tenant | 是 |
| 客户用户 | customer@thingsboard.org | customer | 是 |
常用运维:
docker compose ps
docker compose logs -f --tail 100 thingsboard-ce
docker compose down # 停止(数据卷保留)
docker compose up -d # 再启动3. 方式 B:TB + PostgreSQL + Kafka
队列改为 Kafka,更接近生产用法。Compose 对齐官方 Docker 文档中的 Kafka 方案。
cd ~/thingsboard
cat > docker-compose.yml <<'EOF'
services:
postgres:
restart: always
image: "postgres:18"
ports:
- "5432"
environment:
POSTGRES_DB: thingsboard
POSTGRES_PASSWORD: postgres
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d thingsboard"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
kafka:
restart: always
image: bitnamilegacy/kafka:4.0
ports:
- "9092:9092"
- "9093"
environment:
ALLOW_PLAINTEXT_LISTENER: "yes"
KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://:9092"
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CFG_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: "false"
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: "1"
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: "1"
KAFKA_CFG_PROCESS_ROLES: "controller,broker"
KAFKA_CFG_NODE_ID: "0"
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: "0@kafka:9093"
KAFKA_CFG_LOG_RETENTION_MS: "300000"
KAFKA_CFG_SEGMENT_BYTES: "26214400"
volumes:
- kafka-data:/bitnami
thingsboard-ce:
restart: always
image: "thingsboard/tb-node:4.3.1.8"
ports:
- "8080:8080"
- "7070:7070"
- "1883:1883"
- "8883:8883"
- "5683-5688:5683-5688/udp"
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
environment:
TB_SERVICE_ID: tb-ce-node
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard
SPRING_DATASOURCE_PASSWORD: postgres
TB_QUEUE_TYPE: kafka
TB_KAFKA_SERVERS: kafka:9092
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_started
volumes:
postgres-data:
name: tb-postgres-data
driver: local
kafka-data:
name: tb-ce-kafka-data
driver: local
EOF核对要点: TB_QUEUE_TYPE=kafka 且 TB_KAFKA_SERVERS=kafka:9092(容器服务名);Kafka 使用官方文档同款 bitnamilegacy/kafka:4.0 KRaft 单节点参数。
初始化与启动(与方式 A 相同):
docker compose run --rm -e INSTALL_TB=true -e LOAD_DEMO=true thingsboard-ce
docker compose up -d
docker compose logs -f thingsboard-ce4. 方式 C:TB + PostgreSQL + Cassandra(混合库)
实体在 PostgreSQL,时序在 Cassandra。适合高写入;内存建议 ≥ 16GB。下面默认把 Cassandra 堆调到 2G(原文 8G 容易把小机器打崩;有余量再加大)。
cd ~/thingsboard
cat > docker-compose.yml <<'EOF'
services:
postgres:
restart: always
image: "postgres:18"
ports:
- "5432"
environment:
POSTGRES_DB: thingsboard
POSTGRES_PASSWORD: postgres
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d thingsboard"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
cassandra:
restart: always
image: "cassandra:5.0"
ports:
- "9042"
environment:
CASSANDRA_CLUSTER_NAME: "ThingsBoard Cluster"
JAVA_TOOL_OPTIONS: >-
-Xms2G -Xmx2G
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=7199
-Dcom.sun.management.jmxremote.rmi.port=7199
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=127.0.0.1
volumes:
- cassandra-data:/var/lib/cassandra
healthcheck:
test: ["CMD-SHELL", "nodetool status | grep -E '^UN\\s+' || exit 1"]
interval: 30s
timeout: 15s
retries: 30
start_period: 180s
thingsboard-ce:
restart: always
image: "thingsboard/tb-node:4.3.1.8"
ports:
- "8080:8080"
- "7070:7070"
- "1883:1883"
- "8883:8883"
- "5683-5688:5683-5688/udp"
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
environment:
TB_SERVICE_ID: tb-ce-node
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard
SPRING_DATASOURCE_PASSWORD: postgres
DATABASE_TS_TYPE: cassandra
CASSANDRA_URL: cassandra:9042
depends_on:
postgres:
condition: service_healthy
cassandra:
condition: service_healthy
volumes:
postgres-data:
name: tb-postgres-data
driver: local
cassandra-data:
name: tb-cassandra-data
driver: local
EOF核对要点: DATABASE_TS_TYPE=cassandra + CASSANDRA_URL=cassandra:9042;先等 Cassandra healthcheck 通过再装库。
因 Cassandra 启动慢,建议先拉起依赖再初始化:
docker compose up -d postgres cassandra
docker compose ps
# 等到 cassandra healthy 后再执行:
docker compose run --rm -e INSTALL_TB=true -e LOAD_DEMO=true thingsboard-ce
docker compose up -d
docker compose logs -f thingsboard-ce机器内存充足时,可将 JAVA_TOOL_OPTIONS 中的 -Xms2G -Xmx2G 改为 -Xms4G -Xmx4G 或更高。
5. 方式 D:TB + PostgreSQL + Kafka + Cassandra
高吞吐组合:队列 Kafka + 时序 Cassandra。资源要求最高。
cd ~/thingsboard
cat > docker-compose.yml <<'EOF'
services:
postgres:
restart: always
image: "postgres:18"
ports:
- "5432"
environment:
POSTGRES_DB: thingsboard
POSTGRES_PASSWORD: postgres
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d thingsboard"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
kafka:
restart: always
image: bitnamilegacy/kafka:4.0
ports:
- "9092:9092"
- "9093"
environment:
ALLOW_PLAINTEXT_LISTENER: "yes"
KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://:9092"
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CFG_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: "false"
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: "1"
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: "1"
KAFKA_CFG_PROCESS_ROLES: "controller,broker"
KAFKA_CFG_NODE_ID: "0"
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: "0@kafka:9093"
KAFKA_CFG_LOG_RETENTION_MS: "300000"
KAFKA_CFG_SEGMENT_BYTES: "26214400"
volumes:
- kafka-data:/bitnami
cassandra:
restart: always
image: "cassandra:5.0"
ports:
- "9042"
environment:
CASSANDRA_CLUSTER_NAME: "ThingsBoard Cluster"
JAVA_TOOL_OPTIONS: >-
-Xms2G -Xmx2G
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=7199
-Dcom.sun.management.jmxremote.rmi.port=7199
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=127.0.0.1
volumes:
- cassandra-data:/var/lib/cassandra
healthcheck:
test: ["CMD-SHELL", "nodetool status | grep -E '^UN\\s+' || exit 1"]
interval: 30s
timeout: 15s
retries: 30
start_period: 180s
thingsboard-ce:
restart: always
image: "thingsboard/tb-node:4.3.1.8"
ports:
- "8080:8080"
- "7070:7070"
- "1883:1883"
- "8883:8883"
- "5683-5688:5683-5688/udp"
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
environment:
TB_SERVICE_ID: tb-ce-node
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard
SPRING_DATASOURCE_PASSWORD: postgres
TB_QUEUE_TYPE: kafka
TB_KAFKA_SERVERS: kafka:9092
DATABASE_TS_TYPE: cassandra
CASSANDRA_URL: cassandra:9042
depends_on:
postgres:
condition: service_healthy
kafka:
condition: service_started
cassandra:
condition: service_healthy
volumes:
postgres-data:
name: tb-postgres-data
driver: local
kafka-data:
name: tb-ce-kafka-data
driver: local
cassandra-data:
name: tb-cassandra-data
driver: local
EOFdocker compose up -d postgres kafka cassandra
docker compose ps
docker compose run --rm -e INSTALL_TB=true -e LOAD_DEMO=true thingsboard-ce
docker compose up -d
docker compose logs -f thingsboard-ce6. 端口与防火墙
按需放行(云安全组 + ufw):
| 端口 | 用途 |
|---|---|
| TCP 8080 | Web UI / REST |
| TCP 1883 / 8883 | MQTT / MQTTS |
| UDP 5683–5688 | CoAP / LwM2M |
| TCP 7070 | Edge RPC |
示例:
sudo ufw allow 8080/tcp
sudo ufw allow 1883/tcp
sudo ufw reloadPostgreSQL / Cassandra / Kafka 端口在 Compose 里多为「仅映射容器端口、不绑死宿主机公布端口」或仅内部访问;不要把 5432/9042 无防护暴露公网。
7. 可选:开启 ThingsBoard Web SSL
在方式 A 基础上增加证书挂载与 SSL 环境变量。先准备自签证书(生产请换成正式证书):
cd ~/thingsboard
mkdir -p keys
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout keys/server_key.pem \
-out keys/server.pem \
-subj "/CN=localhost"将 thingsboard-ce 服务改为类似(其余 postgres 服务保持不变):
thingsboard-ce:
restart: always
image: "thingsboard/tb-node:4.3.1.8"
ports:
- "8080:8080"
- "7070:7070"
- "1883:1883"
- "8883:8883"
- "5683-5688:5683-5688/udp"
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
environment:
TB_SERVICE_ID: tb-ce-node
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard
SPRING_DATASOURCE_PASSWORD: postgres
SSL_ENABLED: "true"
SSL_PEM_CERT: /keys/server.pem
SSL_PEM_KEY: /keys/server_key.pem
volumes:
- ./keys:/keys:ro
- thingsboard-ce-logs:/var/log/thingsboard
depends_on:
postgres:
condition: service_healthy并在 volumes: 下增加:
thingsboard-ce-logs:
name: tb-logs
driver: local改完后重新 docker compose up -d。浏览器访问 https://服务器IP:8080(自签证书需信任例外)。
8. 排错速查
| 现象 | 处理 |
|---|---|
docker compose 不存在 | 安装 docker-compose-v2 / docker-compose-plugin |
| 拉镜像失败 | 配镜像加速或代理,检查 DNS |
| 初始化失败 | 先 docker compose logs postgres;保证 PG healthy |
| Cassandra 一直 starting | 内存不够;先降 -Xmx,或换方式 A/B |
| 8080 打不开 | docker compose ps、看 TB 日志、查安全组 / ufw |
| 改密码后连不上库 | POSTGRES_PASSWORD 与 SPRING_DATASOURCE_PASSWORD 不一致 |
| 换部署方式复用旧卷 | 结构不兼容时需换 volume 名或 docker volume rm(会丢数据) |
彻底删除本目录栈(含数据卷,慎用):
docker compose down -v9. 小结
- 系统选 Ubuntu 24.04 LTS(或 22.04 LTS)。
- 入门用方式 A(TB + PG),复制第 2 节三条命令即可跑通。
- Kafka / Cassandra 组合已按官方镜像与关键环境变量校核;Cassandra 默认堆改为 2G,避免小机器 OOM。
- 先
INSTALL_TB再up -d,不要跳过初始化。
