Skip to main content
Source

This page is generated from skills/eks-cost-intelligence/references/waste-calculation.md. Edit the source, not this page.

Waste Calculation Formulas

Part of: eks-cost-intelligence Purpose: Dollar waste formulas for computing waste from utilization gaps, idle nodes, storage inefficiency, network costs, and missed Spot/Graviton opportunities


Core Principle

Waste = money spent on capacity that is allocated but not used, or money overspent by not using cheaper alternatives.

Every formula follows the same structure:

  1. Inputs — what data you need to collect
  2. Calculation — the formula to compute waste
  3. Outputmonthly_waste and monthly_savings values for the finding

1. Compute Waste (Request vs P95 Utilization)

Per-Pod Compute Waste

Inputs

InputSourceExample
cpu_request_coresPod spec .resources.requests.cpu0.800 (800m)
cpu_p95_coresmetrics-server / Container Insights / Prometheus0.065
mem_request_bytesPod spec .resources.requests.memory1073741824 (1Gi)
mem_p95_bytesmetrics-server / Container Insights / Prometheus398458880 (380Mi)
pod_monthly_costAllocated share of node cost (see cost-estimation-fallback.md)$185.00

Calculation

# Step 1: Calculate waste ratios for each resource
cpu_waste_ratio = max(0, (cpu_request_cores - cpu_p95_cores) / cpu_request_cores)
mem_waste_ratio = max(0, (mem_request_bytes - mem_p95_bytes) / mem_request_bytes)

# Step 2: Use the LOWER ratio (conservative — waste only what BOTH resources confirm)
waste_ratio = min(cpu_waste_ratio, mem_waste_ratio)

# Step 3: Calculate dollar waste
monthly_waste = waste_ratio * pod_monthly_cost

# Step 4: Calculate savings (account for 1.5x headroom buffer on right-sized requests)
headroom_factor = 0.85 # savings after keeping 15% headroom above p95
monthly_savings = monthly_waste * headroom_factor

Worked Example

Pod: payments/checkout-7f8b9c-abc12
CPU request: 800m (0.800 cores)
CPU P95 actual: 65m (0.065 cores)
Memory request: 1Gi (1024 MiB)
Memory P95 actual: 380Mi

Step 1:
cpu_waste_ratio = (0.800 - 0.065) / 0.800 = 0.919 (91.9%)
mem_waste_ratio = (1024 - 380) / 1024 = 0.629 (62.9%)

Step 2:
waste_ratio = min(0.919, 0.629) = 0.629

Step 3:
pod_monthly_cost = $185.00
monthly_waste = 0.629 × $185.00 = $116.37

Step 4:
monthly_savings = $116.37 × 0.85 = $98.91

Finding:
monthly_waste: $116.37
monthly_savings: $98.91
fix: Set CPU to 100m (1.5× P95), memory to 570Mi (1.5× P95)

Per-Node Compute Waste (Aggregate)

Inputs

InputSourceExample
node_allocatable_cpukubectl get node -o json.status.allocatable.cpu4.0 cores
node_total_requests_cpuSum of all pod CPU requests on node1.2 cores
node_p95_cpuCloudWatch / Prometheus node-level metric0.8 cores
node_hourly_costInstance pricing (see table below)$0.192

Calculation

# Node-level waste: gap between total requests and actual usage
node_waste_ratio = max(0, (node_total_requests_cpu - node_p95_cpu) / node_allocatable_cpu)
node_monthly_cost = node_hourly_cost * 24 * 30
monthly_waste = node_waste_ratio * node_monthly_cost

Severity Thresholds

Waste RatioSeverityAction
> 70%CRITICALRight-size immediately
40–70%HIGHReview and adjust within sprint
20–40%MEDIUMMonitor trend, plan adjustment
< 20%LOWAcceptable headroom

2. Idle Node Waste

Inputs

