# Docker 部署

本文介绍如何用 Docker Compose 在本机安装牧言低代码平台,作为开发和试用环境。部署到服务器请再看 生产环境部署,从旧版本升级请看 升级说明。

# 目标读者

本系统的开发和实施人员,以及希望在本地试用平台的开发者。

# 先决条件

注意

没有仓库访问权限时,下面的克隆步骤会失败。

# 组件与版本

平台由以下容器组成,镜像版本以仓库中 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
1
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
1

如果使用 https://www.muyan.io/muyan.sh 地址,必须带 -L:它会 301 跳转到 https://muyan.io/muyan.sh,不跟随跳转时 bash 收到的是空内容,命令会直接结束,什么都不安装。

脚本依次执行:

  1. 检查 docker-compose(v1)或 docker compose(v2)是否可用;
  2. 如果当前目录已有 platform 目录,先改名为 platform_<日期_时间> 备份;
  3. 用 SSH 克隆配置仓库到 ./platform;
  4. 用仓库里的只读令牌 token.txt 登录 Docker Hub(docker login -u muyantech),后端镜像需要登录才能拉取;
  5. 启动全部容器:装有 v1 的 docker-compose 时优先执行 docker-compose up -d,否则执行 docker compose up -d;
  6. 轮询 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 只读令牌
1
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)导入。

# 开始编码

平台使用统一的前端,一般不需要自己开发前端。需要自定义界面组件时,参考仓库里的 codes/ui-component 工程和 插件开发。

# 管理应用

在 platform 目录下执行:

# 启动
docker compose up -d

# 停止
docker compose down

# 查看后端日志
docker compose logs -f server
1
2
3
4
5
6
7
8

# 升级到新版本

平台发布新版本后,仓库中 docker-compose.yml 的镜像版本会随之更新。在 platform 目录下执行:

git pull && docker compose pull && docker compose up -d
1

如果本地改过仓库中的文件(例如 docker-compose.yml、default.conf),git pull 可能冲突,请先备份或 git stash。

升级前请先阅读 升级说明,特别是 1.0.0-beta18 的匿名调用变更。

# 查看当前版本

docker compose images
1

输出示例:

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   ...
1
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 中的 . 换成 _ 作为变量名,有环境变量时优先使用环境变量的值。

# 更改默认租户

租户名有两个作用:

  1. 作为动态领域模型数据表的前缀,例如 muyan_sample_dynamic_order_domain;
  2. 作为所有记录 tenant 列的值。

默认租户是 muyan。更改租户要同时改后端和 nginx 两处,建议在首次安装、还没有业务数据时进行。

# 1. 设置 TENANT_ID

在 platform 目录下新建 .env 文件(Docker Compose 会自动读取):

TENANT_ID=acme
1

也可以在启动前 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
1
2

只改 TENANT_ID 不改这里,所有请求都会失败,后端返回 Tenant muyan not found in system。

# 3. 重启

docker compose up -d --force-recreate server proxy
1

后端启动时会为新租户创建租户记录,并把平台种子数据和 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 后再启动。这会清空所有数据,请先备份。

# 进一步阅读

Last Updated: 2026/9/24 14:27:35