f151747d56
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled
327 lines
10 KiB
Bash
Executable File
327 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# deploy-docker.sh — Deploy Stonks Oracle to a Docker host via SSH
|
|
#
|
|
# Usage: bash deploy-docker.sh [OPTIONS]
|
|
#
|
|
# Options:
|
|
# --host USER@HOST SSH target (default: celes@192.168.42.254)
|
|
# --ollama-url URL Ollama API URL (default: auto-detect or install)
|
|
# --ollama-model MODEL Ollama model name (default: qwen3.5:9b-fast)
|
|
# --dir PATH Remote install directory (default: ~/stonks-oracle)
|
|
#
|
|
# Examples:
|
|
# bash deploy-docker.sh
|
|
# bash deploy-docker.sh --ollama-url http://10.1.1.12:2701 --ollama-model qwen3.6
|
|
# bash deploy-docker.sh --host user@myserver --dir /opt/stonks
|
|
|
|
# -------------------------------------------------------
|
|
# Configuration (override via flags or environment)
|
|
# -------------------------------------------------------
|
|
REMOTE_HOST="${DEPLOY_HOST:-celes@192.168.42.254}"
|
|
REMOTE_DIR="${DEPLOY_DIR:-/home/celes/stonks-oracle}"
|
|
OLLAMA_URL="${DEPLOY_OLLAMA_URL:-}"
|
|
OLLAMA_MODEL="${DEPLOY_OLLAMA_MODEL:-qwen3.5:9b-fast}"
|
|
REPO_URL="http://admin:St0nks0racl3!@10.1.1.12:30300/admin/stonks-oracle.git"
|
|
|
|
# Parse command-line flags
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--host) REMOTE_HOST="$2"; shift 2 ;;
|
|
--ollama-url) OLLAMA_URL="$2"; shift 2 ;;
|
|
--ollama-model) OLLAMA_MODEL="$2"; shift 2 ;;
|
|
--dir) REMOTE_DIR="$2"; shift 2 ;;
|
|
*) echo "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
echo "=== Stonks Oracle Docker Deployment ==="
|
|
echo " Target: ${REMOTE_HOST}:${REMOTE_DIR}"
|
|
echo " Model: ${OLLAMA_MODEL}"
|
|
echo " Ollama: ${OLLAMA_URL:-auto-detect}"
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 1: Clone or update the repo on the remote host
|
|
# -------------------------------------------------------
|
|
echo "--- Step 1: Syncing repository ---"
|
|
ssh "$REMOTE_HOST" bash -s -- "$REMOTE_DIR" "$REPO_URL" <<'REMOTE_SCRIPT'
|
|
set -euo pipefail
|
|
REMOTE_DIR="$1"
|
|
REPO_URL="$2"
|
|
|
|
if [ -d "$REMOTE_DIR/.git" ]; then
|
|
echo " Updating existing repo..."
|
|
cd "$REMOTE_DIR"
|
|
git fetch origin
|
|
git reset --hard origin/main
|
|
else
|
|
echo " Cloning fresh..."
|
|
git clone "$REPO_URL" "$REMOTE_DIR"
|
|
cd "$REMOTE_DIR"
|
|
fi
|
|
|
|
echo " ✓ Repo synced at $(git log --oneline -1)"
|
|
REMOTE_SCRIPT
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 2: Detect or configure Ollama
|
|
# -------------------------------------------------------
|
|
echo "--- Step 2: Configuring Ollama ---"
|
|
if [ -z "$OLLAMA_URL" ]; then
|
|
# Auto-detect: check if Ollama is running on the remote host
|
|
OLLAMA_URL=$(ssh "$REMOTE_HOST" bash -s <<'DETECT_SCRIPT'
|
|
# Check common Ollama ports
|
|
for port in 11434 2701; do
|
|
if curl -sf --connect-timeout 2 "http://localhost:$port/api/tags" > /dev/null 2>&1; then
|
|
echo "http://localhost:$port"
|
|
exit 0
|
|
fi
|
|
done
|
|
echo ""
|
|
DETECT_SCRIPT
|
|
)
|
|
|
|
if [ -n "$OLLAMA_URL" ]; then
|
|
echo " ✓ Found existing Ollama at: $OLLAMA_URL"
|
|
else
|
|
echo " No Ollama detected — will use Docker container"
|
|
OLLAMA_URL="http://ollama:11434"
|
|
fi
|
|
else
|
|
echo " Using provided Ollama URL: $OLLAMA_URL"
|
|
fi
|
|
|
|
# Determine if we need the Docker Ollama container
|
|
USE_DOCKER_OLLAMA=false
|
|
if [ "$OLLAMA_URL" = "http://ollama:11434" ]; then
|
|
USE_DOCKER_OLLAMA=true
|
|
fi
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 3: Create .env and compose override
|
|
# -------------------------------------------------------
|
|
echo "--- Step 3: Configuring environment ---"
|
|
ssh "$REMOTE_HOST" bash -s -- "$REMOTE_DIR" "$OLLAMA_URL" "$OLLAMA_MODEL" "$USE_DOCKER_OLLAMA" <<'REMOTE_SCRIPT'
|
|
set -euo pipefail
|
|
REMOTE_DIR="$1"
|
|
OLLAMA_URL="$2"
|
|
OLLAMA_MODEL="$3"
|
|
USE_DOCKER_OLLAMA="$4"
|
|
cd "$REMOTE_DIR"
|
|
|
|
# Read API keys from local files if they exist
|
|
POLYGON_KEY=""
|
|
ALPACA_KEY=""
|
|
ALPACA_SECRET=""
|
|
ALPACA_URL="https://paper-api.alpaca.markets"
|
|
|
|
[ -f polygon.io.key ] && POLYGON_KEY=$(cat polygon.io.key)
|
|
[ -f alpaca.key ] && ALPACA_KEY=$(cat alpaca.key)
|
|
[ -f alpaca.secret ] && ALPACA_SECRET=$(cat alpaca.secret)
|
|
[ -f alpaca.url ] && ALPACA_URL=$(cat alpaca.url)
|
|
|
|
cat > .env <<EOF
|
|
# Stonks Oracle — Docker Deployment Environment
|
|
MARKET_DATA_API_KEY=${POLYGON_KEY}
|
|
BROKER_API_KEY=${ALPACA_KEY}
|
|
BROKER_API_SECRET=${ALPACA_SECRET}
|
|
BROKER_BASE_URL=${ALPACA_URL}
|
|
TRADING_ENABLED=true
|
|
TRADING_RISK_TIER=moderate
|
|
TRADING_MAX_OPEN_POSITIONS=15
|
|
OLLAMA_MODEL=${OLLAMA_MODEL}
|
|
MACRO_ENABLED=true
|
|
COMPETITIVE_ENABLED=true
|
|
EOF
|
|
|
|
# Create compose override based on Ollama configuration
|
|
if [ "$USE_DOCKER_OLLAMA" = "true" ]; then
|
|
# Using Docker Ollama — no override needed, default compose handles it
|
|
rm -f docker-compose.override.yml
|
|
echo " ✓ Using Docker Ollama container"
|
|
else
|
|
# Using external Ollama — disable the container and point services to it
|
|
# Determine if URL is localhost (needs host-gateway) or remote
|
|
if echo "$OLLAMA_URL" | grep -qE "localhost|127\.0\.0\.1"; then
|
|
DOCKER_OLLAMA_URL="http://host.docker.internal:$(echo "$OLLAMA_URL" | grep -oP ':\K[0-9]+')"
|
|
cat > docker-compose.override.yml <<EOF
|
|
services:
|
|
ollama:
|
|
entrypoint: ["true"]
|
|
restart: "no"
|
|
ports: []
|
|
extractor:
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
OLLAMA_BASE_URL: "${DOCKER_OLLAMA_URL}"
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
recommendation:
|
|
environment:
|
|
OLLAMA_BASE_URL: "${DOCKER_OLLAMA_URL}"
|
|
extra_hosts:
|
|
- "host.docker.internal:host-gateway"
|
|
EOF
|
|
else
|
|
# Remote Ollama — containers can reach it directly
|
|
cat > docker-compose.override.yml <<EOF
|
|
services:
|
|
ollama:
|
|
entrypoint: ["true"]
|
|
restart: "no"
|
|
extractor:
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
OLLAMA_BASE_URL: "${OLLAMA_URL}"
|
|
recommendation:
|
|
environment:
|
|
OLLAMA_BASE_URL: "${OLLAMA_URL}"
|
|
EOF
|
|
fi
|
|
echo " ✓ Override created — services will use external Ollama at ${OLLAMA_URL}"
|
|
fi
|
|
|
|
echo " ✓ .env configured (polygon=$([ -n "$POLYGON_KEY" ] && echo 'set' || echo 'empty'), alpaca=$([ -n "$ALPACA_KEY" ] && echo 'set' || echo 'empty'))"
|
|
REMOTE_SCRIPT
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 4: Build and start all services
|
|
# -------------------------------------------------------
|
|
echo "--- Step 4: Building and starting services ---"
|
|
ssh "$REMOTE_HOST" bash -s -- "$REMOTE_DIR" "$USE_DOCKER_OLLAMA" <<'REMOTE_SCRIPT'
|
|
set -euo pipefail
|
|
REMOTE_DIR="$1"
|
|
USE_DOCKER_OLLAMA="$2"
|
|
cd "$REMOTE_DIR"
|
|
|
|
# Stop any existing deployment
|
|
docker compose down 2>/dev/null || true
|
|
|
|
# Build all images
|
|
echo " Building images (this may take a few minutes)..."
|
|
docker compose build --quiet 2>&1 | tail -5
|
|
|
|
# Start infrastructure
|
|
echo " Starting infrastructure..."
|
|
if [ "$USE_DOCKER_OLLAMA" = "true" ]; then
|
|
docker compose up -d postgres redis minio minio-init ollama
|
|
else
|
|
docker compose up -d postgres redis minio minio-init
|
|
fi
|
|
|
|
# Wait for infrastructure to be healthy
|
|
echo " Waiting for infrastructure health checks..."
|
|
for svc in postgres redis minio; do
|
|
for i in $(seq 1 30); do
|
|
if docker compose ps "$svc" 2>/dev/null | grep -q healthy; then
|
|
break
|
|
fi
|
|
sleep 2
|
|
done
|
|
done
|
|
echo " ✓ Infrastructure healthy"
|
|
|
|
# Start all application services
|
|
echo " Starting application services..."
|
|
docker compose up -d
|
|
|
|
echo " Waiting for services to stabilize..."
|
|
sleep 20
|
|
|
|
# Show status
|
|
echo ""
|
|
echo " Service Status:"
|
|
docker compose ps --format "table {{.Name}}\t{{.Status}}" 2>/dev/null | head -25 || docker compose ps
|
|
REMOTE_SCRIPT
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 5: Seed the database
|
|
# -------------------------------------------------------
|
|
echo "--- Step 5: Seeding database ---"
|
|
ssh "$REMOTE_HOST" bash -s -- "$REMOTE_DIR" <<'REMOTE_SCRIPT'
|
|
set -euo pipefail
|
|
cd "$1"
|
|
|
|
# Wait for query-api to be healthy
|
|
for i in $(seq 1 30); do
|
|
if docker compose ps query-api 2>/dev/null | grep -q healthy; then
|
|
break
|
|
fi
|
|
sleep 3
|
|
done
|
|
|
|
# Run the symbol registry seed
|
|
echo " Seeding symbol registry..."
|
|
docker compose exec -T scheduler python -m services.symbol_registry.seed 2>/dev/null && echo " ✓ Database seeded" || echo " ⚠ Seed skipped (may already be seeded or service not ready)"
|
|
REMOTE_SCRIPT
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Step 6: Ensure Ollama model is available
|
|
# -------------------------------------------------------
|
|
echo "--- Step 6: Checking Ollama model ---"
|
|
ssh "$REMOTE_HOST" bash -s -- "$OLLAMA_URL" "$OLLAMA_MODEL" "$USE_DOCKER_OLLAMA" "$REMOTE_DIR" <<'REMOTE_SCRIPT'
|
|
set -euo pipefail
|
|
OLLAMA_URL="$1"
|
|
OLLAMA_MODEL="$2"
|
|
USE_DOCKER_OLLAMA="$3"
|
|
REMOTE_DIR="$4"
|
|
|
|
if [ "$USE_DOCKER_OLLAMA" = "true" ]; then
|
|
# Pull via Docker container
|
|
cd "$REMOTE_DIR"
|
|
if docker compose exec -T ollama ollama list 2>/dev/null | grep -q "$OLLAMA_MODEL"; then
|
|
echo " ✓ Model $OLLAMA_MODEL already available"
|
|
else
|
|
echo " Pulling $OLLAMA_MODEL via Docker Ollama..."
|
|
docker compose exec -T ollama ollama pull "$OLLAMA_MODEL"
|
|
echo " ✓ Model pulled"
|
|
fi
|
|
else
|
|
# Check via API
|
|
if curl -sf "$OLLAMA_URL/api/tags" 2>/dev/null | grep -q "$OLLAMA_MODEL"; then
|
|
echo " ✓ Model $OLLAMA_MODEL already available at $OLLAMA_URL"
|
|
else
|
|
echo " Pulling $OLLAMA_MODEL via $OLLAMA_URL..."
|
|
curl -sf "$OLLAMA_URL/api/pull" -d "{\"name\":\"$OLLAMA_MODEL\"}" | tail -1
|
|
echo " ✓ Model pulled"
|
|
fi
|
|
fi
|
|
REMOTE_SCRIPT
|
|
echo ""
|
|
|
|
# -------------------------------------------------------
|
|
# Done
|
|
# -------------------------------------------------------
|
|
REMOTE_IP=$(echo "$REMOTE_HOST" | cut -d@ -f2)
|
|
echo "=== Deployment Complete ==="
|
|
echo ""
|
|
echo "Endpoints:"
|
|
echo " Dashboard: http://${REMOTE_IP}:3000"
|
|
echo " Query API: http://${REMOTE_IP}:8004"
|
|
echo " Symbol Registry: http://${REMOTE_IP}:8001"
|
|
echo " Trading Engine: http://${REMOTE_IP}:8002"
|
|
echo " Risk Engine: http://${REMOTE_IP}:8003"
|
|
echo " MinIO Console: http://${REMOTE_IP}:9001"
|
|
echo " Superset: http://${REMOTE_IP}:8088"
|
|
echo " Ollama: ${OLLAMA_URL}"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " ssh $REMOTE_HOST 'cd $REMOTE_DIR && docker compose logs -f'"
|
|
echo " ssh $REMOTE_HOST 'cd $REMOTE_DIR && docker compose ps'"
|
|
echo " ssh $REMOTE_HOST 'cd $REMOTE_DIR && docker compose down'"
|