InputSourceExample
node_avg_cpu_7dCloudWatch CPUUtilization (7-day avg)6%
node_avg_mem_7dCloudWatch / kubelet metrics (7-day avg)12%
instance_typekubectl get node labelsm5.xlarge
instance_hourly_rateAWS Price List (see reference table)$0.192
node_has_gpuNode labels nvidia.com/gpufalse

Reference: Instance Hourly Rates (us-east-1, On-Demand)

⚠️ Fallback only — last verified June 2026. Prefer the AWS Price List API for production assessments. See cost-estimation-fallback.md Step 2.

Instance TypevCPUMemoryHourly Rate
m5.large28 GiB$0.096
m5.xlarge416 GiB$0.192
m5.2xlarge832 GiB$0.384
m6i.large28 GiB$0.096
m6i.xlarge416 GiB$0.192
m6i.2xlarge832 GiB$0.384
m7i.xlarge416 GiB$0.202
m7i.2xlarge832 GiB$0.403
m6g.xlarge416 GiB$0.154
m7g.xlarge416 GiB$0.163
c5.xlarge48 GiB$0.170
c5.2xlarge816 GiB$0.340
c7i.xlarge48 GiB$0.178
c7g.xlarge48 GiB$0.145
r5.xlarge432 GiB$0.252
r5.2xlarge864 GiB$0.504
r7i.xlarge432 GiB$0.264
r7g.xlarge432 GiB$0.214

For instance types not in this table, use the AWS Price List API:

aws pricing get-products --service-code AmazonEC2 --region us-east-1 \
--filters "Type=TERM_MATCH,Field=instanceType,Value=<INSTANCE_TYPE>" \
"Type=TERM_MATCH,Field=operatingSystem,Value=Linux" \
"Type=TERM_MATCH,Field=location,Value=US East (N. Virginia)" \
"Type=TERM_MATCH,Field=tenancy,Value=Shared" \
"Type=TERM_MATCH,Field=preInstalledSw,Value=NA" \
"Type=TERM_MATCH,Field=capacitystatus,Value=Used" \
--query 'PriceList[0]' --output text | jq -r '.terms.OnDemand | to_entries[0].value.priceDimensions | to_entries[0].value.pricePerUnit.USD'

Detection Criteria

A node is idle if ALL of:

  • Average CPU utilization < 10% over 7 days
  • Average memory utilization < 20% over 7 days
  • No GPU workloads scheduled (nvidia.com/gpu not present)

Calculation

# Per idle node
is_idle = (node_avg_cpu_7d < 0.10 and
node_avg_mem_7d < 0.20 and
not node_has_gpu)

if is_idle:
monthly_waste = instance_hourly_rate * 24 * 30
monthly_savings = monthly_waste # full node cost is recoverable

# Aggregate across all idle nodes
total_idle_waste = sum(node.monthly_waste for node in idle_nodes)

Worked Example

Node: ip-10-0-1-42.ec2.internal
Instance type: m5.xlarge
Avg CPU (7d): 6%
Avg Memory (7d): 12%
GPU workloads: none

Detection:
6% < 10% ✓ AND 12% < 20% ✓ AND no GPU ✓ → IDLE

Calculation:
monthly_waste = $0.192/hr × 24 × 30 = $138.24/month
monthly_savings = $138.24/month

Cluster has 3 idle nodes (m5.xlarge):
total_monthly_waste = 3 × $138.24 = $414.72/month
total_annual_savings = $414.72 × 12 = $4,976.64/year

Karpenter Consolidation Savings (when consolidation is disabled)

# If Karpenter is installed but consolidateAfter is not set or consolidation is off
consolidation_monthly_savings = (
idle_node_count * avg_instance_hourly_rate * 24 * 30 * 0.25
)
# 25% is conservative — actual savings depend on workload packing density

3. Storage Waste

3a. gp2 → gp3 Migration Savings

Inputs

InputSourceExample
provisioned_gbPVC .spec.resources.requests.storage100 GiB
storage_classPVC .spec.storageClassNamegp2

