# Docker 部署
本文介绍如何用 Docker Compose 在本机安装牧言低代码平台,作为开发和试用环境。部署到服务器请再看 生产环境部署,从旧版本升级请看 升级说明。
# 目标读者
本系统的开发和实施人员,以及希望在本地试用平台的开发者。
# 先决条件
支持 Docker 和 Docker Compose 的 Linux、macOS 或 WSL2
提示
目前不支持原生 Windows。如需在 Windows 上运行,请使用 WSL2,或通过 社区 (opens new window) 联系我们。
Docker (opens new window) 和 Docker Compose v2 (opens new window)(命令为
docker compose)平台配置仓库
muyantech/platform的访问权限。这是一个私有仓库,购买平台后请通过 社区 (opens new window) 联系我们开通。在 GitHub 上配置好 SSH 密钥 (opens new window),仓库通过 SSH 克隆。
注意
没有仓库访问权限时,下面的克隆步骤会失败。
# 组件与版本
平台由以下容器组成,镜像版本以仓库中 docker-compose.yml 为准。下表是当前仓库中的配置:
| 服务 | 镜像 | 说明 |
|---|---|---|
proxy | nginx:latest | 统一入口,把 /api/ 转发给后端,其他请求转发给前端 |
client | muyantech/frontend-next:1.0.0-beta12 | 平台前端 |
client_legacy | muyantech/frontend:0.31.0-beta5 | 旧版前端,挂在 /legacy/ 路径下 |
server | muyantech/backend:1.0.0-beta18 | 平台后端(Grails 7 + Java 25) |
database | pgvector/pgvector:0.8.0-pg17 | PostgreSQL 17,带 pgvector 扩展 |
redis | redis:latest | 缓存、分布式锁 |
pgadmin | dpage/pgadmin4:latest | 数据库的 Web 管理工具 |
# 安装
# 手动安装(推荐)
在要存放平台的目录下依次执行:
# 1. 克隆平台配置仓库
git clone [email protected]:muyantech/platform.git
cd platform
# 2. 用只读令牌登录 Docker Hub(后端镜像需要登录才能拉取)
cat token.txt | docker login -u muyantech --password-stdin
# 3. 启动全部容器
docker compose up -d
# 4. 查看容器状态,server 显示 healthy 即启动完成
docker compose ps
2
3
4
5
6
7
8
9
10
11
12
首次安装要拉取全部镜像,视网络情况可能需要 10 分钟以上。也可以用 curl -s http://localhost:9080/api/actuator/health 确认后端就绪,返回 {"status":"UP"} 即可访问。
macOS 用户
docker-compose.yml 中 server 服务挂载了宿主机的 /etc/timezone(/etc/timezone:/etc/timezone:ro)。如果在 macOS 上启动时报 /etc/timezone 挂载相关的错误,删除 docker-compose.yml 中这一行后再执行 docker compose up -d。
# 一键安装脚本(暂不推荐)
一键脚本当前安装的是旧版本
目前线上的 muyan.sh 克隆的是旧的配置仓库 xqliu/platform,而不是上面的 muyantech/platform:只开通了 muyantech/platform 权限的账号会在克隆这一步失败;即使克隆成功,装出来的后端和前端也都是 1.0.0-beta8,不包含 1.0.0-beta18 的安全修复。在脚本更新之前,请使用上面的手动安装。已经用脚本安装的,可以在 platform 目录执行 docker compose images 查看版本。
脚本的用法和执行过程如下,供了解:
curl -fsSL https://muyan.io/muyan.sh | bash
如果使用 https://www.muyan.io/muyan.sh 地址,必须带 -L:它会 301 跳转到 https://muyan.io/muyan.sh,不跟随跳转时 bash 收到的是空内容,命令会直接结束,什么都不安装。
脚本依次执行:
- 检查
docker-compose(v1)或docker compose(v2)是否可用; - 如果当前目录已有
platform目录,先改名为platform_<日期_时间>备份; - 用 SSH 克隆配置仓库到
./platform; - 用仓库里的只读令牌
token.txt登录 Docker Hub(docker login -u muyantech),后端镜像需要登录才能拉取; - 启动全部容器:装有 v1 的
docker-compose时优先执行docker-compose up -d,否则执行docker compose up -d; - 轮询
http://localhost:9080/api/actuator/health,最多等 10 分钟,直到返回UP,然后在浏览器中打开平台。
# 访问
# 本机访问
浏览器打开 http://localhost:9080 (opens new window),用下文的 默认账号 登录。
登录后进入首页。首页有“消息”和“系统运行监控”两个仪表盘页签,当前版本默认先显示哪一个不固定,下图是“系统运行监控”页签:
注意
首页“客制化运行记录”卡片中的 向导运行记录、字段客制化运行记录、系统集成运行记录 三个链接对应 1.0 已移除的功能,点击后显示 404 页面,这是当前版本的界面问题,请忽略这三个链接。同一页面上“字段客制化运行结果分布”卡片对应的也是已移除的功能,内容为空;“客制化运行总体成功率”仪表的刻度显示的是运行次数(例如截图中的 0–800,会随数据变化),而不是 0–100%,这些都是当前版本的界面问题。
前端和后端都通过 proxy 服务的 9080 端口访问:页面是 http://localhost:9080/,后端接口是 http://localhost:9080/api/。
# 局域网访问
9080 端口映射到宿主机所有网卡,局域网内可以直接用宿主机 IP 访问,例如 http://192.168.0.2:9080,无需额外配置。
# 开始开发
# 项目结构
安装完成后进入 platform 目录,仓库中的主要文件如下:
.
├── codes # 插件工程(Gradle)
│ ├── build.gradle # 插件构建配置
│ ├── settings.gradle
│ ├── gradlew / gradlew.bat # Gradle 包装器
│ ├── src/main/groovy/tech/muyan/plugin
│ │ └── PluginExample.java # 插件示例
│ ├── data # 应用种子数据,挂载到容器内的 /app/plugin/data
│ │ ├── csv # 种子 CSV(领域模型、表单、菜单、用户等)
│ │ ├── groovy # 动态逻辑的 Groovy 源码
│ │ ├── attachments # 种子数据引用的附件
│ │ ├── css # 自定义样式
│ │ └── prompts # 提示词文件
│ └── ui-component # 自定义前端组件工程
├── db-seed-data
│ └── initdb # 数据库首次初始化时执行的脚本
│ ├── 00-restore-dump.sh # 从 seed-data.dump 恢复初始数据
│ ├── 01-create-pgvector-extension.sql
│ └── seed-data.dump # 初始数据库转储
├── runtime # 运行时目录
│ ├── attachments # 上传的附件,挂载到容器内的 /app/attachments
│ ├── client / client_legacy # 前端日志;可放入自行编译的前端
│ ├── pgadmin # pgAdmin 配置(servers.json、pgpass)
│ ├── proxy/conf.d/default.conf # nginx 转发配置
│ └── server # 可放入自行编译的后端 boot.jar
├── docker-compose.yml # 容器编排配置
├── muyan.sh # 一键安装脚本
├── start.sh # 如有 runtime/server/boot.jar 则挂载后启动(使用 docker-compose v1 命令)
└── token.txt # Docker Hub 只读令牌
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
数据库数据保存在 runtime/database/data,首次启动时自动创建,不在仓库中。
种子 CSV 直接放在 codes/data/csv 下,不再按租户分子目录。后端启动时从 ${SEED_DATA_FOLDER}/csv(即容器内的 /app/plugin/data/csv)导入。
# 开始编码
- 跟着教程 从零开始构建一个简易的 CRM 系统
- 开始系统设计,参考 系统设计指南
- 定义领域模型、表单、动作等,参考 数据导入 及 CSV 文件模板
- 开发插件,参考 插件开发
平台使用统一的前端,一般不需要自己开发前端。需要自定义界面组件时,参考仓库里的 codes/ui-component 工程和 插件开发。
# 管理应用
在 platform 目录下执行:
# 启动
docker compose up -d
# 停止
docker compose down
# 查看后端日志
docker compose logs -f server
2
3
4
5
6
7
8
# 升级到新版本
平台发布新版本后,仓库中 docker-compose.yml 的镜像版本会随之更新。在 platform 目录下执行:
git pull && docker compose pull && docker compose up -d
如果本地改过仓库中的文件(例如 docker-compose.yml、default.conf),git pull 可能冲突,请先备份或 git stash。
升级前请先阅读 升级说明,特别是 1.0.0-beta18 的匿名调用变更。
# 查看当前版本
docker compose images
输出示例:
CONTAINER REPOSITORY TAG ...
platform-client-1 muyantech/frontend-next 1.0.0-beta12 ...
platform-client_legacy-1 muyantech/frontend 0.31.0-beta5 ...
platform-database-1 pgvector/pgvector 0.8.0-pg17 ...
platform-server-1 muyantech/backend 1.0.0-beta18 ...
2
3
4
5
TAG 列就是正在运行的版本。
注意
界面上 系统运维 > 产品版本 里的数据目前停在 0.28.8,不代表实际运行的后端版本,请以 docker compose images 为准。
# 相关配置
# 后端环境变量
docker-compose.yml 中 server 服务的环境变量:
| 变量 | 默认配置 | 说明 |
|---|---|---|
JDBC_DATABASE_URL | jdbc:postgresql://database:5432/application | 数据库连接地址 |
JDBC_DATABASE_USERNAME | postgres | 数据库用户名 |
JDBC_DATABASE_PASSWORD | password | 数据库密码,需与 database 服务的 POSTGRES_PASSWORD 一致 |
REDIS_URL | redis://redis:6379 | Redis 地址。另可用 REDIS_PASSWORD、REDIS_DATABASE |
SEED_DATA_FOLDER | /app/plugin/data | 应用种子数据目录,后端从其下的 csv 子目录导入。未设置时为 /app/data |
JAVA_OPTS | 开启 5005 远程调试 | 追加的 JVM 参数,例如内存上限 -Xmx4g |
GRAILS_ENV | development | 运行环境,不要随意修改。development 下每次启动都会刷新平台模型定义和种子数据 |
TENANT_ID | ${TENANT_ID:-muyan} | 租户名,见下文 更改默认租户 |
JWT_SECRET | 未设置(使用镜像内置的默认值) | 登录令牌的签名密钥。部署到服务器时必须设置,见 生产环境部署 |
注意
docker-compose.yml 中还有 ISOLATION_REQUIRED、ISOLATION_PLUGIN_VERSION、ISOLATION_PLUGIN_DIGEST、TENANT_HEADER_TRUSTED 四个变量。当前后端版本(1.0.0-beta18)没有读取它们,修改不会产生任何效果,请保持原样。
此外,系统配置(DynamicConfig)也可以用环境变量覆盖:把配置的 key 中的 . 换成 _ 作为变量名,有环境变量时优先使用环境变量的值。
# 更改默认租户
租户名有两个作用:
- 作为动态领域模型数据表的前缀,例如
muyan_sample_dynamic_order_domain; - 作为所有记录
tenant列的值。
默认租户是 muyan。更改租户要同时改后端和 nginx 两处,建议在首次安装、还没有业务数据时进行。
# 1. 设置 TENANT_ID
在 platform 目录下新建 .env 文件(Docker Compose 会自动读取):
TENANT_ID=acme
也可以在启动前 export TENANT_ID=acme。
# 2. 修改 nginx 转发的租户请求头
runtime/proxy/conf.d/default.conf 中有 12 处 proxy_set_header X-Muyan-Tenant muyan;,后端按这个请求头确定租户。把它们全部改为新租户名:
sed -i 's/X-Muyan-Tenant muyan;/X-Muyan-Tenant acme;/' runtime/proxy/conf.d/default.conf
grep -c 'X-Muyan-Tenant acme' runtime/proxy/conf.d/default.conf # 应输出 12
2
只改 TENANT_ID 不改这里,所有请求都会失败,后端返回 Tenant muyan not found in system。
# 3. 重启
docker compose up -d --force-recreate server proxy
后端启动时会为新租户创建租户记录,并把平台种子数据和 codes/data/csv 下的应用种子数据导入新租户。默认账号不变,仍可用 [email protected] 登录。
注意
- 原租户的数据仍保留在数据库中,但换租户后不可见。
- 数据库里同时存在两个租户时,后端启动日志会出现一条
Failed to execute after import sql ... more than one row returned by a subquery的错误。实测不影响登录和使用。
# 附加说明
# 端口列表
| 组件 | 宿主机端口 | 访问方式 |
|---|---|---|
| 前端与后端(proxy) | 9080 | 页面 http://localhost:9080,接口 http://localhost:9080/api/ |
| pgAdmin | 5433 | http://localhost:5433 |
| 后端远程调试 | 5005 | 在 IDEA 中新建 Remote JVM Debug,连接 localhost:5005 |
| 后端 8080 | 不映射 | 只在容器网络内可访问,请通过 9080 的 /api/ 访问 |
| PostgreSQL 5432 | 不映射 | docker compose exec database psql -U postgres -d application,或用 pgAdmin |
| Redis 6379 | 不映射 | docker compose exec redis redis-cli |
如果宿主机的 9080、5433、5005 端口已被占用,修改 docker-compose.yml 中对应服务 ports 的左侧端口即可。
# 默认用户名及密码
| 组件 | 用户名 | 密码 |
|---|---|---|
| 平台超级管理员(管理员组) | [email protected] | password |
| 示例用户“项目经理”(业务组) | [email protected] | password |
| 示例用户“财务”(业务组) | [email protected] | password |
| pgAdmin | [email protected] | secret |
| PostgreSQL | postgres | password |
平台用户定义在 codes/data/csv/User.csv,所属用户组在 UserGroup.csv。PostgreSQL 的数据库名是 application。
部署到服务器前请修改上述所有默认密码。
# Docker 数据卷
| 组件 | 容器内路径 | 宿主机路径 | 说明 |
|---|---|---|---|
| PostgreSQL | /var/lib/postgresql/data | ./runtime/database/data | 数据库数据文件 |
| PostgreSQL | /docker-entrypoint-initdb.d/ | ./db-seed-data/initdb | 首次初始化脚本和初始数据 |
| 后端 | /app/plugin/data/csv | ./codes/data/csv | 应用种子 CSV |
| 后端 | /app/plugin/data/groovy | ./codes/data/groovy | 动态逻辑源码 |
| 后端 | /app/plugin/data/attachments | ./codes/data/attachments | 种子数据附件 |
| 后端 | /app/plugin/data/css | ./codes/data/css | 自定义样式 |
| 后端 | /app/plugin/data/prompts | ./codes/data/prompts | 提示词文件 |
| 后端 | /app/attachments | ./runtime/attachments | 用户上传的附件 |
| 后端 | /etc/timezone(只读) | /etc/timezone | 宿主机时区 |
| proxy | /etc/nginx/conf.d | ./runtime/proxy/conf.d | nginx 转发配置 |
| proxy | /var/log/nginx | ./runtime/proxy/logs | nginx 日志 |
| client | /var/log/nginx | ./runtime/client/logs | 前端 nginx 日志 |
| client_legacy | /var/log/nginx | ./runtime/client_legacy/logs | 旧版前端 nginx 日志 |
| pgAdmin | /var/lib/pgadmin | ./runtime/pgadmin/data | pgAdmin 数据 |
| pgAdmin | /pgadmin4/config | ./runtime/pgadmin/config | pgAdmin 配置 |
| pgAdmin | /var/log/pgadmin | ./runtime/pgadmin/log | pgAdmin 日志 |
| pgAdmin | /var/lib/pgadmin/storage/db_muyan.cloud/pgpass | ./runtime/pgadmin/pgpass | pgAdmin 数据库密码文件 |
db-seed-data/initdb 只在 runtime/database/data 为空(首次启动)时执行。要恢复成全新的初始数据库,先 docker compose down,删除 runtime/database/data 后再启动。这会清空所有数据,请先备份。
# 进一步阅读
← 🎨 系统设计指南 💻 Dokku 部署 →