#!/bin/bash # # IT0 Web Admin - Deployment Script # ================================== # # Usage: # ./deploy.sh build - Build Docker image # ./deploy.sh start - Build and start service # ./deploy.sh stop - Stop service # ./deploy.sh restart - Restart service # ./deploy.sh logs - View logs # ./deploy.sh status - Show service status # ./deploy.sh clean - Clean containers and images # set -e # =========================================================================== # Configuration # =========================================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" PROJECT_NAME="it0-web-admin" IMAGE_NAME="it0-web-admin" CONTAINER_NAME="it0-web-admin" DEFAULT_PORT=3000 # API Configuration API_DOMAIN="${API_DOMAIN:-it0api.szaiai.com}" API_BASE_URL="${API_BASE_URL:-https://${API_DOMAIN}}" WS_URL="${WS_URL:-wss://${API_DOMAIN}}" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # =========================================================================== # Docker Check # =========================================================================== check_docker() { if ! command -v docker &> /dev/null; then log_error "Docker is not installed. Please install Docker first." exit 1 fi if ! docker info &> /dev/null; then log_error "Docker service is not running. Please start Docker." exit 1 fi if docker compose version &> /dev/null; then COMPOSE_CMD="docker compose" elif command -v docker-compose &> /dev/null; then COMPOSE_CMD="docker-compose" else log_error "Docker Compose is not installed." exit 1 fi log_success "Docker check passed" } # =========================================================================== # Ensure docker-compose.yml exists # =========================================================================== ensure_compose_file() { if [ ! -f "$SCRIPT_DIR/docker-compose.yml" ]; then log_info "Creating docker-compose.yml..." cat > "$SCRIPT_DIR/docker-compose.yml" << EOF version: '3.8' services: web-admin: build: context: . dockerfile: Dockerfile container_name: ${CONTAINER_NAME} ports: - "\${PORT:-${DEFAULT_PORT}}:3000" environment: - NODE_ENV=production - NEXT_PUBLIC_API_BASE_URL=${API_BASE_URL} - NEXT_PUBLIC_WS_URL=${WS_URL} restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000"] interval: 30s timeout: 10s retries: 3 start_period: 30s EOF log_success "docker-compose.yml created" fi } # =========================================================================== # Ensure Dockerfile exists # =========================================================================== ensure_dockerfile() { if [ ! -f "$SCRIPT_DIR/Dockerfile" ]; then log_info "Creating Dockerfile..." cat > "$SCRIPT_DIR/Dockerfile" << 'EOF' # Stage 1: Dependencies FROM node:20-alpine AS deps RUN corepack enable && corepack prepare pnpm@latest --activate WORKDIR /app COPY package.json pnpm-lock.yaml* ./ RUN pnpm install --frozen-lockfile --prod=false # Stage 2: Build FROM node:20-alpine AS builder RUN corepack enable && corepack prepare pnpm@latest --activate WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN pnpm build # Stage 3: Production FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static USER nextjs EXPOSE 3000 ENV PORT=3000 CMD ["node", "server.js"] EOF log_success "Dockerfile created" fi } # =========================================================================== # Commands # =========================================================================== build() { log_info "Building Docker image..." ensure_compose_file ensure_dockerfile $COMPOSE_CMD build --no-cache log_success "Image built successfully" } start() { log_info "Starting IT0 Web Admin..." ensure_compose_file ensure_dockerfile PORT=${PORT:-$DEFAULT_PORT} # Check if port is occupied if command -v lsof &> /dev/null && lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1; then log_warn "Port $PORT is already in use, stopping existing service..." stop fi $COMPOSE_CMD up -d --build # Wait for service to start log_info "Waiting for service to start..." sleep 5 if docker ps | grep -q "$CONTAINER_NAME"; then log_success "Service deployed successfully!" log_info "Access URL: http://localhost:$PORT" log_info "API endpoint: $API_BASE_URL" else log_error "Service failed to start. Check logs: ./deploy.sh logs" exit 1 fi } stop() { log_info "Stopping service..." $COMPOSE_CMD down log_success "Service stopped" } restart() { log_info "Restarting service..." stop start } logs() { $COMPOSE_CMD logs -f } status() { log_info "Service status:" docker ps -a --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" echo "" # Health check PORT=${PORT:-$DEFAULT_PORT} if curl -s -o /dev/null -w "%{http_code}" "http://localhost:$PORT" 2>/dev/null | grep -q "200"; then log_success "Web Admin is running (port $PORT)" else log_warn "Web Admin is not responding (port $PORT)" fi } clean() { log_info "Cleaning containers and images..." $COMPOSE_CMD down --rmi local --volumes --remove-orphans docker image prune -f log_success "Cleanup complete" } # =========================================================================== # Help # =========================================================================== show_help() { echo "" echo "IT0 Web Admin Deployment Script" echo "" echo "Usage: $0 " echo "" echo "Commands:" echo " build Build Docker image" echo " start Build and start service (default)" echo " stop Stop service" echo " restart Restart service" echo " logs View service logs" echo " status Show service status" echo " clean Clean containers and images" echo " help Show this help message" echo "" echo "Environment Variables:" echo " PORT Service port (default: 3000)" echo " API_DOMAIN API domain (default: it0api.szaiai.com)" echo " API_BASE_URL API base URL (default: https://it0api.szaiai.com)" echo " WS_URL WebSocket URL (default: wss://it0api.szaiai.com)" echo "" echo "Examples:" echo " $0 start # Start on default port 3000" echo " PORT=8080 $0 start # Start on port 8080" echo " API_DOMAIN=api.example.com $0 start # Use custom API domain" echo "" } # =========================================================================== # Main # =========================================================================== main() { cd "$SCRIPT_DIR" check_docker case "${1:-start}" in build) build ;; start) start ;; stop) stop ;; restart) restart ;; logs) logs ;; status) status ;; clean) clean ;; help|--help|-h) show_help ;; *) log_error "Unknown command: $1" show_help exit 1 ;; esac } main "$@"