Pricing

Storage ClassCost per GiB/month
gp2$0.10
gp3$0.08
Savings$0.02/GiB/month (20%)

Calculation

# Per volume
gp2_monthly_cost = provisioned_gb * 0.10
gp3_monthly_cost = provisioned_gb * 0.08
monthly_waste = gp2_monthly_cost - gp3_monthly_cost # = provisioned_gb * 0.02
monthly_savings = monthly_waste # full savings, zero-effort migration

# Aggregate across all gp2 volumes
total_gp2_waste = sum(pvc.provisioned_gb for pvc in gp2_pvcs) * 0.02

Worked Example

Cluster has 12 gp2 PVCs totaling 850 GiB:
monthly_waste = 850 × $0.02 = $17.00/month
annual_savings = $17.00 × 12 = $204.00/year

Individual PVC: data-postgres-0 (500 GiB, gp2)
monthly_waste = 500 × $0.02 = $10.00/month
monthly_savings = $10.00/month
effort: Low (create gp3 StorageClass, migrate PVC)

3b. Unused PVC Waste

Inputs

InputSourceExample
pvc_statusPVC .status.phaseBound
pvc_provisioned_gbPVC .spec.resources.requests.storage50 GiB
storage_classPVC .spec.storageClassNamegp3
last_mount_timePod events / volume attachment events14 days ago
storage_rateRate for the storage class$0.08/GiB/month

Detection Criteria

A PVC is unused if:

  • Status is Bound but no pod has mounted it in the last 7 days, OR
  • Status is Released (volume freed but PVC object remains)

Calculation

# Per unused PVC — the FULL cost is waste since nothing uses it
monthly_waste = pvc_provisioned_gb * storage_rate
monthly_savings = monthly_waste # delete PVC to recover full cost

Worked Example

PVC: logging/elasticsearch-data-2
Status: Bound
Size: 200 GiB
Storage class: gp3 ($0.08/GiB/month)
Last mounted: 21 days ago (pod was deleted)

Calculation:
monthly_waste = 200 × $0.08 = $16.00/month
monthly_savings = $16.00/month

Cluster has 4 unused PVCs totaling 500 GiB (gp3):
total_monthly_waste = 500 × $0.08 = $40.00/month

3c. Oversized Volume Waste

Inputs

InputSourceExample
provisioned_gbPVC .spec.resources.requests.storage500 GiB
actual_used_gbCloudWatch VolumeUsedBytes / kubelet volume stats45 GiB
storage_rateRate for the storage class$0.08/GiB/month

Detection Criteria

Flag if:

  • waste_ratio > 50% AND provisioned_gb > 20 GiB (ignore small volumes)

Calculation

waste_ratio = (provisioned_gb - actual_used_gb) / provisioned_gb
wasted_gb = provisioned_gb - actual_used_gb

# Can't always shrink EBS volumes, so savings = cost of excess capacity
monthly_waste = wasted_gb * storage_rate

# Savings assumes right-sizing to 2x actual usage (safety buffer)
right_sized_gb = max(actual_used_gb * 2, 20) # minimum 20 GiB
monthly_savings = (provisioned_gb - right_sized_gb) * storage_rate

Worked Example

PVC: analytics/clickstream-data
Provisioned: 500 GiB (gp3)
Actual used: 45 GiB
Storage rate: $0.08/GiB/month

Detection:
waste_ratio = (500 - 45) / 500 = 91%
91% > 50% ✓ AND 500 > 20 GiB ✓ → OVERSIZED

Calculation:
wasted_gb = 500 - 45 = 455 GiB
monthly_waste = 455 × $0.08 = $36.40/month

right_sized_gb = max(45 × 2, 20) = 90 GiB
monthly_savings = (500 - 90) × $0.08 = $32.80/month

effort: Medium (requires volume snapshot + restore to smaller size)

