SAMA 0.37 Docker Compose 部署指南

以官方 docker-compose 形态从零部署 SAMA 0.37.2 全栈(sama-server 双节点 + sama-client 静态构建 + nginx 双端口入口 + MinIO + MongoDB 6.0.11 + Redis),覆盖 .env.docker 全量配置、数据库迁移、静态资源卷初始化两个必踩坑、注册/登录/频道/消息/文件全链路验证与数据持久化,2026-10-30 实测通过。

SAMA即时通讯SAMADockerdocker-compose安装部署2026/10/30

SAMA 0.37 Docker Compose 部署指南

目标:用官方主推的 Docker Compose 形态在单机部署一套可用的 SAMA 聊天服务(7 容器全栈),并完成注册、登录、频道、消息、文件上传下载的全链路验证。本文所有命令与回显均来自 2026-10-30 在 Ubuntu(Docker 28 + Compose v2)上的实测。SAMA 未提供原生二进制发行包,服务端以 Node.js 源码 + Docker 为唯一官方部署形态。组件背景见 《SAMA 0.37 介绍与选型指南》。

1. 前置条件

项要求(实测环境)
操作系统Ubuntu 22.04(任意可跑 Docker 的 Linux)
Docker / ComposeDocker 24+,Compose v2(docker compose version)
硬件2C4G 起步(7 容器全栈实测内存峰值约 1.5GB)
端口宿主机暴露 8161(Web 客户端)、8162(API/WS),可自行调整
网络构建期需访问 GitHub(client 容器克隆源码)与 npm registry

2. 获取源码与目录结构

git clone https://github.com/SAMA-Communications/sama-server.git
cd sama-server

关键文件(实测目录):

sama-server/
├── Dockerfile.local          # server 镜像:node:22 构建期 npm install,运行期 pm2-runtime
├── docker-compose.yml        # 官方全栈编排(extends prefs/docker-compose/services/*.yml)
├── prefs/
│   ├── client/Dockerfile.frontend   # client 镜像:alpine/git 克隆 sama-client → node:22 构建 → 静态产物
│   ├── nginx/Dockerfile.nginx       # nginx 镜像 + default.conf(upstream 双节点负载均衡)
│   └── docker-compose/services/     # frontend/backend/s3/db/push-daemon 分文件定义
├── migrations/               # migrate-mongo 迁移脚本(必须执行,见 §5 坑一)
└── pm2.config.cjs            # 容器内 PM2 集群配置

3. 编写 .env.docker(实测全量)

在 sama-server/ 根目录创建 .env.docker(server、s3、s3-service 共用),以下为实测通过的最小完整集,密钥请全部换成自己的随机值:

NODE_ENV=production
APP_PORT=9001

# MongoDB / Redis(容器网段 IP 或服务名,见 §4 静态 IP)
MONGODB_URL=mongodb://mongo/samadb
REDIS_URL=redis://redis:6379

# 对象存储:MinIO 驱动
STORAGE_DRIVER=minio
MINIO_ROOT_USER=<minio-root-user>
MINIO_ROOT_PASSWORD=<minio-root-password>
MINIO_ACCESS_KEY=<s3-service-账号-access-key>
MINIO_SECRET_KEY=<s3-service-账号-secret-key>
MINIO_BUCKET_NAME=samabucket
MINIO_USE_SSL=false

# 会话/消息预载与上限
CONVERSATION_MAX_PARTICIPANTS=50
CONVERSATION_PRELOAD_COUNT=30
MESSAGE_PRELOAD_COUNT=30
SEARCH_PRELOAD_COUNT=30

# JWT:access 3 小时,refresh 14 天
JWT_ACCESS_SECRET=<openssl rand -hex 32>
JWT_ACCESS_TOKEN_EXPIRES_IN=10800
JWT_REFRESH_SECRET=<openssl rand -hex 32>
JWT_REFRESH_TOKEN_EXPIRES_IN=12096000

# 加密消息/设备令牌 TTL(秒)
ENCRYPTION_MESSAGE_EXPIRED_IN=2592000
ENCRYPTION_DEVICE_TOKEN_EXPIRES_IN=2592000
OPERATIONS_LOG_EXPIRES_IN=1209600
NODE_CLUSTER_DATA_EXPIRES_IN=10000

