198 lines
12 KiB
Markdown
198 lines
12 KiB
Markdown
# AML_Backend 本地开发(docker-compose)使用说明
|
||
|
||
用 docker-compose 在本地一键拉起 `iCON.Abp.FX.HttpApi.Host`,包含 SQL Server 数据库容器,并自动完成数据库迁移与种子数据初始化,用于本地开发调试。
|
||
|
||
> 适用平台:macOS(含 Apple Silicon / arm64)。相关文件均位于 `AML_Backend/docker-compose-local-dev/` 目录下;构建上下文(build context)是上一级的仓库根目录 `AML_Backend/`。
|
||
|
||
---
|
||
|
||
## 1. 架构概览
|
||
|
||
`docker-compose.local.yml` 定义四个服务:
|
||
|
||
| 服务 | 作用 | 说明 |
|
||
|------|------|------|
|
||
| `mssql` | SQL Server 2022 数据库 | arm64 上通过 `platform: linux/amd64`(Rosetta 模拟)运行;数据持久化在命名卷 `mssql-data` |
|
||
| `rabbitmq` | 消息队列(异步任务中枢) | `rabbitmq:3.13-management`(arm64 原生);`host`/`consumer` 靠它跑数据采集、报告生成、AI 检测、门户订单等异步链路。宿主端口错开为 `5673`/`15673`(见第 8 节) |
|
||
| `db-migrator` | 数据初始化 | 运行一次:执行 EF Core 迁移 + 种子数据,完成后退出(exit 0) |
|
||
| `httpapi-host` | 后端 API 主机 | 等 `db-migrator` 成功后才启动;对外暴露 `44331`;随宿主启动 `RabbitMQConsumerService` 消费上述队列 |
|
||
|
||
启动顺序由健康检查与 `depends_on` 保证:`mssql` + `rabbitmq` 健康 → `db-migrator` 跑完 → `httpapi-host` 启动。
|
||
|
||
配套文件(均在 `docker-compose-local-dev/` 内):
|
||
- `Dockerfile.local`:本地多阶段构建镜像(**.NET 6**),产出 `host` 与 `migrator` 两个目标。
|
||
- `Dockerfile.local.dockerignore`:本地构建专用忽略表(仅排除 `bin/obj/.git` 等)。BuildKit 会优先采用「与 Dockerfile 同目录、同名 + `.dockerignore`」的这个文件,从而**覆盖**仓库根目录的 `.dockerignore`(根目录那个会把 `appsettings.json`、`docker-compose*` 都排除掉,不适用于本地构建)。
|
||
- `appsettings.local.json`:**本地专用、绕过 Nacos 的完整配置**(见第 1.1 节),构建时会被覆盖进镜像的 `appsettings.json`。
|
||
|
||
> ⚠️ 仓库自带的 CI 用 `src/iCON.Abp.FX.HttpApi.Host/Dockerfile` 已过时(写的是 .NET 5、且 COPY 一个不存在的 `src/access-token.bin`),**不要**用它做本地构建,请使用 `Dockerfile.local`。
|
||
|
||
### 1.1 配置来源:为什么要绕过 Nacos
|
||
|
||
最新代码已把配置中心切到 **Nacos**:`src/iCON.Abp.FX.HttpApi.Host/appsettings.json` 现在只剩一个 `NacosConfig` 段,真正的配置(连接串、AuthServer、AppConfig、RabbitMQ、任务开关等)都从 Nacos 服务器 `http://192.168.1.120:8848`(DataId `aml.dev.json`)拉取。
|
||
|
||
该 Nacos 地址是公司内网,本机通常不可达;且它指向的是共享 dev 环境(连接串指向远程 dev 库),与「本地自包含隔离栈」的目标冲突。
|
||
|
||
`Program.cs` 里 Nacos 是**条件加载**的——仅当配置里存在 `NacosConfig` 段才会 `AddNacosV2Configuration`。因此本地方案是:用 `appsettings.local.json`(一份**不含 `NacosConfig`、但包含完整配置**的文件)覆盖镜像里的 `appsettings.json`,App 便不再尝试连接 Nacos,直接用本地配置启动;再由 compose 的环境变量把连接串等指向本地 `mssql` 容器。
|
||
|
||
> `appsettings.local.json` 取自 Nacos 改造前(commit `297d3bb6` 的父提交)那版完整 `appsettings.json`,是目前唯一可自包含运行的完整配置快照。若今后 Nacos 里新增了启动必需的配置项,需要手动同步补进这个文件。
|
||
|
||
---
|
||
|
||
## 2. 前置条件
|
||
|
||
1. **Docker Desktop** 已安装并运行。
|
||
2. **内存 ≥ 16 GB**:SQL Server 2022 在 Apple Silicon 上是 amd64 模拟运行,内存不足会 SIGSEGV(exit 139)。
|
||
- 在 Docker Desktop → Settings → Resources → Memory 调到 16 GB,或编辑 `~/Library/Group Containers/group.com.docker/settings-store.json` 加入 `"MemoryMiB": 16384` 后执行 `docker desktop restart`。
|
||
3. **ABP 商业版授权令牌**(关键,见下一节)。
|
||
|
||
---
|
||
|
||
## 3. ABP 授权令牌(必须,否则 API 起不来)
|
||
|
||
`httpapi-host` 依赖 ABP 商业模块(LanguageManagement、Lepton Commercial、Account Pro 等)。
|
||
启动时若授权校验失败,进程会直接终止:**exit 214 / `ABP-LIC-0008`**。
|
||
appsettings 内置的 `AbpLicenseCode` 是 2021 年的旧授权(已过期),因此需要用 `abp login` 生成的令牌。
|
||
|
||
> 注:`db-migrator` 不强制校验授权,所以数据迁移/种子在没有令牌时也能成功,只有 `httpapi-host` 需要令牌。
|
||
|
||
### 生成令牌(一次即可,令牌持久化在 `~/.abp/cli/`)
|
||
|
||
本机若已安装 ABP CLI:
|
||
|
||
```bash
|
||
abp login fengruixiang -o JustGroup -p <你的密码>
|
||
```
|
||
|
||
本机未安装 ABP CLI 时,可在容器内执行(令牌通过挂载落到宿主机 `~/.abp/cli/`):
|
||
|
||
```bash
|
||
mkdir -p "$HOME/.abp"
|
||
docker run --rm -v "$HOME/.abp:/root/.abp" \
|
||
--entrypoint /bin/bash mcr.microsoft.com/dotnet/sdk:6.0 -lc '
|
||
export PATH="$PATH:/root/.dotnet/tools"
|
||
dotnet tool install --global Volo.Abp.Cli --version 6.0.3
|
||
abp login fengruixiang -o JustGroup -p <你的密码>
|
||
'
|
||
```
|
||
|
||
成功后会生成 `~/.abp/cli/access-token.bin`。`docker-compose.local.yml` 已把它只读挂载进容器:
|
||
|
||
```yaml
|
||
volumes:
|
||
- "${HOME}/.abp/cli:/root/.abp/cli:ro"
|
||
```
|
||
|
||
> 该令牌在**运行时联网**向 abp.io 校验授权,因此 `httpapi-host` 启动时需要网络。
|
||
|
||
---
|
||
|
||
## 4. 一键启动
|
||
|
||
```bash
|
||
cd AML_Backend/docker-compose-local-dev
|
||
docker compose -f docker-compose.local.yml up -d --build
|
||
```
|
||
|
||
> 也可在仓库根目录运行:`cd AML_Backend && docker compose -f docker-compose-local-dev/docker-compose.local.yml up -d --build`。
|
||
|
||
首次构建较慢(需还原大量 ABP 商业 NuGet 包并编译约 40 个项目,并拉取 SQL Server 镜像)。
|
||
构建已做内存优化(`-m:1` 单项目编译 + NuGet 缓存挂载),避免 Roslyn 因内存不足被杀(OOM / exit 137)。
|
||
|
||
启动后验证:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.local.yml ps
|
||
# httpapi-host 为 Up、db-migrator 为 Exited(0)、mssql 为 Up(healthy)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 访问信息
|
||
|
||
| 项目 | 地址 / 凭据 |
|
||
|------|------------|
|
||
| Swagger | http://localhost:44331/swagger (FX API + AMLPortal API) |
|
||
| OpenID 配置 | http://localhost:44331/.well-known/openid-configuration |
|
||
| 数据库 | `localhost,11433`,用户 `sa`,密码 `Aml@Local2026`,库名 `AbpAML` |
|
||
| RabbitMQ 管理台 | http://localhost:15673 ,用户 `admin` / 密码 `123456`(vhost `bthost`) |
|
||
| 应用管理员 | `admin@abp.io` / `1q2w3E*` |
|
||
|
||
种子数据包含:管理员账号、249 个国家、155 种货币、转账类型、文本模板、检测阈值等(共约 124 张表)。
|
||
|
||
---
|
||
|
||
## 6. 常用操作
|
||
|
||
```bash
|
||
cd AML_Backend/docker-compose-local-dev
|
||
|
||
# 查看后端日志(注意:Release 构建日志写文件,docker logs 可能为空,见下)
|
||
docker compose -f docker-compose.local.yml logs -f httpapi-host
|
||
|
||
# 停止(保留数据库卷)
|
||
docker compose -f docker-compose.local.yml down
|
||
|
||
# 重新启动
|
||
docker compose -f docker-compose.local.yml up -d
|
||
|
||
# 改了代码后重建并重启
|
||
docker compose -f docker-compose.local.yml up -d --build
|
||
|
||
# 仅重跑数据初始化(迁移+种子,幂等)
|
||
docker compose -f docker-compose.local.yml run --rm db-migrator
|
||
|
||
# 彻底重置数据库(删除数据卷后重来)
|
||
docker compose -f docker-compose.local.yml down -v
|
||
docker compose -f docker-compose.local.yml up -d --build
|
||
|
||
# 连接数据库执行 SQL
|
||
docker exec aml-mssql /opt/mssql-tools18/bin/sqlcmd \
|
||
-S localhost -U sa -P "Aml@Local2026" -C -d AbpAML -Q "SELECT COUNT(*) FROM AbpUsers"
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 本地开发已做的环境覆盖
|
||
|
||
`httpapi-host` 通过环境变量覆盖了若干配置,让本地能干净启动:
|
||
|
||
- `ASPNETCORE_URLS=http://+:44331`,`App__SelfUrl` / `AuthServer__Authority=http://localhost:44331`(保证 IdentityServer 颁发者与浏览器访问地址一致),`AuthServer__RequireHttpsMetadata=false`。
|
||
- `ConnectionStrings__Default` 指向 `mssql` 服务(覆盖 appsettings 里的 `localhost`)。
|
||
- **RabbitMQ**:`AppConfig__RabbitMQConfig__HostName=rabbitmq`(指向 compose 内的 broker)、`...__EnableConsumer=true`(开启后台消费)。账号/vhost(`admin`/`123456`/`bthost`)沿用 appsettings.local.json,与 `rabbitmq` 服务的 `RABBITMQ_DEFAULT_*` 一致。
|
||
- **iCS**:`AppConfig__iCS__iCSRootUrl=https://stag-abp-api.iconsz.com/`(iCS 服务端不在本仓库,指向共享 stag 实例,让文档/问卷/检测引擎等功能可用)。iCS 用的是 ZeroSSL/Sectigo 证书、且服务器只下发部分证书链;`Dockerfile.local` 的 `runtime-base` 阶段刷新了容器 CA 库,否则 HttpClient 会因 `PartialChain` 握手失败(应用自带的证书旁路只作用于旧式 WebClient,不管 HttpClient)。
|
||
> 依赖 stag 那边的 iCS 凭证有效;若 stag 不可达或换了证书,相关功能会失败但不影响 host 启动。
|
||
- 仍关闭 `SanctionJob`(依赖本地未部署的 Elasticsearch)。`EngineListSyncJob` 因 iCS 已指向 stag 而恢复默认启用。
|
||
|
||
> 仍有部分检测功能依赖 Elasticsearch(`192.168.1.120:9200` 等)等远程/局域网服务,本 compose 未包含。如需本地联调,需另行配置对应服务地址。
|
||
|
||
---
|
||
|
||
## 8. 故障排查
|
||
|
||
| 现象 | 原因 | 解决 |
|
||
|------|------|------|
|
||
| `httpapi-host` 反复重启 / exit 214,日志含 `ABP-LIC-0008` | ABP 授权令牌缺失或过期 | 按第 3 节生成 `~/.abp/cli/access-token.bin`,确认 compose 挂载,重启服务 |
|
||
| `mssql` exit 139(SIGSEGV)、状态 unhealthy | Apple Silicon 模拟下内存不足 | 把 Docker 内存调到 ≥16 GB(第 2 节),`docker desktop restart` |
|
||
| 构建时 `csc.dll exited with code 137` / `cannot allocate memory` | 编译 `DbMigrations` 大项目时 OOM | 已用 `-m:1` 缓解;确保 Docker 内存充足,必要时串行构建 |
|
||
| `docker logs httpapi-host` 为空但服务异常 | Release 构建只写文件日志(`#if DEBUG` 才有控制台 sink),日志在容器内 `/app/Logs/<级别>/<日期>/` | `docker cp aml-httpapi-host:/app/Logs ./Logs` 后查看,或临时用 `--build-arg BUILD_CONFIGURATION=Debug` 构建以获得控制台日志 |
|
||
| 访问 Swagger 401/跳转异常 | `AuthServer:Authority` 与实际访问地址不一致 | 确认仍是 `http://localhost:44331`,端口映射 `44331:44331` 未改 |
|
||
| 启动报 `Bind for 0.0.0.0:5672 failed: port is already allocated` | 宿主已有其它 RabbitMQ 占用 5672/15672 | 本 compose 已把宿主端口错开为 `5673`/`15673`;若仍冲突,改 `rabbitmq.ports` 即可(容器间通信走内部 5672,不受影响) |
|
||
| 日志含 `SSL connection could not be established ... PartialChain` | 容器 CA 库无法补全 iCS(stag) 的 ZeroSSL 证书链,且 HttpClient 不认应用的证书旁路 | 由 `Dockerfile.local` 的 `runtime-base` 刷新 CA 库解决;若复现,确认镜像是最新构建(`--build`)|
|
||
| iCS 功能报 401/token 失败(非 TLS) | stag 那边的 iCS 凭证/租户失效 | 与后端确认 `AppConfig:iCS:Credential` 在 stag 是否有效;非致命,不影响 host |
|
||
|
||
---
|
||
|
||
## 9. 相关文件清单
|
||
|
||
```
|
||
AML_Backend/ # 构建上下文(build context)根目录
|
||
├─ NuGet.Config # ABP 商业源(Dockerfile 会 COPY)
|
||
├─ src/iCON.Abp.FX.HttpApi.Host/ # API 主机工程
|
||
└─ docker-compose-local-dev/ # ← 本地开发相关文件都在这里
|
||
├─ docker-compose.local.yml # 本地三服务编排(本说明对应文件)
|
||
├─ Dockerfile.local # 本地 .NET 6 多阶段构建(host / migrator 两个目标)
|
||
├─ Dockerfile.local.dockerignore # 本地构建忽略表(覆盖根目录 .dockerignore)
|
||
├─ appsettings.local.json # 绕过 Nacos 的完整本地配置(覆盖进镜像)
|
||
└─ docker-compose-local-dev.md # 本说明文档
|
||
```
|