4. Network Waste

4a. Cross-AZ Data Transfer

Inputs

InputSourceExample
cross_az_gb_per_monthVPC Flow Logs / Container Insights network metrics500 GiB
cross_az_rateAWS pricing (fixed)$0.01/GiB

Calculation

# Current cross-AZ cost
monthly_waste = cross_az_gb_per_month * 0.01

# Savings from topology-aware routing (typically 50–80% reduction)
reduction_factor = 0.65 # conservative 65% reduction
monthly_savings = monthly_waste * reduction_factor

Worked Example

Cluster: production-us-east-1
Pods spread across 3 AZs (us-east-1a, 1b, 1c)
Service "order-api" has 6 replicas across all 3 AZs
Estimated cross-AZ traffic: 500 GiB/month

Calculation:
monthly_waste = 500 × $0.01 = $5.00/month
monthly_savings = $5.00 × 0.65 = $3.25/month

fix: Enable topology-aware routing on high-traffic services
effort: Low (add annotation to Service)

Estimating Cross-AZ Traffic

When direct metrics are unavailable, estimate from service topology:

# For each Service with pods in multiple AZs:
# Assume uniform traffic distribution across replicas
# Traffic that hits a replica in a different AZ = cross-AZ

num_azs = len(set(pod.az for pod in service.pods))
cross_az_probability = (num_azs - 1) / num_azs # e.g., 2/3 for 3 AZs

# If service handles ~1000 requests/sec at ~10KB avg response:
estimated_monthly_gb = (requests_per_sec * avg_response_kb / 1024 / 1024) * 86400 * 30
cross_az_gb = estimated_monthly_gb * cross_az_probability

4b. NAT Gateway Waste

Inputs

InputSourceExample
nat_gb_per_monthCloudWatch NatGatewayBytesOutToDestination200 GiB
nat_rateAWS pricing (fixed)$0.045/GiB
num_azsNumber of AZs with private subnets3
vpc_endpoint_hourly_rateAWS pricing (fixed)$0.01/hr/AZ

Calculation

# Current NAT cost for AWS service traffic
monthly_waste = nat_gb_per_month * 0.045

# VPC endpoint cost (per endpoint, per AZ)
endpoint_monthly_cost = vpc_endpoint_hourly_rate * 24 * 30 * num_azs
# = $0.01 × 24 × 30 × 3 = $21.60/month per endpoint

# Savings = NAT cost eliminated minus endpoint cost
# Typically need endpoints for: ECR (2 endpoints), S3 (gateway, free), STS (1)
num_interface_endpoints = 3 # ecr.api, ecr.dkr, sts
total_endpoint_cost = endpoint_monthly_cost * num_interface_endpoints

monthly_savings = monthly_waste - total_endpoint_cost
# Only recommend if savings > 0 (break-even analysis)

Worked Example

Cluster: production-us-east-1
NAT Gateway traffic to AWS services: 200 GiB/month
AZs: 3
No VPC endpoints configured

Current NAT cost:
monthly_waste = 200 × $0.045 = $9.00/month

VPC endpoint cost (if added):
S3 gateway endpoint: FREE
ECR endpoints (ecr.api + ecr.dkr): 2 × ($0.01 × 24 × 30 × 3) = $43.20/month
STS endpoint: 1 × ($0.01 × 24 × 30 × 3) = $21.60/month
Total endpoint cost: $64.80/month

Break-even analysis:
$9.00 < $64.80 → VPC endpoints NOT cost-effective at this traffic level

→ Only recommend VPC endpoints when NAT traffic > ~1,440 GiB/month
→ Break-even: nat_gb × $0.045 > num_endpoints × $21.60
→ Break-even GB = (3 × $21.60) / $0.045 = 1,440 GiB/month

Higher-traffic example (2,000 GiB/month):
monthly_waste = 2,000 × $0.045 = $90.00/month
endpoint_cost = $64.80/month
monthly_savings = $90.00 - $64.80 = $25.20/month ✓

