deploy: add single-host cloud profile
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
*.md text eol=lf
|
*.md text eol=lf
|
||||||
*.html text eol=lf
|
*.html text eol=lf
|
||||||
*.css text eol=lf
|
*.css text eol=lf
|
||||||
|
*.conf text eol=lf
|
||||||
*.js text eol=lf
|
*.js text eol=lf
|
||||||
*.mjs text eol=lf
|
*.mjs text eol=lf
|
||||||
*.cjs text eol=lf
|
*.cjs text eol=lf
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ coverage*.out
|
|||||||
/coverage
|
/coverage
|
||||||
*.exe
|
*.exe
|
||||||
/opsconfig
|
/opsconfig
|
||||||
|
/deploy/server/.env
|
||||||
bin/
|
bin/
|
||||||
dist/
|
dist/
|
||||||
tmp/
|
tmp/
|
||||||
|
|||||||
@@ -18,12 +18,14 @@
|
|||||||
"redirectUris": [
|
"redirectUris": [
|
||||||
"http://localhost:3100/*",
|
"http://localhost:3100/*",
|
||||||
"http://127.0.0.1:3100/*",
|
"http://127.0.0.1:3100/*",
|
||||||
|
"http://121.41.46.238/*",
|
||||||
"http://localhost:5173/*",
|
"http://localhost:5173/*",
|
||||||
"http://127.0.0.1:5173/*"
|
"http://127.0.0.1:5173/*"
|
||||||
],
|
],
|
||||||
"webOrigins": [
|
"webOrigins": [
|
||||||
"http://localhost:3100",
|
"http://localhost:3100",
|
||||||
"http://127.0.0.1:3100",
|
"http://127.0.0.1:3100",
|
||||||
|
"http://121.41.46.238",
|
||||||
"http://localhost:5173",
|
"http://localhost:5173",
|
||||||
"http://127.0.0.1:5173"
|
"http://127.0.0.1:5173"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 阿里云单机演示部署
|
||||||
|
|
||||||
|
该配置用于单机公网演示,不是生产验收配置。只向公网发布HTTP 80;PostgreSQL、Redis、MinIO、Keycloak内部端口以及API/Worker端口均不映射到宿主机。真实RTC、模型、内容安全、HTTPS、云KMS、备份恢复和监控告警仍按阶段8验收清单执行。
|
||||||
|
|
||||||
|
服务器至少需要Docker Engine 29与Compose 2.40。首次部署先生成权限为600的服务器专用配置:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./deploy/server/bootstrap-secrets.sh \
|
||||||
|
http://SERVER_IP \
|
||||||
|
0.64.0-rc.cloud1 \
|
||||||
|
FULL_GIT_COMMIT \
|
||||||
|
2026-08-26T00:00:00Z
|
||||||
|
```
|
||||||
|
|
||||||
|
载入同一候选版本的`data-terminal-cloud-backend`和`data-terminal-cloud-web`镜像后执行:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker compose -f compose.yaml -f deploy/server/compose.override.yaml \
|
||||||
|
--env-file deploy/server/.env up -d --no-build \
|
||||||
|
postgres redis minio keycloak migrate seed mock-alert-receiver callbacks \
|
||||||
|
mock-provider api worker web gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
安全组和主机防火墙只保留TCP 80以及受限来源的SSH 22。使用域名前只能运行HTTP演示;正式环境必须配置域名、受信HTTPS证书、生产OIDC和真实外部服务,并切换到Kubernetes生产覆盖层。
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "$#" -ne 4 ]; then
|
||||||
|
echo "usage: $0 PUBLIC_ORIGIN VERSION COMMIT BUILD_TIME" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
public_origin=$1
|
||||||
|
build_version=$2
|
||||||
|
build_commit=$3
|
||||||
|
build_time=$4
|
||||||
|
public_host=${public_origin#http://}
|
||||||
|
public_host=${public_host#https://}
|
||||||
|
output_path=$(dirname "$0")/.env
|
||||||
|
|
||||||
|
if [ -e "$output_path" ]; then
|
||||||
|
echo "refusing to overwrite existing $output_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
umask 077
|
||||||
|
{
|
||||||
|
printf 'PUBLIC_ORIGIN=%s\n' "$public_origin"
|
||||||
|
printf 'PUBLIC_HOST=%s\n' "$public_host"
|
||||||
|
printf 'PLATFORM_BUILD_VERSION=%s\n' "$build_version"
|
||||||
|
printf 'PLATFORM_BUILD_COMMIT=%s\n' "$build_commit"
|
||||||
|
printf 'PLATFORM_BUILD_TIME=%s\n' "$build_time"
|
||||||
|
printf 'POSTGRES_PASSWORD=%s\n' "$(openssl rand -hex 24)"
|
||||||
|
printf 'REDIS_PASSWORD=%s\n' "$(openssl rand -hex 24)"
|
||||||
|
printf 'MINIO_ACCESS_KEY=%s\n' "$(openssl rand -hex 12)"
|
||||||
|
printf 'MINIO_SECRET_KEY=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'KEYCLOAK_ADMIN_USERNAME=platform-admin\n'
|
||||||
|
printf 'KEYCLOAK_ADMIN_PASSWORD=%s\n' "$(openssl rand -hex 24)"
|
||||||
|
printf 'DEVICE_LOCAL_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'RTC_TOKEN_SIGNING_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'CURSOR_SIGNING_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'SHARE_TOKEN_SIGNING_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'PROVIDER_CALLBACK_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
printf 'MOCK_PROVIDER_API_KEY=%s\n' "$(openssl rand -hex 24)"
|
||||||
|
printf 'ALERT_WEBHOOK_SECRET=%s\n' "$(openssl rand -hex 32)"
|
||||||
|
} > "$output_path"
|
||||||
|
|
||||||
|
chmod 600 "$output_path"
|
||||||
|
echo "created $output_path with mode 600"
|
||||||
|
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
x-server-backend-environment: &server-backend-environment
|
||||||
|
APP_ENV: local
|
||||||
|
LOG_LEVEL: info
|
||||||
|
DATABASE_URL: postgres://voice:${POSTGRES_PASSWORD}@postgres:5432/voice_platform?sslmode=disable
|
||||||
|
REDIS_ADDR: redis:6379
|
||||||
|
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||||
|
REDIS_DB: "0"
|
||||||
|
AUTH_ISSUER_URL: ${PUBLIC_ORIGIN}/realms/voice-local
|
||||||
|
AUTH_JWKS_URL: http://keycloak:8080/realms/voice-local/protocol/openid-connect/certs
|
||||||
|
AUTH_AUDIENCE: voice-platform-web
|
||||||
|
OTEL_EXPORTER_OTLP_ENDPOINT: ""
|
||||||
|
OBJECT_STORE_ENDPOINT: minio:9000
|
||||||
|
OBJECT_STORE_PUBLIC_ENDPOINT: ${PUBLIC_HOST}
|
||||||
|
OBJECT_STORE_ACCESS_KEY: ${MINIO_ACCESS_KEY}
|
||||||
|
OBJECT_STORE_SECRET_KEY: ${MINIO_SECRET_KEY}
|
||||||
|
OBJECT_STORE_EXPORT_BUCKET: private-exports
|
||||||
|
OBJECT_STORE_REGION: us-east-1
|
||||||
|
OBJECT_STORE_SECURE: "false"
|
||||||
|
CURSOR_SIGNING_SECRET: ${CURSOR_SIGNING_SECRET}
|
||||||
|
SHARE_TOKEN_SIGNING_SECRET: ${SHARE_TOKEN_SIGNING_SECRET}
|
||||||
|
EMBEDDING_PROVIDER: local
|
||||||
|
VOICE_PROVIDER: mock
|
||||||
|
|
||||||
|
services:
|
||||||
|
otel-collector:
|
||||||
|
ports: !reset []
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
ports: !reset []
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
ports: !reset []
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: voice_platform
|
||||||
|
POSTGRES_USER: voice
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
redis:
|
||||||
|
ports: !reset []
|
||||||
|
command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD}"]
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
minio:
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
|
||||||
|
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
ports: !reset []
|
||||||
|
command: ["start-dev", "--import-realm"]
|
||||||
|
environment:
|
||||||
|
KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN_USERNAME}
|
||||||
|
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
|
||||||
|
KC_HOSTNAME: ${PUBLIC_ORIGIN}
|
||||||
|
KC_HTTP_ENABLED: "true"
|
||||||
|
KC_PROXY_HEADERS: xforwarded
|
||||||
|
JAVA_OPTS_KC_HEAP: -Xms128m -Xmx384m
|
||||||
|
volumes:
|
||||||
|
- ./deploy/keycloak:/opt/keycloak/data/import:ro
|
||||||
|
- keycloak-data:/opt/keycloak/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
migrate:
|
||||||
|
command:
|
||||||
|
- -path=/migrations
|
||||||
|
- -database=postgres://voice:${POSTGRES_PASSWORD}@postgres:5432/voice_platform?sslmode=disable
|
||||||
|
- up
|
||||||
|
|
||||||
|
seed:
|
||||||
|
environment:
|
||||||
|
PGPASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|
||||||
|
api:
|
||||||
|
image: data-terminal-cloud-backend:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
<<: *server-backend-environment
|
||||||
|
HTTP_ADDR: 0.0.0.0:8080
|
||||||
|
DEVICE_LOCAL_SECRET: ${DEVICE_LOCAL_SECRET}
|
||||||
|
RTC_TOKEN_SIGNING_SECRET: ${RTC_TOKEN_SIGNING_SECRET}
|
||||||
|
RTC_TOKEN_ISSUER: local
|
||||||
|
RTC_APP_ID: local-public-rtc-app
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
callbacks:
|
||||||
|
image: data-terminal-cloud-backend:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
<<: *server-backend-environment
|
||||||
|
HTTP_ADDR: 0.0.0.0:8081
|
||||||
|
PROVIDER_CALLBACK_SECRET: ${PROVIDER_CALLBACK_SECRET}
|
||||||
|
RATE_LIMIT_RPS: "1000"
|
||||||
|
RATE_LIMIT_BURST: "1500"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
worker:
|
||||||
|
image: data-terminal-cloud-backend:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
<<: *server-backend-environment
|
||||||
|
HTTP_ADDR: 0.0.0.0:8082
|
||||||
|
MOCK_PROVIDER_BASE_URL: http://mock-provider:8083
|
||||||
|
MOCK_PROVIDER_API_KEY: ${MOCK_PROVIDER_API_KEY}
|
||||||
|
ALERT_WEBHOOK_URL: http://mock-alert-receiver:8084/webhooks/alerts
|
||||||
|
ALERT_WEBHOOK_SECRET: ${ALERT_WEBHOOK_SECRET}
|
||||||
|
CONTENT_GENERATOR: local
|
||||||
|
CONTENT_SAFETY_PROVIDER: local
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mock-provider:
|
||||||
|
image: data-terminal-cloud-backend:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
HTTP_ADDR: 0.0.0.0:8083
|
||||||
|
MOCK_PROVIDER_API_KEY: ${MOCK_PROVIDER_API_KEY}
|
||||||
|
MOCK_PROVIDER_CALLBACK_URL: http://callbacks:8081/callbacks/v1/vertc/voice-chat
|
||||||
|
PROVIDER_CALLBACK_SECRET: ${PROVIDER_CALLBACK_SECRET}
|
||||||
|
MOCK_PROVIDER_START_DELAY: 100ms
|
||||||
|
MOCK_PROVIDER_DUPLICATE_CALLBACKS: "2"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mock-alert-receiver:
|
||||||
|
image: data-terminal-cloud-backend:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
HTTP_ADDR: 0.0.0.0:8084
|
||||||
|
ALERT_WEBHOOK_SECRET: ${ALERT_WEBHOOK_SECRET}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
web:
|
||||||
|
image: data-terminal-cloud-web:${PLATFORM_BUILD_VERSION}
|
||||||
|
pull_policy: never
|
||||||
|
ports: !reset []
|
||||||
|
environment:
|
||||||
|
WEB_OIDC_AUTHORITY: ${PUBLIC_ORIGIN}/realms/voice-local
|
||||||
|
WEB_OIDC_CLIENT_ID: voice-platform-web
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
gateway:
|
||||||
|
image: nginx:1.30-alpine
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
volumes:
|
||||||
|
- ./deploy/server/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
- callbacks
|
||||||
|
- keycloak
|
||||||
|
- minio
|
||||||
|
- web
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
keycloak-data:
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
server_tokens off;
|
||||||
|
client_max_body_size 256m;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://api:8080;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /device/ {
|
||||||
|
proxy_pass http://api:8080;
|
||||||
|
proxy_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /callbacks/ {
|
||||||
|
proxy_pass http://callbacks:8081;
|
||||||
|
proxy_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /realms/ {
|
||||||
|
proxy_pass http://keycloak:8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /resources/ {
|
||||||
|
proxy_pass http://keycloak:8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /private-exports/ {
|
||||||
|
proxy_pass http://minio:9000;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
proxy_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://web:8080;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user