feat(deploy): Task 14 完成 docker-compose 扩展 + 环境变量双态部署
- deploy/docker-compose.dev.yml 新增 media-server 服务 + coturn(profiles:public),
全部服务参数改为 env 变量注入,go-service 依赖 media-server
- deploy/.env.example / .env.local.example / .env.public.example 三份模板,
公网模板用 _REPLACE_WITH_*_ 占位符防"示例值上生产"
- scripts/start.sh / stop.sh / status.sh 新增 full 子命令对接 docker compose --profile public
- scripts/deploy-public.sh 新建:env 校验 + 端口 checklist + Docker 自检 +
--profile public up -d --build + 健康检查闭环
- docs/deployment/meeting-mvp.md 新建:双态部署全流程 + 强密码生成 + 防火墙 + FAQ
- 双模式 docker compose config 校验通过;deploy-public.sh 三种错误场景按预期退出
同步更新 CURRENT_STATUS / implementation.plan / project-context
Task 0-14 ✅ / 剩余 Task 15-16
Made-with: Cursor
This commit is contained in:
76
deploy/.env.example
Normal file
76
deploy/.env.example
Normal file
@@ -0,0 +1,76 @@
|
||||
# ============================================================
|
||||
# EchoChat 部署环境变量示例(通用)
|
||||
# 本文件为主模板,含所有可配置项 + 默认值说明
|
||||
# 选择部署形态时请复制为 .env.local 或 .env.public,然后按需修改
|
||||
# ------------------------------------------------------------
|
||||
# 本机 Demo:cp deploy/.env.local.example deploy/.env
|
||||
# 公网部署:cp deploy/.env.public.example deploy/.env
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 1. 部署形态切换
|
||||
# ============================================================
|
||||
# 部署形态标识(仅用于人眼识别,不影响运行时)
|
||||
# 可选值:local | public
|
||||
DEPLOY_MODE=local
|
||||
|
||||
# ============================================================
|
||||
# 2. Postgres / Redis / MinIO(中间件)
|
||||
# ============================================================
|
||||
POSTGRES_DB=echochat
|
||||
POSTGRES_USER=echochat
|
||||
POSTGRES_PASSWORD=echochat_dev_2026
|
||||
|
||||
REDIS_PASSWORD=
|
||||
|
||||
MINIO_ROOT_USER=echochat
|
||||
MINIO_ROOT_PASSWORD=echochat123456
|
||||
|
||||
# ============================================================
|
||||
# 3. Go backend
|
||||
# ============================================================
|
||||
GO_SERVICE_PORT=8085
|
||||
# JWT 签名密钥(生产环境必须改)
|
||||
JWT_SECRET=echochat-dev-jwt-secret-2026-please-change-in-production
|
||||
|
||||
# ============================================================
|
||||
# 4. mediasoup 媒体服务器(Node)
|
||||
# ============================================================
|
||||
# Go ↔ Node 内部鉴权 token(生产必须改)
|
||||
MEDIA_INTERNAL_TOKEN=dev-internal-token-change-me
|
||||
|
||||
# mediasoup RTC 监听 IP:Docker 内部一律 0.0.0.0
|
||||
MEDIASOUP_LISTEN_IP=0.0.0.0
|
||||
|
||||
# mediasoup RTC 对外通告 IP(本决策见设计 §D01):
|
||||
# - 本机 Demo:留空(浏览器走 127.0.0.1 / 局域网 IP 直连)
|
||||
# - 公网部署:必须填 **服务器公网 IP** 或解析到公网 IP 的域名
|
||||
# 错误示例:127.0.0.1(远端浏览器只能拿到回环地址,无法建连)
|
||||
MEDIASOUP_ANNOUNCED_IP=
|
||||
|
||||
# mediasoup UDP/TCP 端口范围(MVP 200 端口足够 ~25 用户级 Transport)
|
||||
MEDIASOUP_RTC_MIN_PORT=40000
|
||||
MEDIASOUP_RTC_MAX_PORT=40199
|
||||
|
||||
# ============================================================
|
||||
# 5. coturn TURN 服务器(仅公网部署启用)
|
||||
# ============================================================
|
||||
# 是否启用 TURN(`docker compose --profile public up` 才拉起 coturn):
|
||||
# - 本机 Demo:false
|
||||
# - 公网部署:推荐 true(对称 NAT 用户的 fallback 通路)
|
||||
TURN_ENABLED=false
|
||||
|
||||
# coturn 提供的 realm、用户名、密码
|
||||
# 生产务必改,TURN 账号泄漏可被滥用
|
||||
TURN_REALM=echochat
|
||||
TURN_USERNAME=echouser
|
||||
TURN_PASSWORD=echopass
|
||||
|
||||
# TURN 外部监听端口(标准 3478 STUN/TURN,5349 TLS)
|
||||
# coturn 走 network_mode: host,端口一般沿用默认
|
||||
TURN_LISTEN_PORT=3478
|
||||
TURN_TLS_PORT=5349
|
||||
|
||||
# TURN 为中继流量分配的端口范围
|
||||
TURN_MIN_PORT=49160
|
||||
TURN_MAX_PORT=49200
|
||||
32
deploy/.env.local.example
Normal file
32
deploy/.env.local.example
Normal file
@@ -0,0 +1,32 @@
|
||||
# ============================================================
|
||||
# EchoChat 本机 Demo 部署环境变量(默认值,即装即用)
|
||||
# 用法:cp deploy/.env.local.example deploy/.env
|
||||
# 说明:此模式下 coturn 不启动(需同一局域网 / 直连 IP 可达即可)
|
||||
# ============================================================
|
||||
|
||||
DEPLOY_MODE=local
|
||||
|
||||
# ---- 中间件(与 docker-compose.dev.yml 默认值一致,通常无需修改)----
|
||||
POSTGRES_DB=echochat
|
||||
POSTGRES_USER=echochat
|
||||
POSTGRES_PASSWORD=echochat_dev_2026
|
||||
|
||||
REDIS_PASSWORD=
|
||||
|
||||
MINIO_ROOT_USER=echochat
|
||||
MINIO_ROOT_PASSWORD=echochat123456
|
||||
|
||||
# ---- Go backend ----
|
||||
GO_SERVICE_PORT=8085
|
||||
JWT_SECRET=echochat-dev-jwt-secret-2026-please-change-in-production
|
||||
|
||||
# ---- mediasoup ----
|
||||
# 本机 Demo 不用跨公网,announcedIp 留空让 mediasoup 自动探测即可
|
||||
MEDIA_INTERNAL_TOKEN=dev-internal-token-change-me
|
||||
MEDIASOUP_LISTEN_IP=0.0.0.0
|
||||
MEDIASOUP_ANNOUNCED_IP=
|
||||
MEDIASOUP_RTC_MIN_PORT=40000
|
||||
MEDIASOUP_RTC_MAX_PORT=40199
|
||||
|
||||
# ---- TURN 关闭 ----
|
||||
TURN_ENABLED=false
|
||||
75
deploy/.env.public.example
Normal file
75
deploy/.env.public.example
Normal file
@@ -0,0 +1,75 @@
|
||||
# ============================================================
|
||||
# EchoChat 公网部署环境变量示例
|
||||
# 用法:cp deploy/.env.public.example deploy/.env
|
||||
# 然后修改下面的 MEDIASOUP_ANNOUNCED_IP / TURN_* / 所有密码
|
||||
# 启动:scripts/deploy-public.sh(会校验关键参数 + 开 public profile)
|
||||
# ============================================================
|
||||
|
||||
DEPLOY_MODE=public
|
||||
|
||||
# ============================================================
|
||||
# 中间件(生产环境 MUST 修改密码)
|
||||
# ============================================================
|
||||
POSTGRES_DB=echochat
|
||||
POSTGRES_USER=echochat
|
||||
POSTGRES_PASSWORD=_REPLACE_WITH_STRONG_PG_PASSWORD_
|
||||
|
||||
REDIS_PASSWORD=_REPLACE_WITH_STRONG_REDIS_PASSWORD_
|
||||
|
||||
MINIO_ROOT_USER=echochat
|
||||
MINIO_ROOT_PASSWORD=_REPLACE_WITH_STRONG_MINIO_PASSWORD_
|
||||
|
||||
# ============================================================
|
||||
# Go backend
|
||||
# ============================================================
|
||||
GO_SERVICE_PORT=8085
|
||||
# MUST 替换为随机 64 字符字符串;生产可用 openssl rand -hex 32
|
||||
JWT_SECRET=_REPLACE_WITH_RANDOM_64_CHAR_SECRET_
|
||||
|
||||
# ============================================================
|
||||
# mediasoup(关键:MEDIASOUP_ANNOUNCED_IP 必填)
|
||||
# ============================================================
|
||||
# Go ↔ Node 内部 token,必须与 media-server/.env 一致
|
||||
MEDIA_INTERNAL_TOKEN=_REPLACE_WITH_SECURE_INTERNAL_TOKEN_
|
||||
|
||||
MEDIASOUP_LISTEN_IP=0.0.0.0
|
||||
|
||||
# ⚠️ 必填:填服务器的**公网 IP** 或解析到公网 IP 的域名 A 记录
|
||||
# 示例:MEDIASOUP_ANNOUNCED_IP=203.0.113.42
|
||||
# 留空会导致远端浏览器只能拿到局域网/回环地址,完全建不连
|
||||
MEDIASOUP_ANNOUNCED_IP=
|
||||
|
||||
MEDIASOUP_RTC_MIN_PORT=40000
|
||||
MEDIASOUP_RTC_MAX_PORT=40199
|
||||
|
||||
# ============================================================
|
||||
# TURN 开启(公网对称 NAT fallback 必备)
|
||||
# ============================================================
|
||||
TURN_ENABLED=true
|
||||
|
||||
TURN_REALM=echochat
|
||||
# MUST 改密码,否则 TURN 可能被互联网匿名中继流量滥用
|
||||
TURN_USERNAME=_REPLACE_WITH_TURN_USERNAME_
|
||||
TURN_PASSWORD=_REPLACE_WITH_STRONG_TURN_PASSWORD_
|
||||
|
||||
TURN_LISTEN_PORT=3478
|
||||
TURN_TLS_PORT=5349
|
||||
TURN_MIN_PORT=49160
|
||||
TURN_MAX_PORT=49200
|
||||
|
||||
# ============================================================
|
||||
# 公网部署 checklist(启动前必查)
|
||||
# ------------------------------------------------------------
|
||||
# 1. 所有 _REPLACE_WITH_*_ 占位符都已替换为真实强密码
|
||||
# 2. MEDIASOUP_ANNOUNCED_IP 已设置为服务器公网 IP
|
||||
# 3. 云安全组/iptables 放通以下端口:
|
||||
# - TCP 8085 Go backend API
|
||||
# - TCP 5173 前端用户端(如单独暴露)
|
||||
# - UDP 40000-40199 mediasoup RTC 流量
|
||||
# - TCP 40000-40199 mediasoup ICE-TCP fallback
|
||||
# - UDP 3478 coturn STUN/TURN
|
||||
# - TCP 3478 coturn
|
||||
# - TCP 5349 coturn TLS
|
||||
# - UDP 49160-49200 coturn 中继流量
|
||||
# 4. scripts/deploy-public.sh 会自动进行一轮参数 + 端口校验
|
||||
# ============================================================
|
||||
@@ -1,18 +1,21 @@
|
||||
services:
|
||||
# ============================================================
|
||||
# 中间件层:Postgres / Redis / MinIO
|
||||
# ============================================================
|
||||
postgres:
|
||||
image: postgres:17
|
||||
container_name: echochat-postgres
|
||||
environment:
|
||||
POSTGRES_DB: echochat
|
||||
POSTGRES_USER: echochat
|
||||
POSTGRES_PASSWORD: echochat_dev_2026
|
||||
POSTGRES_DB: ${POSTGRES_DB:-echochat}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-echochat}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-echochat_dev_2026}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U echochat"]
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-echochat}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -40,8 +43,8 @@ services:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: echochat
|
||||
MINIO_ROOT_PASSWORD: echochat123456
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-echochat}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-echochat123456}
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
healthcheck:
|
||||
@@ -51,6 +54,9 @@ services:
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# 应用层:Go backend
|
||||
# ============================================================
|
||||
go-service:
|
||||
build:
|
||||
context: ../backend/go-service
|
||||
@@ -58,8 +64,11 @@ services:
|
||||
container_name: echochat-go-service
|
||||
environment:
|
||||
CONFIG_NAME: config.docker
|
||||
# 透传关键环境变量,config.docker.yaml 内部引用(可选覆盖)
|
||||
ECHOCHAT_JWT_SECRET: ${JWT_SECRET:-}
|
||||
ECHOCHAT_MEDIA_SERVER_INTERNAL_TOKEN: ${MEDIA_INTERNAL_TOKEN:-}
|
||||
ports:
|
||||
- "8085:8085"
|
||||
- "${GO_SERVICE_PORT:-8085}:8085"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
@@ -67,6 +76,73 @@ services:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
condition: service_healthy
|
||||
media-server:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# 媒体层:mediasoup Node SFU
|
||||
# ============================================================
|
||||
media-server:
|
||||
build:
|
||||
context: ../media-server
|
||||
dockerfile: Dockerfile
|
||||
container_name: echochat-media-server
|
||||
environment:
|
||||
HTTP_HOST: 0.0.0.0
|
||||
HTTP_PORT: 3300
|
||||
LOG_LEVEL: info
|
||||
LOG_PRETTY: "false"
|
||||
MEDIA_INTERNAL_TOKEN: ${MEDIA_INTERNAL_TOKEN:-dev-internal-token-change-me}
|
||||
MEDIASOUP_LISTEN_IP: ${MEDIASOUP_LISTEN_IP:-0.0.0.0}
|
||||
# 关键:公网部署时必须填服务器公网 IP,本机留空
|
||||
MEDIASOUP_ANNOUNCED_IP: ${MEDIASOUP_ANNOUNCED_IP:-}
|
||||
MEDIASOUP_RTC_MIN_PORT: ${MEDIASOUP_RTC_MIN_PORT:-40000}
|
||||
MEDIASOUP_RTC_MAX_PORT: ${MEDIASOUP_RTC_MAX_PORT:-40199}
|
||||
MEDIASOUP_WORKER_LOG_LEVEL: warn
|
||||
MEDIASOUP_MAX_ROUTERS: "200"
|
||||
ports:
|
||||
- "3300:3300"
|
||||
# mediasoup RTC 流量端口范围(UDP + TCP 双栈,ICE-TCP fallback 用)
|
||||
- "40000-40199:40000-40199/udp"
|
||||
- "40000-40199:40000-40199/tcp"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:3300/healthz"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
start_period: 15s
|
||||
retries: 3
|
||||
restart: unless-stopped
|
||||
|
||||
# ============================================================
|
||||
# TURN 层:coturn(仅公网部署,profiles=public 才启动)
|
||||
# ------------------------------------------------------------
|
||||
# 本机 Demo 默认不拉起(coturn 在 profiles 里)
|
||||
# 公网部署:docker compose --profile public up -d
|
||||
# 或使用 scripts/deploy-public.sh 一键启动
|
||||
# ============================================================
|
||||
coturn:
|
||||
image: coturn/coturn:latest
|
||||
container_name: echochat-coturn
|
||||
profiles: ["public"]
|
||||
# TURN 一般需要 host 网络以便对外中继(端口映射模式会遇到
|
||||
# coturn 回包端口被 Docker NAT 改写的问题)
|
||||
network_mode: host
|
||||
command: >
|
||||
-n
|
||||
--log-file=stdout
|
||||
--listening-port=${TURN_LISTEN_PORT:-3478}
|
||||
--tls-listening-port=${TURN_TLS_PORT:-5349}
|
||||
--min-port=${TURN_MIN_PORT:-49160}
|
||||
--max-port=${TURN_MAX_PORT:-49200}
|
||||
--realm=${TURN_REALM:-echochat}
|
||||
--user=${TURN_USERNAME:-echouser}:${TURN_PASSWORD:-echopass}
|
||||
--fingerprint
|
||||
--lt-cred-mech
|
||||
--no-multicast-peers
|
||||
--no-cli
|
||||
--no-tlsv1
|
||||
--no-tlsv1_1
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
|
||||
Reference in New Issue
Block a user