5. Spot Opportunity

Inputs

InputSourceExample
workload_is_statelessNo PVCs, no StatefulSettrue
workload_replicasDeployment .spec.replicas4
workload_has_pdbPodDisruptionBudget existstrue
workload_node_typeNode capacity-type labelon-demand
workload_monthly_costAllocated node cost for this workload$280.00
spot_discountTypical Spot discount (region/instance dependent)0.65 (65% off)

Spot Eligibility Criteria

A workload is Spot-eligible if ALL of:

  • Stateless (no PersistentVolumeClaims)
  • Not a database or stateful system (not a StatefulSet)
  • Has multiple replicas (replicas > 1)
  • Has a PodDisruptionBudget configured
  • Currently running on On-Demand nodes

Getting Accurate Spot Pricing

The default 65% discount is a conservative estimate. For production-grade findings, query actual Spot prices for the customer's instance types and region:

# Get current Spot prices for the instance types in use
aws ec2 describe-spot-price-history \
--instance-types m5.xlarge m6g.xlarge c5.xlarge c7g.xlarge \
--product-descriptions "Linux/UNIX" \
--start-time "$(date -u +%Y-%m-%dT%H:%M:%S)" \
--query 'SpotPriceHistory[].{Type:InstanceType,AZ:AvailabilityZone,Price:SpotPrice}' \
--output table

When live Spot pricing is available:

  • Use actual_spot_discount = 1 - (spot_price / on_demand_price) per instance type
  • Confidence level: High
  • Report exact dollar savings

When live Spot pricing is NOT available (no ec2:DescribeSpotPriceHistory permission):

  • Use 65% default discount
  • Confidence level: Medium
  • Prefix savings with "~" (approximate)

Calculation

# Identify Spot-eligible workloads currently on On-Demand
spot_eligible = [
w for w in workloads
if w.is_stateless
and w.replicas > 1
and w.has_pdb
and w.node_capacity_type == "on-demand"
and not w.is_statefulset
]

# Per workload
on_demand_cost = workload_monthly_cost
spot_savings = on_demand_cost * spot_discount # typically 60–70%

monthly_waste = spot_savings # "waste" = premium paid for On-Demand
monthly_savings = spot_savings

# Aggregate
total_spot_opportunity = sum(w.monthly_savings for w in spot_eligible)

Worked Example

Workload: frontend/web-app
Replicas: 6
Stateless: yes (no PVCs)
PDB: yes (minAvailable: 4)
Current capacity: On-Demand (m5.xlarge nodes)
Monthly cost: $280.00

Spot discount for m5.xlarge in us-east-1: ~65%

Calculation:
monthly_waste = $280.00 × 0.65 = $182.00/month
monthly_savings = $182.00/month

Cluster has 5 Spot-eligible workloads:
| Workload | Monthly Cost | Spot Savings |
|----------|-------------|--------------|
| frontend/web-app | $280 | $182 |
| api/gateway | $420 | $273 |
| workers/processor | $560 | $364 |
| cache/redis-proxy | $140 | $91 |
| monitoring/collector | $96 | $62 |
| **Total** | **$1,496** | **$972/month** |

total_annual_savings = $972 × 12 = $11,664/year
effort: Medium (create Spot NodePool, add tolerations, verify PDBs)

6. Graviton Opportunity

Inputs

InputSourceExample
workload_architectureNode label kubernetes.io/archamd64
image_supports_arm64docker manifest inspect or ECR image indextrue
workload_monthly_costAllocated node cost$192.00
graviton_discountGraviton vs x86 price differential0.20 (20% cheaper)

Graviton Eligibility Criteria

A workload is Graviton-eligible if:

  • Currently running on x86 (amd64) nodes
  • Container image supports arm64 platform (multi-arch manifest)
  • No x86-specific binary dependencies (e.g., custom native libraries compiled for x86 only)

