# Lobster Docker 部署说明

本文档描述 13 服务器上的 Lobster Docker 部署、自动更新、初始化依赖发布和常用运维命令。

## 服务说明

当前 compose 文件：`/home/app/lobster-ai/deploy/docker/docker-compose.dev.yml`

主要服务：

- `lobster-ai-tomcat`：Tomcat 8 + Java 8，运行后端 exploded webapp。
- `lobster-code-sandbox-docker`：Docker-in-Docker daemon，供 `code_exec` 沙箱容器使用。
- `lobster-code-sandbox-builder`：一次性构建沙箱镜像 `lobster-sandbox:py3.11-office-v4`。
- `lobster-ai-frontend-build`：一次性构建 H5 前端。
- `lobster-ai-update-build`：一次性自动更新服务，负责检查 Git、按需构建、部署和重启 Tomcat。

运行目录挂载关系：

```text
/home/app/lobster-ai/zm-ai-server                 -> /usr/local/tomcat/webapps/ROOT
/home/app/lobster-ai/zm-ai-frontend/dist/build/ai-ui -> /usr/local/tomcat/webapps/ROOT/ai-ui
/home/app/lobster-ai/log                          -> /log/zmeg_new
/home/app/lobster-ai/zm_new_files                 -> /files1
```

后端运行目录 `/home/app/lobster-ai/zm-ai-server` 必须是完整 exploded webapp，至少包含：

```text
WEB-INF/classes
WEB-INF/config
WEB-INF/lib
WEB-INF/lobster
WEB-INF/fonts
WEB-INF/db.properties
```

## 13 服务器日常更新

