diff --git a/deploy/cec-prd-cluster/cost.yaml b/deploy/cec-prd-cluster/cost.yaml index 3574655..a573119 100644 --- a/deploy/cec-prd-cluster/cost.yaml +++ b/deploy/cec-prd-cluster/cost.yaml @@ -17,7 +17,7 @@ spec: spec: containers: - name: cost - image: fiskercloud.azurecr.io/cost:v5 + image: fiskercloud.azurecr.io/cost:v6 imagePullPolicy: Always ports: - containerPort: 8077 diff --git a/deploy/overlays/development/kustomization.yaml b/deploy/overlays/development/kustomization.yaml index 3891107..c480097 100644 --- a/deploy/overlays/development/kustomization.yaml +++ b/deploy/overlays/development/kustomization.yaml @@ -7,8 +7,8 @@ resources: - ../../base - secrets.yaml - services/gateway/ - # - services/depot/ - # - services/attendant/ + - services/depot/ + - services/attendant/ - services/jetfire/ - services/optimus/ - services/ota/ diff --git a/services/cost/README.md b/services/cost/README.md index 12d8170..7e09e09 100644 --- a/services/cost/README.md +++ b/services/cost/README.md @@ -16,9 +16,9 @@ This service estimates the cost of running cloud services per VIN by: | Activity Level | Messages/15min | CPU (cores) | Memory (GB) | |---------------|----------------|-------------|-------------| -| Low | < 100 | 0.15 | 0.25 | -| Medium | 100-1000 | 0.225 | 0.375 | -| High | > 1000 | 0.30 | 0.50 | +| Low | < 100 | 0.60 | 1.00 | +| Medium | 100-1000 | 0.90 | 1.50 | +| High | > 1000 | 1.20 | 2.00 | These estimates account for the full data pipeline per vehicle: - Data ingestion (MQTT/HTTP endpoints) @@ -29,12 +29,20 @@ These estimates account for the full data pipeline per vehicle: - MongoDB document storage - API serving +### Base Infrastructure Costs + +Shared infrastructure costs are distributed across active vehicles each collection interval: + +| Component | Cloud ($/15min) | On-Prem ($/15min) | +|-----------|-----------------|-------------------| +| Storage, Event Hubs, Defender, monitoring | $7.00 | $0.90 | + ### Cost Rates (per hour) | Resource | Cloud (Azure) | On-Prem | |----------|---------------|---------| -| CPU/core | $0.12 | $0.015 | -| Memory/GB| $0.025 | $0.003 | +| CPU/core | $0.20 | $0.02 | +| Memory/GB| $0.05 | $0.005 | #### Cloud Rates (Fudged Higher) - Based on Azure D-series VM pricing + 50% managed services overhead @@ -50,14 +58,26 @@ These estimates account for the full data pipeline per vehicle: ### Savings Calculation ``` -Cloud Cost = (CPU_cores × $0.12 + Memory_GB × $0.025) × hours -On-Prem Cost = (CPU_cores × $0.015 + Memory_GB × $0.003) × hours +Per-VIN Cost = (CPU_cores × rate + Memory_GB × rate) × hours + (base_infra / active_vins) +Cloud Cost = Per-VIN costs summed across fleet +On-Prem Cost = Same formula with on-prem rates Savings = Cloud Cost - On-Prem Cost Savings % = (Savings / Cloud Cost) × 100 ``` Expected savings: **~85-88%** with on-prem hosting (hardware costs only). +### Projected Annual Costs (5000 vehicles) + +Based on actual Azure billing (~$65k/month): + +| Metric | Cloud | On-Prem | +|--------|-------|---------| +| Monthly Cost | ~$65,000 | ~$9,500 | +| Annual Cost | ~$780,000 | ~$114,000 | +| Per Vehicle/Month | ~$13.00 | ~$1.90 | +| Annual Savings | ~$666,000 (85%) | - | + ## API Endpoints ### GET /cost/vin/{vin} diff --git a/services/cost/handlers/handlers.go b/services/cost/handlers/handlers.go index 0a41b4c..0f5f304 100644 --- a/services/cost/handlers/handlers.go +++ b/services/cost/handlers/handlers.go @@ -222,8 +222,9 @@ func GetReport(w http.ResponseWriter, r *http.Request) { ╠══════════════════════════════════════════════════════════════════╣ ║ COST RATES ║ ║ ─────────────────────────────────────────────────────────────── ║ -║ Cloud: CPU $%.3f/core-hr Memory $%.4f/GB-hr -║ On-Prem: CPU $%.3f/core-hr Memory $%.4f/GB-hr +║ Cloud: CPU $%.2f/core-hr Memory $%.3f/GB-hr +║ On-Prem: CPU $%.2f/core-hr Memory $%.3f/GB-hr +║ Base Infra: Cloud $%.2f/15min On-Prem $%.2f/15min ╠══════════════════════════════════════════════════════════════════╣ ║ ANNUAL PROJECTION (based on current usage) ║ ║ ─────────────────────────────────────────────────────────────── ║ @@ -244,6 +245,7 @@ func GetReport(w http.ResponseWriter, r *http.Request) { summary.TotalSavings, summary.SavingsPercent, services.CloudCPUPerCoreHour, services.CloudMemoryPerGBHour, services.OnpremCPUPerCoreHour, services.OnpremMemoryPerGBHour, + services.BaseInfraCloudCost, services.BaseInfraOnpremCost, annualCloud, annualOnprem, annualSavings, ) diff --git a/services/cost/services/collector.go b/services/cost/services/collector.go index 7fa3dca..a2fbe63 100644 --- a/services/cost/services/collector.go +++ b/services/cost/services/collector.go @@ -8,22 +8,28 @@ import ( // Cost rates per hour const ( - // Cloud costs (fudged higher - Azure pricing + overhead) - // Includes: AKS compute, managed Kafka, CosmosDB, storage, networking, monitoring - CloudCPUPerCoreHour = 0.12 // $/core/hour (Azure D-series + 50% managed services overhead) - CloudMemoryPerGBHour = 0.025 // $/GB/hour (includes managed DB memory costs) + // Cloud costs (based on actual Azure bill ~$65k/month for ~5000 vehicles) + // Includes: AKS compute, Event Hubs (Kafka), CosmosDB, storage, networking, monitoring + CloudCPUPerCoreHour = 0.20 // $/core/hour (Azure D-series + managed services + support) + CloudMemoryPerGBHour = 0.05 // $/GB/hour (includes managed DB, Redis, caching layers) - // On-prem costs (fudged lower - amortized hardware) + // On-prem costs (amortized hardware only) // Assumes: 3-year hardware amortization, minimal ops overhead - // Does NOT include: datacenter, power, cooling, staff - OnpremCPUPerCoreHour = 0.015 // $/core/hour - OnpremMemoryPerGBHour = 0.003 // $/GB/hour + // Does NOT include: datacenter, power, cooling, staff, network + OnpremCPUPerCoreHour = 0.02 // $/core/hour + OnpremMemoryPerGBHour = 0.005 // $/GB/hour // Estimated resource usage per active VIN - // A connected vehicle generates ~1-5 MB/day of telemetry - // Processing includes: ingestion, Kafka, stream processing, storage, analytics - EstimatedCPUPerVin = 0.15 // 150 millicores per active VIN (ingestion + processing) - EstimatedMemoryPerVin = 0.25 // 250MB per active VIN (buffers, caches, state) + // Connected vehicle telemetry pipeline: ingestion → Kafka → processing → storage → APIs + // Each active VIN requires dedicated processing capacity across the stack + EstimatedCPUPerVin = 0.6 // 600 millicores per active VIN (realistic for full pipeline) + EstimatedMemoryPerVin = 1.0 // 1GB per active VIN (buffers, state, caches, connections) + + // Base infrastructure cost per collection interval (shared services) + // Storage, Event Hubs, Defender, other fixed costs + // ~$30k/month fixed = ~$7/15min + BaseInfraCloudCost = 7.00 // $/15min for shared infra (cloud) + BaseInfraOnpremCost = 0.90 // $/15min for shared infra (on-prem) ) // CalculateCosts computes cloud and on-prem costs for given resource usage @@ -37,6 +43,11 @@ func CalculateCosts(cpuCores, memoryGB float64, durationHours float64) (cloudCos return } +// CalculateBaseCosts returns the shared infrastructure costs for a collection interval +func CalculateBaseCosts() (cloudCost, onpremCost float64) { + return BaseInfraCloudCost, BaseInfraOnpremCost +} + // StartMetricsCollector runs the background metrics collection loop func StartMetricsCollector(interval time.Duration) { logger.Info().Msgf("Starting metrics collector with %v interval", interval) @@ -73,6 +84,11 @@ func collectMetrics() { durationHours := 0.25 // 15 minutes = 0.25 hours records := make([]CostRecord, 0, len(activeVins)) + // Get base infrastructure costs and distribute across active VINs + baseCloud, baseOnprem := CalculateBaseCosts() + baseCloudPerVin := baseCloud / float64(len(activeVins)) + baseOnpremPerVin := baseOnprem / float64(len(activeVins)) + for _, v := range activeVins { // Scale resource estimate by activity level activityMultiplier := 1.0 @@ -86,6 +102,10 @@ func collectMetrics() { memoryGB := EstimatedMemoryPerVin * activityMultiplier cloudCost, onpremCost := CalculateCosts(cpuCores, memoryGB, durationHours) + + // Add share of base infrastructure costs + cloudCost += baseCloudPerVin + onpremCost += baseOnpremPerVin records = append(records, CostRecord{ VIN: v.VIN,