Calculation

# Identify Graviton-eligible workloads on x86
graviton_eligible = [
w for w in workloads
if w.current_arch == "amd64"
and w.image_supports_arm64
and not w.requires_x86_specific_features
]

# Per workload
x86_cost = workload_monthly_cost
graviton_savings = x86_cost * graviton_discount # typically 20%

monthly_waste = graviton_savings # "waste" = premium paid for x86
monthly_savings = graviton_savings

# Aggregate
total_graviton_opportunity = sum(w.monthly_savings for w in graviton_eligible)

Checking arm64 Support

# Check if image has arm64 manifest
docker manifest inspect nginx:1.25 | jq '.manifests[] | select(.platform.architecture == "arm64")'

# For ECR images:
aws ecr batch-get-image --repository-name my-app --image-ids imageTag=latest \
--query 'images[].imageManifest' | jq -r '.' | jq '.manifests[].platform.architecture'

Worked Example

Workload: api/order-service
Current arch: amd64 (running on m5.xlarge)
Image: 123456789.dkr.ecr.us-east-1.amazonaws.com/order-service:v2.1
arm64 support: yes (multi-arch image)
Monthly cost on x86: $192.00

Graviton equivalent: m6g.xlarge (20% cheaper than m5.xlarge)
m5.xlarge: $0.192/hr
m6g.xlarge: $0.154/hr (19.8% savings)

Calculation:
monthly_waste = $192.00 × 0.20 = $38.40/month
monthly_savings = $38.40/month

Cluster has 8 Graviton-eligible workloads:
Total x86 monthly cost: $2,400.00
total_monthly_savings = $2,400 × 0.20 = $480.00/month
total_annual_savings = $480 × 12 = $5,760/year

effort: Medium (build arm64 images, add nodeSelector/affinity, test)

Aggregation and Prioritization

Combining All Waste Categories

After calculating waste for each category, aggregate into a single prioritized list:

findings = []

# Compute waste (per-pod, aggregated by namespace)
for namespace in namespaces:
waste = calculate_compute_waste(namespace)
if waste.monthly_waste > 0:
findings.append({
"id": f"compute-over-provisioned-{namespace.name}",
"dimension": "compute",
"type": "over_provisioned_pods",
"affected_resource": namespace.name,
"monthly_waste": waste.monthly_waste,
"monthly_savings": waste.monthly_savings,
"effort": "low", # right-sizing requests
"confidence": "high" if has_metrics else "medium"
})

# Idle nodes
for node in idle_nodes:
findings.append({
"id": f"idle-node-{node.name}",
"dimension": "idle",
"type": "idle_node",
"affected_resource": node.name,
"monthly_waste": node.monthly_waste,
"monthly_savings": node.monthly_savings,
"effort": "low", # drain and terminate
"confidence": "high"
})

# Storage waste (gp2, unused PVCs, oversized)
# ... similar pattern for each storage sub-category

# Network waste (cross-AZ, NAT)
# ... similar pattern

# Spot opportunity
# ... similar pattern

# Graviton opportunity
# ... similar pattern

Prioritization Logic

Sort findings by savings descending, then by effort ascending:

EFFORT_ORDER = {"low": 0, "medium": 1, "high": 2}

findings.sort(key=lambda f: (
-f["monthly_savings"], # highest savings first
EFFORT_ORDER[f["effort"]] # lowest effort first (tiebreaker)
))

Severity Assignment (Based on Monthly Waste)

def assign_severity(monthly_waste: float) -> str:
if monthly_waste > 500:
return "CRITICAL"
elif monthly_waste > 200:
return "HIGH"
elif monthly_waste > 50:
return "MEDIUM"
else:
return "LOW"

Summary Aggregation

# Total savings potential
total_monthly_savings = sum(f["monthly_savings"] for f in findings)
total_annual_savings = total_monthly_savings * 12

