从源码本地开发
这页带你把 IoT DC3 从源码跑起来:先用 Compose 起好 PostgreSQL 与 RabbitMQ,再用一组本地环境变量把 Java 进程指向本机端口,构建、启动、跑测试。读完你能在自己的机器上跑通整套中心服务,并理解为什么启动有先后、为什么本地进程不能直接吃根 .env。
先决条件
本地开发是"半容器"模式:基础设施(数据库、消息中间件)跑在容器里,中心服务以本地 Java 进程运行,方便断点调试与热重启。所以你需要一套 JDK/构建工具,外加一个容器运行时。
- JDK 21 —— 平台强制 Java 21,低版本编译会直接失败。
- Maven 3.9+ —— 仓库内置
.mvn/settings.xml与并行构建配置;多模块打包用它。 - pnpm —— 前端
iot-dc3-web与dc3-cli都用 pnpm(不要用 npm/yarn)。仅做后端开发可跳过。 - Podman —— 本仓库容器操作一律用
podman(make默认podman compose)。
为什么是这五步
本地起栈的最短闭环是五步,每一步都有明确产物,下一步依赖上一步的产物:先有基础设施(容器),才能加载指向它们的环境变量;先构建出 jar,才能启动开发栈;服务起来后才谈得上跑测试。
下面逐步展开,每步都给出"做什么"和"怎么验证"。
第一步:起基础设施
make up-db 用 Compose 拉起 db 栈——PostgreSQL 与 RabbitMQ。PostgreSQL 首次启动会按文件名顺序执行 initdb 脚本(扩展、common、auth、data、manager、history、agentic),把租户、用户、菜单、元数据表全部建好,所以第一次起会比后续慢。
make up-dbmake up-db-cn容器对宿主发布的端口是固定的:PostgreSQL localhost:35432、RabbitMQ AMQP localhost:35672(容器内部仍是 5432 / 5672)。验证:
podman ps # 应看到 dc3-postgres、dc3-rabbitmq 在 running
podman exec dc3-postgres psql -U dc3 -d dc3 -c '\dt dc3_auth.*' # 能列出 auth 表即就绪可选可观测栈
需要 EMQX、ELK、Prometheus、Grafana 时,再执行 make up-optional。本地核心开发用不到,建议等中心服务稳定后再起,避免一次性拉起过多容器。
第二步:加载本地环境变量
source dc3/env/dev.env.sh这一步把数据库、RabbitMQ、MQTT、gRPC 目标主机等开发默认值导出到当前 shell。其中关键的是把 POSTGRES_HOST=localhost、POSTGRES_PORT=35432、RABBITMQ_HOST=localhost、RABBITMQ_PORT=35672、以及 CENTER_AUTH_HOST/MANAGER_HOST/DATA_HOST/AGENTIC_HOST=localhost 指向本机,让本地 Java 进程能连上第一步发布出来的容器端口。
.env 只给 Docker Compose 插值,不会注入本地 Java 进程
根目录 .env 是 Compose 专用的——它只在 docker compose 解析时做变量插值(镜像仓库、镜像 tag、发布端口),不会自动注入到你本地起的 Java 进程。本地从源码跑,必须 source dc3/env/dev.env.sh;否则服务会沿用容器内 DNS 名(如 dc3-postgres:5432),在本机根本解析不到,连接直接失败。
在 JetBrains IDEA 里运行时,用 EnvFile 插件加载不含 export 的 dc3/env/dev.env,或把其键值粘进运行配置的环境变量。
验证:echo $POSTGRES_PORT 应回显 35432。
第三步:构建
make package # 等价于 mvn -s .mvn/settings.xml clean package仓库已配好并行构建、强制 JDK 21/Maven 3.9+、Spring Java Format 校验。构建产物是各服务模块的可执行 jar(如 dc3-gateway/target/dc3-gateway.jar)。这一步只验证编译与打包,不依赖第一步的容器。
快速编译检查
只想确认改动能编译、不想整包,用 mvn -s .mvn/settings.xml -q -DskipTests compile,比全量 package 快很多。
第四步:起开发栈
构建出 jar 后,用 dev 栈把中心服务跑起来。make up STACK=dev(或简写 make up-dev)按依赖顺序启动 Gateway、Auth、Manager、Data、Agentic 与驱动。
make up-devmake up-dev-cn为什么有先后顺序?因为服务之间有依赖:
- Auth 中心要先就绪——它持有租户、用户、RBAC 与令牌签发逻辑,其它服务和网关的鉴权都依赖它。
- Gateway 是唯一对外 HTTP 入口(8000),它聚合 Auth/Manager/Data/Agentic 的路由、抽取鉴权头、注入 principal 上下文。它要在后端中心服务可达之后才能正确转发,所以排在依赖项之后。
完整启动顺序与端口
分布式默认走 gRPC(DC3_FACADE_MODE=grpc,dev.env 已设)。各服务端口:
| 服务 | HTTP | gRPC |
|---|---|---|
Gateway / dc3-gateway(唯一对外入口) | 8000 | — |
鉴权中心 / dc3-center-auth | 8300 | 9300 |
管理中心 / dc3-center-manager | 8400 | 9400 |
数据中心 / dc3-center-data | 8500 | 9500 |
智能中心 / dc3-center-agentic | 8600 | — |
只有 Gateway(用户入口)与 listening-virtual 的 TCP 6270 / UDP 6271(设备入口)对宿主映射,其余后端端口都是内部端口。
验证:栈起来后,对网关跑一次登录黄金路径。登录分两步——先取盐,再用盐哈希后的密码换 12 小时有效的 access token:
# 1) 取盐(公开端点,5 分钟有效)
curl -s -X POST http://localhost:8000/api/v3/auth/token/salt \
-H 'Content-Type: application/json' \
-d '{"tenant":"default","name":"dc3"}' # 返回字符串 salt(示例值)
# 2) 用 salt 哈希密码后换 token(公开端点,access token 12 小时有效)
curl -s -X POST http://localhost:8000/api/v3/auth/token/generate \
-H 'Content-Type: application/json' \
-d '{"tenant":"default","name":"dc3","salt":"<上一步的 salt>","password":"<salt 哈希后的密码>"}'拿到 token 后,受保护端点都通过网关访问,并带上三个鉴权头 X-Auth-Tenant、X-Auth-Login、X-Auth-Token。完整的"建驱动 → 建模板 → 建设备 → 读写位号"闭环见 第一个设备:端到端。
第五步:跑测试
make test # 单元测试套件需要更高层验证时:make test-it 跑集成测试(需容器运行时供 Testcontainers),make test-e2e 跑后端 E2E。日常开发改完一处,先 make test 兜住单元回归即可。
常见坑
- 没
source dev.env.sh就起服务——最常见。本地 Java 进程拿不到localhost:35432/35672,会去连容器内 DNS 名而连不上。每开一个新 shell 都要重新source(变量只在当前 shell 生效)。 - podman 没起——
make up-db报连不上容器运行时,先确认podman守护进程/machine 已启动(macOS 上需podman machine start),再用podman ps确认。 - 端口被占——
35432/35672/8000等被其它进程占用时启动失败。释放占用进程,或在根.env中覆盖 Compose 发布端口(仅影响容器侧),本地进程端口用服务级环境变量覆盖。 - 首次起库很慢或表不全——PostgreSQL 只在空卷首启时跑 initdb。若中途中断导致表不全,需重置卷重来:
make reset STACK=db(需CONFIRM_RESET_VOLUMES=true,会删数据,谨慎)。
生产密钥必须替换
dev.env.sh 里的 DC3_SECURITY_KEY 与 AUTH_HMAC_SECRET 是开发默认值。在 pre/pro 环境,若 AUTH_HMAC_SECRET 为空或仍等于默认值 io.github.pnoker.dc3,Gateway 会 fail-fast 拒绝启动。本地开发无妨,上线前务必换成环境专属随机值。