#!/bin/bash
# Komodo MCP Server Docker Deployment Script
# Handles building, running, scaling, and monitoring Docker containers
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
IMAGE_NAME="komodo-mcp"
IMAGE_TAG="${IMAGE_TAG:-latest}"
COMPOSE_FILE="$PROJECT_ROOT/docker-compose.yml"
COMPOSE_DEV_FILE="$PROJECT_ROOT/docker-compose.dev.yml"
LOG_DIR="$PROJECT_ROOT/logs"
# Functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $*"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $*"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $*"
}
# Build Docker image
build_image() {
log_info "Building Docker image: $IMAGE_NAME:$IMAGE_TAG"
if docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f "$PROJECT_ROOT/Dockerfile" "$PROJECT_ROOT"; then
log_success "Docker image built successfully"
else
log_error "Failed to build Docker image"
exit 1
fi
}
# Build development image
build_dev_image() {
log_info "Building development Docker image: $IMAGE_NAME:dev"
if docker build -t "$IMAGE_NAME:dev" -f "$PROJECT_ROOT/Dockerfile.dev" "$PROJECT_ROOT"; then
log_success "Development Docker image built successfully"
else
log_error "Failed to build development Docker image"
exit 1
fi
}
# Start containers
start_containers() {
local profile="${1:-default}"
log_info "Starting containers with profile: $profile"
case "$profile" in
default)
docker-compose -f "$COMPOSE_FILE" up -d komodo-mcp-1
;;
scaled)
docker-compose -f "$COMPOSE_FILE" --profile scaled up -d
;;
load-balanced)
docker-compose -f "$COMPOSE_FILE" --profile scaled --profile load-balanced up -d
;;
dev)
docker-compose -f "$COMPOSE_FILE" -f "$COMPOSE_DEV_FILE" up -d
;;
*)
log_error "Unknown profile: $profile"
log_info "Available profiles: default, scaled, load-balanced, dev"
exit 1
;;
esac
log_success "Containers started"
}
# Stop containers
stop_containers() {
local profile="${1:-default}"
log_info "Stopping containers with profile: $profile"
case "$profile" in
default)
docker-compose -f "$COMPOSE_FILE" stop komodo-mcp-1
;;
scaled)
docker-compose -f "$COMPOSE_FILE" --profile scaled stop
;;
load-balanced)
docker-compose -f "$COMPOSE_FILE" --profile scaled --profile load-balanced stop
;;
dev)
docker-compose -f "$COMPOSE_FILE" -f "$COMPOSE_DEV_FILE" stop
;;
*)
log_error "Unknown profile: $profile"
exit 1
;;
esac
log_success "Containers stopped"
}
# Remove containers
remove_containers() {
local profile="${1:-default}"
log_info "Removing containers with profile: $profile"
case "$profile" in
default)
docker-compose -f "$COMPOSE_FILE" down komodo-mcp-1
;;
scaled)
docker-compose -f "$COMPOSE_FILE" --profile scaled down
;;
load-balanced)
docker-compose -f "$COMPOSE_FILE" --profile scaled --profile load-balanced down
;;
dev)
docker-compose -f "$COMPOSE_FILE" -f "$COMPOSE_DEV_FILE" down
;;
*)
log_error "Unknown profile: $profile"
exit 1
;;
esac
log_success "Containers removed"
}
# Health check
health_check() {
log_info "Performing health checks..."
local instances=("komodo-mcp-1" "komodo-mcp-2" "komodo-mcp-3")
local ports=(1111 1112 1113)
local healthy=0
local total=0
for i in "${!instances[@]}"; do
local instance="${instances[$i]}"
local port="${ports[$i]}"
local container_id=$(docker-compose -f "$COMPOSE_FILE" ps -q "$instance" 2>/dev/null || echo "")
if [ -z "$container_id" ]; then
continue
fi
total=$((total + 1))
if docker-compose -f "$COMPOSE_FILE" exec -T "$instance" node -e "require('net').connect($port, '127.0.0.1').on('connect', () => process.exit(0)).on('error', () => process.exit(1))" &>/dev/null; then
log_success "$instance is healthy (port $port)"
healthy=$((healthy + 1))
else
log_warn "$instance is unhealthy (port $port)"
fi
done
if [ $total -eq 0 ]; then
log_warn "No containers running"
return 1
fi
if [ $healthy -eq $total ]; then
log_success "All $total container(s) are healthy"
return 0
else
log_warn "$healthy/$total container(s) are healthy"
return 1
fi
}
# View logs
view_logs() {
local instance="${1:-komodo-mcp-1}"
local tail="${2:-100}"
log_info "Showing last $tail logs for $instance..."
docker-compose -f "$COMPOSE_FILE" logs -f --tail "$tail" "$instance"
}
# View all logs
view_all_logs() {
local tail="${1:-100}"
log_info "Showing last $tail logs for all containers..."
docker-compose -f "$COMPOSE_FILE" logs -f --tail "$tail"
}
# Clean logs
clean_logs() {
log_info "Cleaning logs..."
if [ -d "$LOG_DIR" ]; then
rm -rf "$LOG_DIR"/*
log_success "Logs cleaned"
else
log_warn "Log directory not found: $LOG_DIR"
fi
}
# Display port mapping
show_ports() {
log_info "Port mapping:"
echo ""
echo -e "${YELLOW}Default Profile:${NC}"
echo " komodo-mcp-1: 1111 -> host:1111"
echo ""
echo -e "${YELLOW}Scaled Profile:${NC}"
echo " komodo-mcp-1: 1111 -> host:1111"
echo " komodo-mcp-2: 1111 -> host:1112"
echo " komodo-mcp-3: 1111 -> host:1113"
echo ""
echo -e "${YELLOW}Load Balanced Profile:${NC}"
echo " nginx-lb: 80 -> host:1110"
echo " komodo-mcp-1: 1111 -> host:1111"
echo " komodo-mcp-2: 1111 -> host:1112"
echo " komodo-mcp-3: 1111 -> host:1113"
echo ""
}
# Display help
show_help() {
cat << EOF
${GREEN}Komodo MCP Server Docker Deployment Script${NC}
Usage: $0 [COMMAND] [OPTIONS]
Commands:
build Build Docker image
build-dev Build development Docker image
start [profile] Start containers (default, scaled, load-balanced, dev)
stop [profile] Stop containers
down [profile] Remove and stop containers
health Check health of running containers
logs [instance] View logs for specific instance (default: komodo-mcp-1)
logs-all View logs for all containers
clean-logs Clean log files
ports Show port mapping
help Display this help message
Examples:
# Build and start default instance
$0 build && $0 start
# Start scaled deployment (3 instances)
$0 start scaled
# Start with load balancer
$0 start load-balanced
# View logs for all containers
$0 logs-all
# Check health
$0 health
Environment Variables:
IMAGE_TAG Docker image tag (default: latest)
EOF
}
# Main script
main() {
# Check if docker and docker-compose are installed
if ! command -v docker &> /dev/null; then
log_error "Docker is not installed"
exit 1
fi
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose is not installed"
exit 1
fi
# Change to project root
cd "$PROJECT_ROOT"
# Parse commands
local command="${1:-help}"
case "$command" in
build)
build_image
;;
build-dev)
build_dev_image
;;
start)
local profile="${2:-default}"
start_containers "$profile"
;;
stop)
local profile="${2:-default}"
stop_containers "$profile"
;;
down)
local profile="${2:-default}"
remove_containers "$profile"
;;
health)
health_check
;;
logs)
local instance="${2:-komodo-mcp-1}"
local tail="${3:-100}"
view_logs "$instance" "$tail"
;;
logs-all)
local tail="${2:-100}"
view_all_logs "$tail"
;;
clean-logs)
clean_logs
;;
ports)
show_ports
;;
help)
show_help
;;
*)
log_error "Unknown command: $command"
show_help
exit 1
;;
esac
}
# Run main
main "$@"