# By dimension
savings_by_dimension = {}
for f in findings:
dim = f["dimension"]
savings_by_dimension[dim] = savings_by_dimension.get(dim, 0) + f["monthly_savings"]

# Quick wins (high savings + low effort)
quick_wins = [f for f in findings if f["effort"] == "low" and f["monthly_savings"] > 50]

Complete Worked Example (Full Cluster)

Cluster: production-us-east-1 (15 nodes, 120 pods)

Findings (sorted by savings DESC, effort ASC):

| # | Type | Resource | Monthly Waste | Monthly Savings | Effort | Severity |
|---|------|----------|---------------|-----------------|--------|----------|
| 1 | Spot opportunity | 5 workloads | $972 | $972 | Medium | CRITICAL |
| 2 | Over-provisioned | payments/ | $847 | $720 | Low | CRITICAL |
| 3 | Graviton opportunity | 8 workloads | $480 | $480 | Medium | HIGH |
| 4 | Idle nodes | 3× m5.xlarge | $414 | $414 | Low | HIGH |
| 5 | Over-provisioned | api/ | $312 | $265 | Low | HIGH |
| 6 | Oversized volumes | analytics/ | $36 | $33 | Medium | LOW |
| 7 | Unused PVCs | logging/ | $40 | $40 | Low | LOW |
| 8 | gp2 volumes | 12 PVCs | $17 | $17 | Low | LOW |
| 9 | Cross-AZ traffic | order-api | $5 | $3 | Low | LOW |

Summary:
Total monthly waste: $3,123
Total monthly savings: $2,944
Total annual savings: $35,328

Quick wins (low effort, >$50 savings):
- Right-size payments/ pods: $720/month
- Drain idle nodes: $414/month
- Right-size api/ pods: $265/month

Savings by dimension:
- Compute: $985/month (33%)
- Spot/Graviton: $1,452/month (49%)
- Idle: $414/month (14%)
- Storage: $90/month (3%)
- Networking: $3/month (<1%)

Confidence Levels

Each waste calculation has an associated confidence level based on data quality:

ConfidenceCriteriaImpact on Reporting
HighDirect metrics available (Container Insights, metrics-server, Cost Explorer)Report exact dollar amounts
MediumEstimated from node-level data or partial metricsReport as "estimated ~$X/month"
LowInferred from configuration only (no utilization data)Report as "potential savings up to $X/month"
def determine_confidence(data_sources: list[str]) -> str:
if "cost_explorer" in data_sources or "container_insights" in data_sources:
return "high"
elif "metrics_server" in data_sources or "node_metrics" in data_sources:
return "medium"
else:
return "low"

Notes

  • All prices are US East (N. Virginia) On-Demand rates. Use the AWS Price List API for region-specific pricing (see cost-estimation-fallback.md Step 2).
  • Spot discounts vary by instance type and region (40–90%). Use 65% as conservative default. For production accuracy, query live Spot prices:
    aws ec2 describe-spot-price-history \
    --instance-types <type1> <type2> \
    --product-descriptions "Linux/UNIX" \
    --start-time "$(date -u +%Y-%m-%dT%H:%M:%S)" \
    --query 'SpotPriceHistory[].{Type:InstanceType,AZ:AvailabilityZone,Price:SpotPrice}' \
    --output table
  • Graviton savings vary by instance family (15–40%). Use 20% as conservative default.
  • Cross-AZ pricing is consistent across regions ($0.01/GiB each direction).
  • NAT Gateway pricing is consistent across regions ($0.045/GiB processed).
  • Storage pricing varies by region; us-east-1 rates used as reference.
  • EKS control plane cost: $0.10/hr (standard support) or $0.60/hr (extended support for older K8s versions). Always check the cluster's K8s version — see cost-estimation-fallback.md for details.
  • Static pricing data in this file is a fallback. The skill should prefer live API lookups for dollar-accurate findings. Mark findings using static prices as "Medium" or "Low" confidence.