<# .SYNOPSIS Edu v2.1 健康检查脚本 .DESCRIPTION 检查范围: 1. Docker 基础设施容器 2. 应用服务 HTTP 端点 3. 可观测性端点 4. CDC 管道状态 .EXAMPLE .\scripts\health-check.ps1 #> $ErrorActionPreference = "Continue" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Edu v2.1 Health Check" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" # ===== 1. 基础设施容器 ===== Write-Host "[1/4] Infrastructure Containers" -ForegroundColor Yellow $infraContainers = @( @{Name="MySQL"; Container="edu-mysql"}, @{Name="Redis"; Container="edu-redis"}, @{Name="Kafka"; Container="edu-kafka"}, @{Name="Zookeeper"; Container="edu-zookeeper"}, @{Name="ClickHouse"; Container="edu-clickhouse"}, @{Name="Debezium"; Container="edu-debezium"}, @{Name="Neo4j"; Container="edu-neo4j"}, @{Name="Elasticsearch"; Container="edu-es"}, @{Name="Apollo Router"; Container="edu-apollo-router"}, @{Name="Jaeger"; Container="edu-jaeger"}, @{Name="Prometheus"; Container="edu-prometheus"}, @{Name="Grafana"; Container="edu-grafana"}, @{Name="Loki"; Container="edu-loki"}, @{Name="Alertmanager"; Container="edu-alertmanager"} ) $infraOk = 0 $infraFail = 0 foreach ($svc in $infraContainers) { $running = docker inspect -f '{{.State.Running}}' $svc.Container 2>$null if ($running -ne "true") { Write-Host " [SKIP] $($svc.Name) (not running, may be optional)" -ForegroundColor Gray continue } $health = docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' $svc.Container 2>$null if ($health -eq "healthy" -or $health -eq "") { Write-Host " [OK] $($svc.Name)" -ForegroundColor Green $infraOk++ } elseif ($health -eq "starting") { Write-Host " [WAIT] $($svc.Name) (starting)" -ForegroundColor Yellow $infraOk++ } else { Write-Host " [WARN] $($svc.Name) (health=$health)" -ForegroundColor Yellow $infraOk++ } } Write-Host "" # ===== 2. 应用服务 ===== Write-Host "[2/4] Application Services" -ForegroundColor Yellow $appServices = @( @{Name="iam"; Url="http://localhost:3002/healthz"; Critical=$true}, @{Name="config-service"; Url="http://localhost:3011/healthz"; Critical=$true}, @{Name="classes"; Url="http://localhost:3001/healthz"; Critical=$false}, @{Name="core-edu"; Url="http://localhost:3004/healthz"; Critical=$false}, @{Name="content"; Url="http://localhost:3005/healthz"; Critical=$false}, @{Name="data-ana"; Url="http://localhost:3006/healthz"; Critical=$false}, @{Name="msg"; Url="http://localhost:3007/healthz"; Critical=$false}, @{Name="ai"; Url="http://localhost:3008/healthz"; Critical=$false}, @{Name="api-gateway"; Url="http://localhost:8080/healthz"; Critical=$false}, @{Name="push-gateway"; Url="http://localhost:8081/healthz"; Critical=$false}, @{Name="portal-shell"; Url="http://localhost:4010/api/health"; Critical=$true}, @{Name="apollo-router"; Url="http://localhost:8088/health"; Critical=$false} ) $appOk = 0 $appFail = 0 $failedApps = @() foreach ($svc in $appServices) { try { $null = Invoke-RestMethod -Uri $svc.Url -Method Get -TimeoutSec 3 -ErrorAction Stop $tag = if ($svc.Critical) { "CRITICAL" } else { "optional" } Write-Host " [OK] $($svc.Name) ($tag)" -ForegroundColor Green $appOk++ } catch { $tag = if ($svc.Critical) { "CRITICAL" } else { "optional" } Write-Host " [FAIL] $($svc.Name) ($tag)" -ForegroundColor Red $appFail++ $failedApps += $svc.Name } } Write-Host "" # ===== 3. 可观测性端点 ===== Write-Host "[3/4] Observability Endpoints" -ForegroundColor Yellow $obsEndpoints = @( @{Name="Prometheus API"; Url="http://localhost:9090/api/v1/query?query=up"}, @{Name="Jaeger API"; Url="http://localhost:16686/api/services"}, @{Name="Debezium Connect"; Url="http://localhost:8083/connectors"}, @{Name="Grafana"; Url="http://localhost:3030/api/health"}, @{Name="Loki"; Url="http://localhost:3100/ready"} ) $obsOk = 0 $obsFail = 0 foreach ($ep in $obsEndpoints) { try { $null = Invoke-RestMethod -Uri $ep.Url -Method Get -TimeoutSec 3 -ErrorAction Stop Write-Host " [OK] $($ep.Name)" -ForegroundColor Green $obsOk++ } catch { Write-Host " [FAIL] $($ep.Name)" -ForegroundColor Red $obsFail++ } } Write-Host "" # ===== 4. CDC 管道状态 ===== Write-Host "[4/4] CDC Pipeline Status" -ForegroundColor Yellow $prevEAP = $ErrorActionPreference $ErrorActionPreference = "Continue" try { $connectorStatus = Invoke-RestMethod -Uri "http://localhost:8083/connectors/edu-mysql-source/status" -Method Get -TimeoutSec 3 -ErrorAction Stop $connectorState = $connectorStatus.connector.state $tasks = @($connectorStatus.tasks) $taskState = if ($tasks.Count -gt 0) { $tasks[0].state } else { "UNKNOWN" } $color = if ($connectorState -eq "RUNNING" -and $taskState -eq "RUNNING") { "Green" } else { "Yellow" } Write-Host " Debezium Connector: $connectorState / Task: $taskState" -ForegroundColor $color } catch { Write-Host " [SKIP] Debezium connector not registered" -ForegroundColor Gray } $ErrorActionPreference = $prevEAP Write-Host "" # ===== 汇总 ===== Write-Host "========================================" -ForegroundColor Cyan $totalChecked = $infraContainers.Count + $appServices.Count + $obsEndpoints.Count $totalOk = $infraOk + $appOk + $obsOk Write-Host " Infra: $infraOk checked | App: $appOk/$($appServices.Count) | Obs: $obsOk/$($obsEndpoints.Count)" -ForegroundColor Cyan if ($appFail -gt 0) { Write-Host " Failed apps: $($failedApps -join ', ')" -ForegroundColor Yellow } Write-Host "========================================" -ForegroundColor Cyan if ($appFail -gt 0 -or $obsFail -gt 0) { exit 1 }