本项目为 MaaS(Model as a Service)底座前端,基于 UmiJS + React + Ant Design 构建。采用 Docker 多阶段构建,最终产物通过 Nginx 提供静态资源服务,并代理部分请求至后端 GPUStack 服务。
| 组件 | 版本 |
|---|---|
| Node.js | 18 (Alpine) |
| pnpm | 9.3.0 |
| Nginx | Alpine (最新稳定版) |
| 后端服务 | gpustack/gpustack:latest |
用户请求 → Nginx (80端口)
├── 静态资源 → /usr/share/nginx/html (前端构建产物)
└── API代理 → gpustack 后端 (:80)
代理路径: /v1, /v2, /auth, /version, /proxy, /update, /cli, /grafana
git clone <repository-url> maas-base-ui
cd maas-base-ui
复制 .env 文件并根据实际情况修改:
cp .env .env.prod
| 变量名 | 说明 | 默认值 |
|---|---|---|
APP_TITLE |
前端应用标题 | 成都网讯MaaS底座 |
ENABLE_PLAYGROUND |
是否显示试验场菜单 (true/false) |
false |
UI_PORT |
Nginx 对外暴露端口 | 8080 |
docker compose --env-file .env.prod up -d --build
该命令会依次执行:
node:18-alpine 中安装依赖并执行 pnpm buildmaas-ui 和 backend 两个服务# 查看容器状态
docker compose ps
# 查看前端服务日志
docker compose logs -f maas-ui
# 查看后端服务日志
docker compose logs -f backend
# 测试访问
curl -I http://localhost:8080
预期返回 200 OK。
当前 nginx.conf 为基础配置,生产环境建议补充以下内容:
server {
listen 80;
server_name your-domain.com; # 替换为实际域名
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Gzip 压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1000;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# 后端代理
location ~ ^/(v1|v2|auth|version|proxy|update|cli|grafana) {
proxy_pass http://backend:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
推荐使用 Nginx Proxy Manager 或手动配置证书:
# 将证书文件放置到指定目录
mkdir -p certs
# 放入 your-domain.crt 和 your-domain.key
# 修改 nginx.conf 监听 443
或通过 docker-compose.yml 挂载 Traefik / Caddy 等反向代理处理 HTTPS。
后端 GPUStack 数据已通过 Docker Volume gpustack-data 持久化。生产环境建议:
# 查看数据卷位置
docker volume inspect maas-base-ui_gpustack-data
# 可选:将 volume 替换为宿主机目录挂载
# volumes:
# - /data/gpustack:/var/lib/gpustack
# 拉取最新代码
git pull
# 重新构建并启动
docker compose --env-file .env.prod up -d --build
# 清理无用镜像
docker image prune -f
修改 .env.prod 中的 UI_PORT 可更改对外端口:
UI_PORT=9090
docker compose --env-file .env.prod up -d
# 实时日志
docker compose logs -f --tail=100 maas-ui
# 导出日志
docker compose logs --no-color maas-ui > maas-ui.log
# 限制 Docker 日志大小(建议配置 /etc/docker/daemon.json)
# {
# "log-driver": "json-file",
# "log-opts": {
# "max-size": "50m",
# "max-file": "3"
# }
# }
# 停止服务
docker compose down
# 停止并删除数据卷(⚠️ 会清除后端数据)
docker compose down -v
# 完整清理
docker compose down -v --rmi all --remove-orphans
# 检查 pnpm-lock.yaml 是否存在
ls -la pnpm-lock.yaml
# 清理 Docker 构建缓存
docker builder prune -a
# 增加 Docker 内存限制(macOS/Windows Docker Desktop)
# 设置 -> Resources -> Memory >= 4GB
# 检查端口占用
netstat -tlnp | grep 8080
# 检查容器网络
docker compose exec maas-ui curl -I http://backend:80
# 检查防火墙
# Ubuntu/Debian
sudo ufw allow 8080/tcp
# CentOS/RHEL
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --reload
确认 nginx.conf 中的 proxy_pass http://backend:80 与 docker-compose.yml 中 backend 服务名一致。Docker Compose 自动通过内部 DNS 解析服务名。
| 文件 | 用途 |
|---|---|
Dockerfile |
多阶段构建:Node.js 构建 + Nginx 运行 |
docker-compose.yml |
编排前端 + 后端 GPUStack 服务 |
nginx.conf |
Nginx 路由配置(静态资源 + API 代理) |
.env |
环境变量配置 |
| 端口 | 服务 | 说明 |
|---|---|---|
UI_PORT (默认 8080) |
maas-ui | 前端 Nginx 对外端口 |
80 |
backend | GPUStack Web 服务 |
30080 |
backend | GPUStack 备用端口 |
10161 |
backend | GPUStack 内部通信端口 |