# 文件预签名 URL 有效期(秒):上传 1h,下载 7d
FILE_UPLOAD_URL_EXPIRES_IN=3600
FILE_DOWNLOAD_URL_EXPIRES_IN=604800

SSL_KEY_FILE_NAME=
SSL_CERT_FILE_NAME=
CORS_ORIGIN=http://localhost:8162
COOKIE_SECRET=<openssl rand -hex 32>
HTTP_ADMIN_API_KEY=<管理端点 API Key>

MINIO_ROOT_USER/PASSWORD 是 MinIO 管理员;MINIO_ACCESS_KEY/SECRET_KEY 是给 SAMA server 用的服务账号(由 s3-service 容器用 mc admin user svcacct add 创建,见 §4)。两者必须不同。参数逐项含义见 《SAMA 0.37 配置参数详解》。

4. docker-compose.yml(实测可用的完整版)

官方 docker-compose.yml 使用 extends 组合,可直接使用;以下为展开后的等效关键结构(实测 IP 规划:mongo .4 / redis .5 / s3 .2,server 用服务名解析亦可):

services:
  sama-client:                 # 一次性构建容器
    build:
      context: ./prefs/client
      dockerfile: Dockerfile.frontend
      args:
        VITE_SOCKET_CONNECT: ws://localhost:8162   # 浏览器侧 WS 地址
        VITE_HTTP_CONNECT: http://localhost:8162   # 浏览器侧 HTTP 地址
        VITE_PUBLIC_VAPID_KEY: <WebPush 公钥>
        VITE_MESSAGES_COUNT_TO_PRELOAD: 30
        BRANCH: main                               # 锁定 client 分支
    volumes: [sama-client-dist:/dist]
    command: /bin/sh -c "cp -r /tmp/dist/* /dist && echo 'Static files are ready'"
  nginx:
    depends_on: [sama-client, sama-server]
    ports: ["8162:9000", "8161:10000"]             # 8162=API/WS(LB), 8161=Web SPA
    volumes: [sama-client-dist:/usr/share/nginx/html:ro]
    restart: always
  sama-server:
    build: { context: ., dockerfile: Dockerfile.local }
    depends_on: { mongo: { condition: service_healthy } }
    entrypoint: sh -c 'npm run start'
    volumes: [./.env.docker:/app/.env]
    environment: ["MINIO_ENDPOINT=s3", "MINIO_PORT=9000"]
    restart: always
  s3:
    image: minio/minio
    command: server --address 0.0.0.0:9000 --console-address :9001 /data
    volumes: [data:/data]
    env_file: [./.env.docker]
    healthcheck: { test: ["CMD", "mc", "ready", "local"], interval: 30s, retries: 3 }
  s3-service:                  # 一次性初始化容器
    image: minio/minio
    depends_on: { s3: { condition: service_healthy } }
    env_file: [./.env.docker]
    entrypoint: >
      /bin/sh -c "
      /usr/bin/mc alias set sama http://s3:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD};
      /usr/bin/mc mb --ignore-existing sama/samabucket;
      /usr/bin/mc policy set public sama/samabucket;
      /usr/bin/mc admin user svcacct add --access-key $${MINIO_ACCESS_KEY} --secret-key $${MINIO_SECRET_KEY} sama $${MINIO_ROOT_USER}"
  mongo:
    image: mongo:6.0.11
    volumes: [mongo:/data/db]
    environment: ["MONGO_INITDB_DATABASE=samadb"]
    healthcheck: { test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/samadb --quiet, interval: 30s, retries: 3 }
    restart: always
  redis:
    image: redis
    restart: always
volumes: { data: {}, mongo: {}, sama-client-dist: {} }

nginx 双 server 块(实测 prefs/nginx/default.conf):listen 9000 把 / 反代到 upstream loadbalance { server sama-server:9001; server sama-server:9002; }(带 Upgrade 头支持 WS);listen 10000 直接服务 SPA 静态文件并 try_files $uri /index.html。

启动:

docker compose up -d --build

实测构建约 8–15 分钟(client 的 npm install 是大头);7 个容器最终形态:

