- Finnhub: Add missing /test endpoint - AlphaVantage: Fix test endpoint deserialization (handle null api_url) - Mock Provider: Add /test endpoint and fix Zodios validation error by adding Mock enum - Deployment: Remove Mock Provider from production deployment script - Infrastructure: Add production Dockerfiles and compose configs
340 lines
9.8 KiB
Bash
340 lines
9.8 KiB
Bash
#!/bin/bash
|
|
|
|
# 遇到错误立即退出
|
|
set -e
|
|
|
|
# 配置变量
|
|
REGISTRY="harbor.3prism.ai"
|
|
PROJECT="fundamental_analysis"
|
|
VERSION="latest"
|
|
NAMESPACE="$REGISTRY/$PROJECT"
|
|
|
|
# 颜色输出
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${GREEN}=== 开始构建并推送镜像到 $NAMESPACE ===${NC}"
|
|
|
|
# 定义服务列表
|
|
# 格式: "服务名:Dockerfile路径"
|
|
# 注意:所有的后端服务现在都使用通用的 docker/Dockerfile.backend.prod
|
|
SERVICES=(
|
|
"data-persistence-service:docker/Dockerfile.backend.prod"
|
|
"api-gateway:docker/Dockerfile.backend.prod"
|
|
"alphavantage-provider-service:docker/Dockerfile.backend.prod"
|
|
"tushare-provider-service:docker/Dockerfile.backend.prod"
|
|
"finnhub-provider-service:docker/Dockerfile.backend.prod"
|
|
"yfinance-provider-service:docker/Dockerfile.backend.prod"
|
|
"report-generator-service:docker/Dockerfile.backend.prod"
|
|
"workflow-orchestrator-service:docker/Dockerfile.backend.prod"
|
|
"mock-provider-service:docker/Dockerfile.backend.prod"
|
|
"frontend:docker/Dockerfile.frontend.prod"
|
|
)
|
|
|
|
# 总大小计数器
|
|
TOTAL_SIZE=0
|
|
|
|
for entry in "${SERVICES[@]}"; do
|
|
KEY="${entry%%:*}"
|
|
DOCKERFILE="${entry#*:}"
|
|
IMAGE_NAME="$NAMESPACE/$KEY:$VERSION"
|
|
|
|
echo -e "\n${YELLOW}>>> 正在构建 $KEY ...${NC}"
|
|
echo "使用 Dockerfile: $DOCKERFILE"
|
|
|
|
# 构建镜像
|
|
if [ "$KEY" == "frontend" ]; then
|
|
# 前端不需要 SERVICE_NAME build-arg
|
|
docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" .
|
|
elif [ "$KEY" == "data-persistence-service" ]; then
|
|
# 特殊处理 data-persistence-service 的二进制名称差异
|
|
docker build -t "$IMAGE_NAME" --build-arg SERVICE_NAME="data-persistence-service-server" -f "$DOCKERFILE" .
|
|
else
|
|
# 后端服务需要传递 SERVICE_NAME
|
|
docker build -t "$IMAGE_NAME" --build-arg SERVICE_NAME="$KEY" -f "$DOCKERFILE" .
|
|
fi
|
|
|
|
# 获取镜像大小 (MB)
|
|
SIZE_BYTES=$(docker inspect "$IMAGE_NAME" --format='{{.Size}}')
|
|
SIZE_MB=$(echo "scale=2; $SIZE_BYTES / 1024 / 1024" | bc)
|
|
|
|
echo -e "${GREEN}√ $KEY 构建完成. 大小: ${SIZE_MB} MB${NC}"
|
|
|
|
# 累加大小
|
|
TOTAL_SIZE=$(echo "$TOTAL_SIZE + $SIZE_BYTES" | bc)
|
|
|
|
echo -e "${YELLOW}>>> 正在推送 $KEY 到 Harbor ...${NC}"
|
|
docker push "$IMAGE_NAME"
|
|
done
|
|
|
|
TOTAL_SIZE_MB=$(echo "scale=2; $TOTAL_SIZE / 1024 / 1024" | bc)
|
|
echo -e "\n${GREEN}=== 所有镜像处理完成 ===${NC}"
|
|
echo -e "${GREEN}总大小: ${TOTAL_SIZE_MB} MB${NC}"
|
|
|
|
|
|
# 生成服务器使用的 docker-compose.server.yml
|
|
echo -e "\n${YELLOW}>>> 正在生成服务器部署文件 docker-compose.server.yml ...${NC}"
|
|
|
|
# 基于 docker-compose.prod.yml 生成,但是替换 build 为 image
|
|
# 这里我们直接手动定义,因为解析 yaml 替换比较复杂,且我们清楚结构
|
|
|
|
cat > docker-compose.server.yml <<EOF
|
|
services:
|
|
postgres-db:
|
|
image: timescale/timescaledb:2.15.2-pg16
|
|
container_name: fundamental-postgres
|
|
command: -c shared_preload_libraries=timescaledb
|
|
environment:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: fundamental
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres -d fundamental"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
nats:
|
|
image: nats:2.9
|
|
container_name: fundamental-nats
|
|
volumes:
|
|
- nats_data:/data
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
data-persistence-service:
|
|
image: $NAMESPACE/data-persistence-service:$VERSION
|
|
container_name: data-persistence-service
|
|
environment:
|
|
HOST: 0.0.0.0
|
|
PORT: 3000
|
|
DATABASE_URL: postgresql://postgres:postgres@postgres-db:5432/fundamental
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
SKIP_MIGRATIONS_ON_MISMATCH: "1"
|
|
depends_on:
|
|
postgres-db:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "curl -fsS http://localhost:3000/health >/dev/null || exit 1"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
api-gateway:
|
|
image: $NAMESPACE/api-gateway:$VERSION
|
|
container_name: api-gateway
|
|
environment:
|
|
SERVER_PORT: 4000
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
REPORT_GENERATOR_SERVICE_URL: http://report-generator-service:8004
|
|
RUST_LOG: info,axum=info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
nats:
|
|
condition: service_started
|
|
data-persistence-service:
|
|
condition: service_healthy
|
|
networks:
|
|
- app-network
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "curl -fsS http://localhost:4000/health >/dev/null || exit 1"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
restart: always
|
|
|
|
mock-provider-service:
|
|
image: $NAMESPACE/mock-provider-service:$VERSION
|
|
container_name: mock-provider-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8006
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
API_GATEWAY_URL: http://api-gateway:4000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
SERVICE_HOST: mock-provider-service
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
alphavantage-provider-service:
|
|
image: $NAMESPACE/alphavantage-provider-service:$VERSION
|
|
container_name: alphavantage-provider-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8000
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
API_GATEWAY_URL: http://api-gateway:4000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
SERVICE_HOST: alphavantage-provider-service
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
tushare-provider-service:
|
|
image: $NAMESPACE/tushare-provider-service:$VERSION
|
|
container_name: tushare-provider-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8001
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
TUSHARE_API_URL: http://api.waditu.com
|
|
API_GATEWAY_URL: http://api-gateway:4000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
SERVICE_HOST: tushare-provider-service
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
finnhub-provider-service:
|
|
image: $NAMESPACE/finnhub-provider-service:$VERSION
|
|
container_name: finnhub-provider-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8002
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
FINNHUB_API_URL: https://finnhub.io/api/v1
|
|
API_GATEWAY_URL: http://api-gateway:4000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
SERVICE_HOST: finnhub-provider-service
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
yfinance-provider-service:
|
|
image: $NAMESPACE/yfinance-provider-service:$VERSION
|
|
container_name: yfinance-provider-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8003
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
API_GATEWAY_URL: http://api-gateway:4000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
SERVICE_HOST: yfinance-provider-service
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
dns:
|
|
- 8.8.8.8
|
|
- 8.8.4.4
|
|
restart: always
|
|
|
|
report-generator-service:
|
|
image: $NAMESPACE/report-generator-service:$VERSION
|
|
container_name: report-generator-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8004
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
GOTENBERG_URL: http://gotenberg:3000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
- gotenberg
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
workflow-orchestrator-service:
|
|
image: $NAMESPACE/workflow-orchestrator-service:$VERSION
|
|
container_name: workflow-orchestrator-service
|
|
volumes:
|
|
- workflow_data:/mnt/workflow_data
|
|
environment:
|
|
SERVER_PORT: 8005
|
|
NATS_ADDR: nats://nats:4222
|
|
DATA_PERSISTENCE_SERVICE_URL: http://data-persistence-service:3000
|
|
WORKFLOW_DATA_PATH: /mnt/workflow_data
|
|
RUST_LOG: info
|
|
RUST_BACKTRACE: "1"
|
|
depends_on:
|
|
- nats
|
|
- data-persistence-service
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
gotenberg:
|
|
image: gotenberg/gotenberg:8
|
|
container_name: gotenberg
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
frontend:
|
|
image: $NAMESPACE/frontend:$VERSION
|
|
container_name: fundamental-frontend
|
|
ports:
|
|
- "8080:80" # Map host 8080 to container 80 (Nginx)
|
|
depends_on:
|
|
api-gateway:
|
|
condition: service_healthy
|
|
networks:
|
|
- app-network
|
|
restart: always
|
|
|
|
volumes:
|
|
workflow_data:
|
|
pgdata:
|
|
nats_data:
|
|
|
|
networks:
|
|
app-network:
|
|
EOF
|
|
|
|
echo -e "${GREEN}生成完成: docker-compose.server.yml${NC}"
|
|
echo -e "请将此文件复制到远程服务器,并执行: docker-compose -f docker-compose.server.yml up -d"
|
|
|