166 lines
6.3 KiB
YAML
166 lines
6.3 KiB
YAML
services:
|
||
# ============================================================
|
||
# 中间件层:Postgres / Redis / MinIO
|
||
# ============================================================
|
||
postgres:
|
||
image: postgres:17
|
||
container_name: echochat-postgres
|
||
environment:
|
||
POSTGRES_DB: ${POSTGRES_DB:-echochat}
|
||
POSTGRES_USER: ${POSTGRES_USER:-echochat}
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-echochat_dev_2026}
|
||
ports:
|
||
- "7432:5432"
|
||
volumes:
|
||
- pgdata:/var/lib/postgresql/data
|
||
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-echochat}"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 5
|
||
|
||
redis:
|
||
image: redis:7
|
||
container_name: echochat-redis
|
||
ports:
|
||
- "7379:6379"
|
||
volumes:
|
||
- redisdata:/data
|
||
- ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf
|
||
command: redis-server /usr/local/etc/redis/redis.conf
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "ping"]
|
||
interval: 5s
|
||
timeout: 5s
|
||
retries: 5
|
||
|
||
minio:
|
||
image: minio/minio:latest
|
||
container_name: echochat-minio
|
||
command: server /data --console-address ":9201"
|
||
ports:
|
||
- "9200:9000"
|
||
- "9201:9001"
|
||
environment:
|
||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-echochat}
|
||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-echochat123456}
|
||
volumes:
|
||
- minio_data:/data
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:9200/minio/health/live"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 5
|
||
restart: unless-stopped
|
||
|
||
# ============================================================
|
||
# 应用层:Go backend
|
||
# ============================================================
|
||
go-service:
|
||
build:
|
||
context: ../backend/go-service
|
||
dockerfile: Dockerfile
|
||
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:-}
|
||
# media-server 失败回调共享密钥:与 media-server 服务的 INTERNAL_WEBHOOK_SECRET 保持一致
|
||
# 未配置时 go-service 会拒绝所有 webhook(Forbidden),录制失败状态将无法及时落 failed
|
||
INTERNAL_WEBHOOK_SECRET: ${INTERNAL_WEBHOOK_SECRET:-internal-webhook-secret-change-me}
|
||
ports:
|
||
- "${GO_SERVICE_PORT:-8085}:8085"
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
redis:
|
||
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
|
||
network_mode: host
|
||
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:-internal-token-22xqs}
|
||
MEDIASOUP_LISTEN_IP: ${MEDIASOUP_LISTEN_IP:-0.0.0.0}
|
||
# 关键:公网部署时必须填服务器公网 IP,本机留空
|
||
MEDIASOUP_ANNOUNCED_IP: ${MEDIASOUP_ANNOUNCED_IP:-123.6.102.114}
|
||
MEDIASOUP_RTC_MIN_PORT: ${MEDIASOUP_RTC_MIN_PORT:-30000}
|
||
MEDIASOUP_RTC_MAX_PORT: ${MEDIASOUP_RTC_MAX_PORT:-30199}
|
||
MEDIASOUP_WORKER_LOG_LEVEL: warn
|
||
MEDIASOUP_MAX_ROUTERS: "200"
|
||
# 录制输出目录:与 host 路径保持一致,使 go-service(host 进程)可直接读取 ffmpeg 写出的 mp4
|
||
# 容器内路径 = host 路径,ffmpeg 写出的 outputPath 字符串可在两侧通用
|
||
RECORDING_OUTPUT_DIR: ${RECORDING_OUTPUT_DIR:-/home/ykf/jenkins/yuyin/data}
|
||
# ffmpeg 异常退出回调地址:media-server 容器使用 network_mode=host,可直连 host 上 go-service 的 8085 端口
|
||
# 路径与 backend/go-service/app/meeting/router.go 注册的 /internal/meeting/recordings/failure 一致
|
||
RECORDING_FAILURE_WEBHOOK_URL: ${RECORDING_FAILURE_WEBHOOK_URL:-http://127.0.0.1:8085/internal/meeting/recordings/failure}
|
||
# webhook 共享密钥:必须与 go-service 端 INTERNAL_WEBHOOK_SECRET 一致,否则 go-service 直接 403
|
||
INTERNAL_WEBHOOK_SECRET: ${INTERNAL_WEBHOOK_SECRET:-internal-webhook-secret-change-me}
|
||
volumes:
|
||
# 录制文件 host 共享卷:media-server 容器内 ffmpeg 写入此目录,go-service host 进程直接读
|
||
# 没有这条挂载时 go-service 会报 "stat ...: no such file or directory"
|
||
- ${RECORDING_OUTPUT_DIR:-/home/ykf/jenkins/yuyin/data}:${RECORDING_OUTPUT_DIR:-/home/ykf/jenkins/yuyin/data}
|
||
#ports:
|
||
# - "3300:3300"
|
||
# mediasoup RTC 流量端口范围(UDP + TCP 双栈,ICE-TCP fallback 用)
|
||
# - "30000-30199:40000-40199/udp"
|
||
# - "30000-30199: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"]
|
||
network_mode: host
|
||
command: >
|
||
-n
|
||
--log-file=stdout
|
||
--external-ip=123.6.102.114
|
||
--listening-ip=0.0.0.0
|
||
--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:-echochat}:${TURN_PASSWORD:-echochat_2026-1s32dswW@#}
|
||
--fingerprint
|
||
--lt-cred-mech
|
||
--no-multicast-peers
|
||
--cli=false
|
||
restart: unless-stopped
|
||
|
||
volumes:
|
||
pgdata:
|
||
redisdata:
|
||
minio_data:
|