日常更新只需要在 13 服务器执行：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml --profile update run --rm lobster-ai-update-build
```

自动更新服务会执行：

1. 拉取或更新 `/home/app/lobster-ai/source-code/zm-ai-server`。
2. 拉取或更新 `/home/app/lobster-ai/source-code/zm-ai-frontend`。
3. 后端 Git HEAD 变化或 `zmeg_new-artifacts` 变化时，构建并部署后端。
4. 前端 Git HEAD 变化时，运行 `lobster-ai-frontend-build` 构建前端。
5. 只有实际构建或部署发生时，才重启 `lobster-ai-tomcat`。

默认 Git 配置：

```text
SERVER_REPO_URL=http://192.168.1.204:3000/gzzm/zm-ai-server.git
SERVER_BRANCH=master
FRONTEND_REPO_URL=http://192.168.1.204:3000/gzzm-frontend/ai-deepseek.git
FRONTEND_BRANCH=next
```

如需调整仓库或分支，可在 `/home/app/lobster-ai/deploy/docker/.env` 中覆盖这些变量。

Git 凭据需要能被一次性更新容器非交互读取。当前配置会把宿主机 root 用户的 `/root/.gitconfig` 和 `/root/.git-credentials` 复制到 updater 容器内部后再执行 Git 操作。

## 后端部署规则

后端部署会把构建后的 `zm-ai-server/web` 同步到运行目录：

```text
/home/app/lobster-ai/zm-ai-server
```

同步策略是“覆盖/新增”，不会删除运行目录中已有文件。

为了保护服务器本地环境配置，以下路径不会被覆盖：

```text
WEB-INF/db.properties
WEB-INF/config/
WEB-INF/*.xml
```

除此之外，`web` 目录下的其它内容会按构建结果复制或覆盖，包括：

```text
WEB-INF/classes
WEB-INF/lib
WEB-INF/lobster
WEB-INF/fonts
静态 web 文件
新增 Java 包
```

如果 `/home/app/lobster-ai/source-code/zm-ai-server` 或 `/home/app/lobster-ai/source-code/zm-ai-frontend` 已存在但不是 Git 仓库，更新脚本会直接停止，不会删除已有目录。

## zmeg_new 初始化依赖

`zmeg_new` 是后端构建的框架依赖来源，只作为初始化依赖使用，日常更新不会自动重新构建 `zmeg_new`。

只有当 `zmeg_new` 框架 jar、`web/WEB-INF/lib` 依赖或框架 web 资源变化时，才需要在本机执行：

```powershell
cd D:\work\lobster
.\deploy\docker\publish-zmeg-artifacts.ps1
```

该脚本会在本机构建 `zmeg_new`，并上传到 13 服务器：

```text
/home/app/lobster-ai/source-code/zmeg_new-artifacts/zmeg_new-classes.jar
/home/app/lobster-ai/source-code/zmeg_new-artifacts/lib/*.jar
/home/app/lobster-ai/source-code/zmeg_new-artifacts/zmeg_new-web-no-webinf.tar.gz
```

发布新的 `zmeg_new` 初始化依赖后，再执行一次日常更新命令，让 `lobster` 使用新依赖重新构建：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml --profile update run --rm lobster-ai-update-build
```

如果服务器上还没有发布过 `zmeg_new-artifacts`，更新脚本会回退使用当前运行目录里的依赖：

```text
/home/app/lobster-ai/zm-ai-server/WEB-INF/lib
```

## 数据库配置

数据库配置读取自：

```text
/usr/local/tomcat/webapps/ROOT/WEB-INF/db.properties
```

对应服务器文件：

```text
/home/app/lobster-ai/zm-ai-server/WEB-INF/db.properties
```

示例：

```text
mysql.url=jdbc:mysql://<db-host>:<db-port>/<db-name>?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
mysql.user=<db-user>
mysql.password=<db-password>
```

该文件属于服务器环境配置，自动更新不会覆盖。

## KB 服务配置

`WEB-INF/config/lobster.xml` 中配置知识库服务地址。

使用内置 mock：

```xml
<oaKnowledgeBaseUrl>http://127.0.0.1:8080/ai/api/_mock/kb</oaKnowledgeBaseUrl>
```

如果 `zm-rag` 由宿主机运行：

```xml
<oaKnowledgeBaseUrl>http://host.docker.internal:8900/api/v1/lobster-kb</oaKnowledgeBaseUrl>
```

如果 `zm-rag` 和 Lobster 在同一个 Docker 网络：

```xml
<oaKnowledgeBaseUrl>http://zm-rag:8900/api/v1/lobster-kb</oaKnowledgeBaseUrl>
```

修改 XML 后重启 Tomcat：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml restart lobster-ai-tomcat
```

## 沙箱镜像

`lobster-code-sandbox-docker` 是 DinD daemon，用于动态创建 `code_exec` 一次性沙箱容器。

`lobster-ai-tomcat` 和 DinD 共享以下路径：

```text
/srv/sandbox
/var/cache/lobster/skill-bundles
```

因此 `DockerRunner` 生成的 bind mount 路径对创建沙箱容器的 Docker daemon 可见。

重建沙箱镜像：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml --profile build run --rm lobster-code-sandbox-builder
docker compose -f docker-compose.dev.yml restart lobster-ai-tomcat
```

不要把沙箱镜像作为常驻服务运行。

## 常用手工命令

只重启 Tomcat：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml restart lobster-ai-tomcat
```

只构建前端：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml --profile build run --rm lobster-ai-frontend-build
docker compose -f docker-compose.dev.yml restart lobster-ai-tomcat
```

重新构建 updater 镜像：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml --profile update build lobster-ai-update-build
```

查看 Tomcat 状态：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml ps lobster-ai-tomcat
```

查看 Tomcat 最新日志：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml logs --tail=300 lobster-ai-tomcat
```

查看最近错误：

```bash
cd /home/app/lobster-ai/deploy/docker
docker compose -f docker-compose.dev.yml logs --since=10m lobster-ai-tomcat | grep -E '\[error\]|Exception|ERROR|SEVERE|ClassNotFoundException'
```

## 更新后验证

服务器本机验证：

```bash
curl -I http://127.0.0.1:8080/
curl -I http://127.0.0.1:8080/ai-ui/index.html
```

外部访问验证：

```text
http://192.168.1.13:8080/
http://192.168.1.13:8080/ai-ui/index.html
```

正常现象：

- `/` 返回 `302` 跳转到 `/oa/index.lp`，跟随跳转后返回 `200`。
- `/ai-ui/index.html` 返回 `200`。
- Tomcat 启动可能较慢，首次部署或依赖变更后 ROOT 部署可能需要数分钟。