quzuo-sama-nginx-1         Up   0.0.0.0:8162->9000/tcp, 0.0.0.0:8161->10000/tcp
quzuo-sama-sama-server-1   Up   52403/tcp(内部 PM2 双节点 9001/9002)
quzuo-sama-s3-service-1    Exited (0)          # 一次性任务,正常退出
quzuo-sama-sama-client-1   Exited (0)          # 一次性构建,正常退出
quzuo-sama-s3-1            Up (healthy)
quzuo_sama_mongo           Up (healthy)
quzuo_sama_redis           Up

5. 两个必踩坑(实测踩坑实录)

坑一:必须手动执行数据库迁移,否则无法注册用户

首次启动后若直接注册,WS 返回 422 INCORRECT_LOGIN 类错误;查看数据库会发现 organizations 集合为空。SAMA 把生成 default 组织的工作放在 migrate-mongo 迁移里,镜像启动命令并不执行它。实测执行:

docker compose exec sama-server sh -c "cd /app && npm run migrate-mongo up"
# MIGRATED UP: 20240812113744-set-encrypted-key-indexes.js
# ...(共 20 个迁移)
# MIGRATED UP: 20260204123952-blocked-users-unique.js

验证:organizations 中出现 {_id: 'default', name: 'default'}。建议把这条命令加入首次部署清单或自定义 entrypoint。

坑二:client 容器只 echo 不拷贝,SPA 打开是 nginx 欢迎页

官方 prefs/docker-compose/services/frontend.yml 中 client 容器命令是 cp -r /tmp/dist/* /dist && echo 'Static files are ready';镜像本身把产物构建到 /tmp/dist 并声明 VOLUME /dist,但镜像内没有任何指令把 /tmp/dist 拷进 /dist——volume 内容完全依赖运行命令完成拷贝。若 compose 里写成了只 echo(或漏掉 command),8161 端口将一直是 nginx 默认欢迎页。实测补救(无需重新构建镜像):

docker run --rm -v <project>_sama-client-dist:/dist sama-sama-client \
  sh -c "cp -r /tmp/dist/* /dist/"
curl -s http://localhost:8161/ | grep -o '<title>[^<]*'   # → <title>SAMA

6. 全链路功能验证(2026-10-30 实测)

API 走 8162,Web 客户端打开 http://<host>:8161。用 wscat/Node ws 连 ws://<host>:8162 逐项验证(完整报文与回显见 《SAMA 0.37 API 详解》):

#动作实测结果
1GET /health{"status":"ok","hostname":"<容器ID>"}
2WS user_create 注册 alice/bob返回 response.user._id
3POST /login200,返回 access_token + Set-Cookie refresh_token
4WS connect(token+device_id){"response":{"success":true}}
5conversation_create type=c 频道返回频道 _id、subscribers_count:2
6WS message 发送{"ask":{"mid":"mid-001","server_mid":"...","t":...}}
7bob conversation_subscribe{"response":{"success":true}}
8bob message_list收到 alice 消息体
9create_files 申请上传 URL返回 upload_url(MinIO 预签名)
10HTTP PUT 上传文件到预签名 URL200
11get_file_urls 下载 URL返回 7 天有效期预签名 URL
12发送带附件消息ask.server_mid 返回,消息体含 attachments

7. 数据持久化与运维

  • 卷:data(MinIO 对象)、mongo(数据库)、sama-client-dist(前端静态文件)。备份 MongoDB 卷 + MinIO 卷即可完整恢复聊天数据。
  • 升级:git pull && docker compose up -d --build;跨版本先 npm run migrate-mongo status 确认迁移状态,再执行 up。
  • 重置:docker compose down -v 会连卷一起删除(含聊天记录),慎用。
  • HTTPS:公网部署建议在 nginx 前再加一层 TLS 或改写 Dockerfile.nginx 挂证书,并把 VITE_*_CONNECT 与 CORS_ORIGIN 改为 https:// 域名(Web Push 强制要求 HTTPS)。

参数如何调优继续阅读 《SAMA 0.37 配置参数详解》;API 对接阅读 《SAMA 0.37 API 详解》。