TeamMapper 0.4.0 Docker Compose 部署指南

Ubuntu 26.04 上以 ghcr 官方镜像 + PostgreSQL 15 部署 TeamMapper 0.4.0 的完整实测流程,含建图/协作/持久化端到端验证与运维命令。

TeamMapperTeamMapperDockerDocker Compose2026/11/02

TeamMapper 0.4.0 Docker Compose 部署指南

目标:在 Ubuntu 26.04 服务器上以 Docker Compose 从零部署 TeamMapper 0.4.0(ghcr 官方预构建镜像 + PostgreSQL 15),完成建图、协作、持久化全链路验证。本文所有命令与回显均为 2026-11-02 实测采集。

一、环境信息

  • 操作系统:Ubuntu 26.04.1 LTS(x86_64)
  • Docker:29.9.2,build a82e528
  • Docker Compose:v5.6.1
  • 应用:TeamMapper 0.4.0(镜像 ghcr.io/b310-digital/teammapper:latest,镜像创建时间 2026-10-28,对应官方 release v0.4.0-1)
  • 数据库:PostgreSQL 15(postgres:15-alpine,与官方 docker-compose-prod.yml 一致)
  • 对外端口:8144(映射到应用内部 3000)
  • 部署目录:/opt/teammapper/deploy/(服务器上自建)

二、镜像选型说明

