mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
315 lines
11 KiB
Bash
Executable File
315 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
# MetaBuilder Full Stack Startup Script
|
|
#
|
|
# Core: nginx gateway, PostgreSQL, MySQL, MongoDB, Redis, Elasticsearch,
|
|
# DBAL C++, WorkflowUI, CodeForge, Pastebin, Postgres Dashboard,
|
|
# Email Client, Exploded Diagrams, Storybook, Frontend App,
|
|
# Postfix, Dovecot, SMTP Relay, Email Service,
|
|
# phpMyAdmin, Mongo Express, RedisInsight, Kibana
|
|
# Monitoring: Prometheus, Grafana, Loki, Promtail, exporters, Alertmanager
|
|
# Media: Media daemon (FFmpeg/radio/retro), Icecast, HLS streaming
|
|
#
|
|
# Portal: http://localhost (nginx welcome page with links to all apps)
|
|
#
|
|
# Usage:
|
|
# ./start-stack.sh [COMMAND] [--monitoring] [--media] [--all]
|
|
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# Pull a single image with exponential backoff retries.
|
|
# Skips silently if the image is already present and up-to-date.
|
|
pull_with_retry() {
|
|
local image="$1"
|
|
local max_attempts=5
|
|
local delay=5
|
|
|
|
for attempt in $(seq 1 $max_attempts); do
|
|
if docker pull "$image" 2>&1; then
|
|
return 0
|
|
fi
|
|
if [ "$attempt" -lt "$max_attempts" ]; then
|
|
echo -e "${YELLOW} Pull failed (attempt $attempt/$max_attempts), retrying in ${delay}s...${NC}"
|
|
sleep "$delay"
|
|
delay=$((delay * 2))
|
|
fi
|
|
done
|
|
|
|
echo -e "${RED} Failed to pull $image after $max_attempts attempts${NC}"
|
|
return 1
|
|
}
|
|
|
|
# Pull all external (non-built) images for the requested profiles.
|
|
# Built images (dbal, workflowui, etc.) are skipped — they're local.
|
|
pull_external_images() {
|
|
local profiles=("$@")
|
|
|
|
local core_images=(
|
|
"postgres:15-alpine"
|
|
"redis:7-alpine"
|
|
"docker.elastic.co/elasticsearch/elasticsearch:8.11.0"
|
|
"mysql:8.0"
|
|
"mongo:7.0"
|
|
"phpmyadmin:latest"
|
|
"mongo-express:latest"
|
|
"redis/redisinsight:latest"
|
|
"docker.elastic.co/kibana/kibana:8.11.0"
|
|
"boky/postfix:latest"
|
|
"nginx:alpine"
|
|
)
|
|
|
|
local monitoring_images=(
|
|
"prom/prometheus:latest"
|
|
"grafana/grafana:latest"
|
|
"grafana/loki:latest"
|
|
"grafana/promtail:latest"
|
|
"prom/node-exporter:latest"
|
|
"prometheuscommunity/postgres-exporter:latest"
|
|
"oliver006/redis_exporter:latest"
|
|
"gcr.io/cadvisor/cadvisor:latest"
|
|
"prom/alertmanager:latest"
|
|
)
|
|
|
|
local media_images=(
|
|
"libretime/icecast:2.4.4"
|
|
)
|
|
|
|
local images=("${core_images[@]}")
|
|
|
|
local want_monitoring=false
|
|
local want_media=false
|
|
for p in "${profiles[@]}"; do
|
|
[[ "$p" == "monitoring" ]] && want_monitoring=true
|
|
[[ "$p" == "media" ]] && want_media=true
|
|
done
|
|
|
|
$want_monitoring && images+=("${monitoring_images[@]}")
|
|
$want_media && images+=("${media_images[@]}")
|
|
|
|
local total=${#images[@]}
|
|
echo -e "${YELLOW}Pre-pulling $total external images (with retry on flaky connections)...${NC}"
|
|
|
|
local failed=0
|
|
for i in "${!images[@]}"; do
|
|
local img="${images[$i]}"
|
|
echo -e " [$(( i + 1 ))/$total] $img"
|
|
pull_with_retry "$img" || failed=$((failed + 1))
|
|
done
|
|
|
|
if [ "$failed" -gt 0 ]; then
|
|
echo -e "${RED}Warning: $failed image(s) failed to pull. Stack may be incomplete.${NC}"
|
|
else
|
|
echo -e "${GREEN}All images ready.${NC}"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.stack.yml"
|
|
|
|
# Parse arguments
|
|
COMMAND=""
|
|
PROFILES=()
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--monitoring) PROFILES+=("--profile" "monitoring") ;;
|
|
--media) PROFILES+=("--profile" "media") ;;
|
|
--all) PROFILES+=("--profile" "monitoring" "--profile" "media") ;;
|
|
*)
|
|
if [ -z "$COMMAND" ]; then
|
|
COMMAND="$arg"
|
|
fi
|
|
;;
|
|
esac
|
|
done
|
|
|
|
COMMAND=${COMMAND:-up}
|
|
|
|
# Check docker compose
|
|
if ! docker compose version &> /dev/null; then
|
|
echo -e "${RED}docker compose not found${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
case "$COMMAND" in
|
|
up|start)
|
|
echo -e "${BLUE}Starting MetaBuilder stack...${NC}"
|
|
|
|
# Collect profile names for the image pre-pull
|
|
PROFILE_NAMES=()
|
|
for p in "${PROFILES[@]}"; do
|
|
[[ "$p" == "--profile" ]] && continue
|
|
PROFILE_NAMES+=("$p")
|
|
done
|
|
pull_external_images "${PROFILE_NAMES[@]}"
|
|
;;
|
|
down|stop)
|
|
echo -e "${YELLOW}Stopping MetaBuilder stack...${NC}"
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" down
|
|
echo -e "${GREEN}Stack stopped${NC}"
|
|
exit 0
|
|
;;
|
|
build)
|
|
echo -e "${YELLOW}Building MetaBuilder stack...${NC}"
|
|
PROFILE_NAMES=()
|
|
for p in "${PROFILES[@]}"; do
|
|
[[ "$p" == "--profile" ]] && continue
|
|
PROFILE_NAMES+=("$p")
|
|
done
|
|
pull_external_images "${PROFILE_NAMES[@]}"
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" up -d --build
|
|
echo -e "${GREEN}Stack built and started${NC}"
|
|
exit 0
|
|
;;
|
|
logs)
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" logs -f ${2:-}
|
|
exit 0
|
|
;;
|
|
restart)
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" restart
|
|
echo -e "${GREEN}Stack restarted${NC}"
|
|
exit 0
|
|
;;
|
|
ps|status)
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" ps
|
|
exit 0
|
|
;;
|
|
clean)
|
|
echo -e "${RED}This will remove all containers and volumes!${NC}"
|
|
read -p "Are you sure? (yes/no): " -r
|
|
if [[ $REPLY == "yes" ]]; then
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" down -v
|
|
echo -e "${GREEN}Stack cleaned${NC}"
|
|
fi
|
|
exit 0
|
|
;;
|
|
help|--help|-h)
|
|
echo "Usage: ./start-stack.sh [COMMAND] [--monitoring] [--media] [--all]"
|
|
echo ""
|
|
echo "Commands:"
|
|
echo " up, start Start the stack (default)"
|
|
echo " build Build and start the stack"
|
|
echo " down, stop Stop the stack"
|
|
echo " restart Restart all services"
|
|
echo " logs [svc] Show logs (optionally for specific service)"
|
|
echo " ps, status Show service status"
|
|
echo " clean Stop and remove all containers and volumes"
|
|
echo " help Show this help message"
|
|
echo ""
|
|
echo "Profiles:"
|
|
echo " --monitoring Add Prometheus, Grafana, Loki, exporters, Alertmanager"
|
|
echo " --media Add media daemon, Icecast, HLS streaming"
|
|
echo " --all Enable all profiles"
|
|
echo ""
|
|
echo "Core services (always started):"
|
|
echo " nginx 80 Gateway + welcome portal (http://localhost)"
|
|
echo " postgres 5432 PostgreSQL database"
|
|
echo " mysql 3306 MySQL database"
|
|
echo " mongodb 27017 MongoDB database"
|
|
echo " redis 6379 Cache layer"
|
|
echo " elasticsearch 9200 Search layer"
|
|
echo " dbal 8080 DBAL C++ backend"
|
|
echo " workflowui 3001 Visual workflow editor (/workflowui)"
|
|
echo " codegen 3002 CodeForge IDE (/codegen)"
|
|
echo " pastebin 3003 Code snippet sharing (/pastebin)"
|
|
echo " postgres-dashboard 3004 PostgreSQL admin (/postgres)"
|
|
echo " emailclient-app 3005 Email client (/emailclient)"
|
|
echo " exploded-diagrams 3006 3D diagram viewer (/diagrams)"
|
|
echo " storybook 3007 Component library (/storybook)"
|
|
echo " frontend-app 3008 Main application (/app)"
|
|
echo " phpmyadmin 8081 MySQL admin (/phpmyadmin/)"
|
|
echo " mongo-express 8082 MongoDB admin (/mongo-express/)"
|
|
echo " redisinsight 8083 Redis admin (/redis-insight/)"
|
|
echo " kibana 5601 Elasticsearch admin (/kibana/)"
|
|
echo " postfix 1025 SMTP relay"
|
|
echo " dovecot 1143 IMAP/POP3"
|
|
echo " smtp-relay 2525 SMTP relay (dashboard: 8025)"
|
|
echo " email-service 8500 Flask email API"
|
|
echo ""
|
|
echo "Monitoring services (--monitoring):"
|
|
echo " prometheus 9090 Metrics"
|
|
echo " grafana 3009 Dashboards"
|
|
echo " loki 3100 Log aggregation"
|
|
echo " promtail - Log shipper"
|
|
echo " node-exporter 9100 Host metrics"
|
|
echo " postgres-exporter 9187 DB metrics"
|
|
echo " redis-exporter 9121 Cache metrics"
|
|
echo " cadvisor 8084 Container metrics"
|
|
echo " alertmanager 9093 Alert routing"
|
|
echo ""
|
|
echo "Media services (--media):"
|
|
echo " media-daemon 8090 FFmpeg, radio, retro gaming"
|
|
echo " icecast 8000 Radio streaming"
|
|
echo " nginx-stream 8088 HLS/DASH streaming"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown command: $COMMAND${NC}"
|
|
echo "Run './start-stack.sh help' for usage"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Start
|
|
docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" up -d
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Stack started!${NC}"
|
|
echo ""
|
|
|
|
# Count expected healthy services
|
|
# Core: postgres, redis, elasticsearch, mysql, mongodb (5)
|
|
# Admin tools: phpmyadmin, mongo-express, redisinsight, kibana (4)
|
|
# Backend: dbal, email-service (2)
|
|
# Mail: postfix, dovecot, smtp-relay (3)
|
|
# Gateway: nginx (1)
|
|
# Apps: workflowui, codegen, pastebin, postgres-dashboard, emailclient-app,
|
|
# exploded-diagrams, storybook, frontend-app (8)
|
|
# Total: 23
|
|
CORE_COUNT=23
|
|
PROFILE_INFO="core"
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--monitoring) CORE_COUNT=$((CORE_COUNT + 9)); PROFILE_INFO="core + monitoring" ;;
|
|
--media) CORE_COUNT=$((CORE_COUNT + 3)); PROFILE_INFO="core + media" ;;
|
|
--all) CORE_COUNT=$((CORE_COUNT + 12)); PROFILE_INFO="core + monitoring + media" ;;
|
|
esac
|
|
done
|
|
|
|
echo -e "${YELLOW}Waiting for services ($PROFILE_INFO)...${NC}"
|
|
|
|
MAX_WAIT=120
|
|
ELAPSED=0
|
|
while [ $ELAPSED -lt $MAX_WAIT ]; do
|
|
HEALTHY=$(docker compose -f "$COMPOSE_FILE" "${PROFILES[@]}" ps --format json 2>/dev/null | grep -c '"healthy"' || true)
|
|
|
|
if [ "$HEALTHY" -ge "$CORE_COUNT" ]; then
|
|
echo -e "\n${GREEN}All $CORE_COUNT services healthy!${NC}"
|
|
echo ""
|
|
echo -e "Portal: ${BLUE}http://localhost${NC}"
|
|
echo ""
|
|
echo "Quick commands:"
|
|
echo " ./start-stack.sh logs View all logs"
|
|
echo " ./start-stack.sh logs dbal View DBAL logs"
|
|
echo " ./start-stack.sh stop Stop the stack"
|
|
echo " ./start-stack.sh restart Restart services"
|
|
exit 0
|
|
fi
|
|
|
|
echo -ne "\r Services healthy: $HEALTHY/$CORE_COUNT (${ELAPSED}s)"
|
|
sleep 2
|
|
ELAPSED=$((ELAPSED + 2))
|
|
done
|
|
|
|
echo ""
|
|
echo -e "${YELLOW}Timeout waiting for all services. Check with:${NC}"
|
|
echo " ./start-stack.sh status"
|
|
echo " ./start-stack.sh logs"
|