TeamMapper 官方镜像只发布在 GitHub Container Registry(ghcr.io),Docker Hub 上的 teammapper/* 均非官方。可用形态对照:

形态来源说明
ghcr.io/b310-digital/teammapper:latest官方 README「Quick Start」推荐预构建,免编译,本文采用
ghcr.io/b310-digital/teammapper:v0.4.0-1官方 Releases 对应 tag锁版本生产建议
源码构建(docker-compose-prod.yml + Dockerfile)官方仓库需 clone 全仓库并 --build,构建链长

实测拉取(服务器直连 ghcr 成功,未走加速器):

docker pull ghcr.io/b310-digital/teammapper:latest
Digest: sha256:c565ceb598bd7ed31db8dd44b21882ea69c5f40be5d92f90f1db2d2bea98d5e6
Status: Downloaded newer image for ghcr.io/b310-digital/teammapper:latest
ghcr.io/b310-digital/teammapper:latest

⚠️ 网络说明:本环境访问 github.com 网页端存在被返回伪 404 页的情况,仓库页/README 取证需走 HTTP 代理;但 ghcr.io 镜像拉取实测直连可用,无需代理或加速器。若你的网络拉取 ghcr 超时,可为 Docker 守护进程配置代理或镜像加速后重试。

💡 说明:实测发现镜像内 /home/node/app/teammapper/package.json 的 version 字段为 0.1.9,与 release tag v0.4.0-1 不一致——这是上游 package.json 版本号未随 tag 同步的事实,不影响功能;核对部署版本应以 release tag 与镜像 digest 为准。

三、前置条件

  • 已安装 Docker 与 compose 插件(docker compose version 有输出即可)。
  • 目标端口未被占用:
ss -ltn | grep ':8144' || echo "8144 空闲"
8144 空闲
  • 建立部署目录与配置目录:
mkdir -p /opt/teammapper/deploy/config

四、部署步骤

4.1 编写 compose 文件

/opt/teammapper/deploy/docker-compose.yml(本文实测文件原样,基于官方 README Quick Start 改写端口与凭据):

name: teammapper-0.4.0-stack

services:
  app_prod:
    image: ghcr.io/b310-digital/teammapper:latest
    container_name: teammapper-0.4.0-app
    environment:
      MODE: PROD
      BINDING: "0.0.0.0"
      POSTGRES_DATABASE: teammapper-db
      POSTGRES_HOST: postgres_prod
      POSTGRES_PASSWORD: q1w2e3r4
      POSTGRES_PORT: 5432
      POSTGRES_SSL: "false"
      POSTGRES_SSL_REJECT_UNAUTHORIZED: "false"
      POSTGRES_USER: teammapper-user
      POSTGRES_QUERY_TIMEOUT: 100000
      POSTGRES_STATEMENT_TIMEOUT: 100000
      DELETE_AFTER_DAYS: 30
      LOG_LEVEL: log
      JWT_SECRET: tm-jwt-9f3a7c2e5b8d1460
    ports:
      - "8144:3000"
    depends_on:
      - postgres_prod
    volumes:
      - ./config/settings.override.json:/home/node/app/teammapper/config/settings.override.json:ro
    networks:
      - tmnet

  postgres_prod:
    image: postgres:15-alpine
    container_name: teammapper-0.4.0-db
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_DB: teammapper-db
      POSTGRES_PASSWORD: q1w2e3r4
      POSTGRES_PORT: 5432
      POSTGRES_USER: teammapper-user
    volumes:
      - postgres_prod_data:/var/lib/postgresql/data/pgdata
    networks:
      - tmnet

volumes:
  postgres_prod_data:

networks:
  tmnet:
    driver: bridge

关键项解说:

  • MODE: PROD:以生产配置(settings.prod.json)启动 NestJS 后端;官方 .env.default 注释说明 PROD 模式建议配数据库 SSL,无 SSL 时 Quick Start 示例仍用 MODE: PROD + POSTGRES_SSL: false,实测可正常启动。
  • BINDING: "0.0.0.0":应用默认只监听部分地址,显式绑全接口才能被端口映射访问。
  • POSTGRES_SSL_REJECT_UNAUTHORIZED: "false":连接自签名证书数据库时不校验证书链(官方 compose 默认值)。
  • JWT_SECRET:后端对 person_id cookie 做签名校验的密钥(auth/person-id.middleware),未设置时「我的导图列表」接口不认 cookie。
  • DELETE_AFTER_DAYS: 30:GDPR 默认保留期,到期由每日定时任务清理。
  • LOG_LEVEL: log:NestJS 日志级别,可选 error/warn/log/debug/verbose。
  • 应用内部监听 3000,宿主端口按实际环境改(本文用 8144)。

4.2 准备挂载配置文件

settings.override.json 是官方支持的运行时覆盖配置(详见 《TeamMapper 0.4.0 配置参数详解》),必须预先创建,否则 compose 会把它挂成目录:

echo '{}' > /opt/teammapper/deploy/config/settings.override.json

4.3 启动

cd /opt/teammapper/deploy && docker compose up -d

实测回显:

 Container teammapper-0.4.0-db Creating 
 Container teammapper-0.4.0-db Created 
 Container teammapper-0.4.0-app Creating 
 Container teammapper-0.4.0-app Created 
 Container teammapper-0.4.0-db Starting 
 Container teammapper-0.4.0-db Started 
 Container teammapper-0.4.0-app Starting 
 Container teammapper-0.4.0-app Started

4.4 验证服务

docker compose ps
NAME                   STATUS
teammapper-0.4.0-app   Up 12 seconds
teammapper-0.4.0-db    Up 12 seconds
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1:8144/
HTTP 200

后端启动日志确认路由与协作网关就绪(docker logs teammapper-0.4.0-app 节选,实测首尾):

[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RoutesResolver] MapsController {/api/maps}:
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps/:id, GET} route
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps, POST} route
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/maps/:id/duplicate, POST} route
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RoutesResolver] SettingsController {/api/settings}:
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [RouterExplorer] Mapped {/api/settings, GET} route
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [YjsGateway] Yjs WebSocket server started on /yjs
[Nest] 49  - 11/02/2026, 6:45:12 AM LOG [NestApplication] Nest application successfully started

浏览器访问 http://<服务器IP>:8144/ 即见 TeamMapper 首页(页面 <title>TeamMapper</title> 实测确认)。

4.5 端到端功能验证(建图 → 协作 → 持久化)

创建一张图(后端 REST 实测):

curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"rootNode":{"name":"E2E 中心主题","colors":{},"font":{},"image":{}}}' \
  http://127.0.0.1:8144/api/maps

响应节选(实测,字段完整):

{
  "map": {
    "uuid": "8f6b81e3-5d41-4b76-b811-6682b7dc6e07",
    "data": [ { "name": "E2E 中心主题", "isRoot": true, "id": "4195d165-e799-44da-971c-431e8d7a7b1a", "...": "..." } ],
    "deleteAfterDays": 30,
    "deletedAt": "2026-12-02T06:46:47.788Z"
  },
  "adminId": "d8558598-4bc3-4d87-b1d8-3df7c6da8d92",
  "modificationSecret": "c6237b28-48d5-4a20-8dbb-082c17137d19"
}

⚠️ 注意:rootNode 必须带 colors/font/image 三个对象字段(可为空对象),缺字段会 400。这是后端 valibot 严格 schema(MapCreateSchema)的实测行为,详见 《TeamMapper 0.4.0 API 使用详解》。

协作链路实测:用 Yjs 协议起两个 WebSocket 客户端(一个带 modificationSecret 可写、一个只读),可写端新增节点后,只读端 1.2 秒内收到广播;只读端尝试写入被服务端静默丢弃(实测回显):

[A] 初始节点: ["E2E 中心主题"]
[A] 已发送新增节点 update, 节点数: 2
[B] 收到广播后节点: ["协作新增节点-来自客户端A","E2E 中心主题"]
[B] 节点数: 2
[A] B写入后A侧节点数(应不变): 2
RESULT: COLLAB_OK

持久化验证(协作写入约 3 秒后从 REST 读取,确认已落 PostgreSQL):

curl -s http://127.0.0.1:8144/api/maps/8f6b81e3-5d41-4b76-b811-6682b7dc6e07 | python3 -c "import sys,json;d=json.load(sys.stdin);print('持久化后节点数:',len(d['data']),'节点名:',[n['name'] for n in d['data']])"
持久化后节点数: 2 节点名: ['E2E 中心主题', '协作新增节点-来自客户端A']

五、数据持久化说明

  • 导图数据全部在 PostgreSQL(postgres_prod_data 命名卷),应用本身无状态;Yjs 内存文档经防抖写库,实测写入后约 3 秒可查。
  • 备份即备份数据库:docker compose exec postgres_prod pg_dump -U teammapper-user teammapper-db > backup.sql。
  • 官方 README 提示:命名卷初始化后,.env.prod 里数据库相关变量再改动不会作用于已有库,需手工改库。
  • 单图 JSON 备份可走 API:GET /api/maps/<uuid>(带 x-map-modification-secret 头可重置保留计时)。

六、环境变量表

compose environment 支持的全部变量(来源:官方 README「Environment variable overrides」+ docker-compose-prod.yml 实测核对):

变量默认值说明
MODEDEVPROD 走生产配置;无数据库 SSL 时官方 Quick Start 也用 PROD+SSL false
BINDING—监听地址,容器内固定 0.0.0.0
POSTGRES_HOST/PORT/DATABASE/USER/PASSWORD—数据库连接五元组
POSTGRES_SSLtrue(prod compose)是否以 SSL 连库;Quick Start 内网直连置 false
POSTGRES_SSL_REJECT_UNAUTHORIZEDfalse自签证书时保持 false,官方建议生产用受信证书再置 true
POSTGRES_QUERY_TIMEOUT / POSTGRES_STATEMENT_TIMEOUT100000库侧查询/语句超时(毫秒)
DELETE_AFTER_DAYS30导图保留天数
LOG_LEVELlog(非 DEV)NestJS 日志级别
JWT_SECRET空person_id cookie 签名密钥
AI_ENABLEDfalseAI 生图开关
FEATURE_ARROWS未设(JSON 配置决定)置 true 强制开启节点间箭头功能
IMPRINT_URL / PRIVACY_URL未设首页页脚法务链接目标,未设则隐藏
PICTOGRAM_API_URL / PICTOGRAM_IMAGES_URLARASAAC 官方图标功能的上游代理地址

七、配置文件挂载

官方配置分三层(优先级由低到高):

  1. teammapper-backend/config/settings.dev.json / settings.prod.json:镜像内置默认值,改 settings.prod.json 需重新构建镜像;
  2. settings.override.json:挂载进 /home/node/app/teammapper/config/settings.override.json,运行时可改,覆盖 prod 配置——本文 compose 已挂载,参数详解见 《TeamMapper 0.4.0 配置参数详解》。

挂载生效实测:向 override 文件写入 systemSettings.urls.imprintUrl 后重启应用,GET /api/settings 返回中即出现该值:

curl -s http://127.0.0.1:8144/api/settings | python3 -c "import sys,json;d=json.load(sys.stdin);print('imprintUrl:',d['systemSettings']['urls'].get('imprintUrl'))"
imprintUrl: http://127.0.0.1:8144/imprint

八、等价 docker run

不想用 compose 时,两条 docker run 等价于上文 compose(官方 README Quick Start 的拆分形态;数据库参数须与上文一致):

docker network create teammapper-net
docker run -d --name teammapper-db --network teammapper-net \
  -e POSTGRES_DB=teammapper-db -e POSTGRES_USER=teammapper-user \
  -e POSTGRES_PASSWORD=q1w2e3r4 \
  -v teammapper-pgdata:/var/lib/postgresql/data postgres:15-alpine
docker run -d --name teammapper-app --network teammapper-net \
  -p 8144:3000 \
  -e MODE=PROD -e BINDING=0.0.0.0 \
  -e POSTGRES_HOST=teammapper-db -e POSTGRES_PORT=5432 \
  -e POSTGRES_DATABASE=teammapper-db -e POSTGRES_USER=teammapper-user \
  -e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_SSL=false \
  -e DELETE_AFTER_DAYS=30 -e JWT_SECRET=tm-jwt-9f3a7c2e5b8d1460 \
  ghcr.io/b310-digital/teammapper:latest

九、常用运维命令

cd /opt/teammapper/deploy
docker compose ps                     # 查看状态
docker compose logs -f app_prod       # 跟踪后端日志(含路由/WS 事件)
docker compose restart app_prod       # 改 settings.override.json 后重启生效
docker compose pull && docker compose up -d   # 升级:拉新镜像重建
docker compose down                   # 停止(保留数据卷)
docker compose down -v                # 停止并删卷(官方标注 DANGER,清空全部导图)

官方内置的运维任务(经 app 容器 pnpm 脚本执行,按需手工触发):

# 立即执行过期导图清理(平时每日 cron 自动跑)
docker compose exec app_prod pnpm --filter teammapper-backend run prod:data:maps:cleanup
# 清理无节点引用的图片(每日 01:00 UTC 自动)
docker compose exec app_prod pnpm --filter teammapper-backend run prod:data:images:cleanup
# 直接跑 SQL(TypeORM 数据源)
docker compose exec app_prod pnpm --filter teammapper-backend exec typeorm query "select count(*) from mmp_map" --dataSource ./dist/data-source.js

十、常见问题

Q1:docker pull ghcr.io/... 超时? ghcr 在部分网络环境不可直连。为 Docker 守护进程配置 HTTP 代理(/etc/systemd/system/docker.service.d/http-proxy.conf)或使用镜像加速后重试;本文实测环境直连成功。

Q2:起不来,日志报数据库连接失败? 核对 POSTGRES_* 五元组与 postgres_prod 服务的环境变量完全一致;compose 内服务名 postgres_prod 即 POSTGRES_HOST 的值。首次启动库初始化需数秒,app 会重试,可 docker compose restart app_prod。

Q3:settings.override.json 挂载后变成空目录? docker compose up 前宿主机文件不存在时,compose 会按路径创建目录。先 echo '{}' > config/settings.override.json 再启动(见 4.2)。

Q4:升级后旧图打不开? TeamMapper 前端/后端协议带版本子协议(teammapper.v2),旧版前端缓存连新后端会被 426 拒绝。强刷(Ctrl+F5)清掉浏览器缓存的旧前端即可;数据本身向后兼容(如节点内联图片双格式并存,官方 README)。

Q5:想永久保留导图? 把 DELETE_AFTER_DAYS 调大(如 3650)后 docker compose up -d 重建 app;注意已建图的 deletedAt 按创建时配置计算,历史图需改库或重新导入导出。

十一、参考链接

TeamMapper 0.4.0 Docker Compose 部署指南 - Quzuo