Back to CI/CD Pipeline
Q36Question 36 of 56

Reducing AWS/cloud cost for idle resources without impacting performance

Key Concepts
  • Right-sizing uses CloudWatch and Compute Optimizer to find instances running far below capacity and steps them down to the smallest type that still meets performance targets.
  • Auto-scaling adjusts instance count to real demand; scaling to zero with serverless or KEDA eliminates cost entirely when there is no traffic.
  • Spot Instances give up to 90% off for fault-tolerant, interruptible work like batch settlement jobs; Savings Plans cover the always-on baseline at a committed discount.
  • Storage lifecycle rules tier cold data from S3 Standard to Infrequent Access and then to Glacier, which is critical for bank statements that must be retained for years.
  • Scheduled shutdowns turn off non-production environments at night and on weekends, typically cutting their cost by more than half.
  • Tag every resource by environment and owner so cost is attributable, and treat cost optimization as an ongoing practice, not a one-time cleanup.

Definition

Match capacity to demand: right-size, auto-scale (even to zero), buy Spot and Savings Plans, tier cold storage, and schedule shutdowns, so you cut idle cost without touching the capacity real traffic needs.
  • Right-sizing – Pick the smallest instance type that still meets your performance target, using CloudWatch metrics and AWS Compute Optimizer to find underutilized resources.
  • Auto-scaling – Adjust instance count to real demand, including scaling to zero for bursty or dev workloads using serverless (Lambda, Fargate) or Kubernetes with KEDA.
  • Spot and Savings Plans – Use Spot Instances (up to 90% off) for fault-tolerant interruptible work, and Savings Plans or Reserved Instances for the always-on baseline.
  • Storage tiering – Move cold data to cheaper storage classes (S3 IA, Glacier, Deep Archive) using lifecycle rules or Intelligent-Tiering.
  • Scheduled shutdowns – Turn off non-production environments outside business hours with EventBridge schedules, cutting their cost by more than half.

The National Bank of India does not keep every counter staffed 24 hours when only two customers come at night. You measure how busy each counter really is and swap oversized ones for right-sized ones (right-sizing), open and close counters as the queue grows and shrinks (auto-scaling), sign long-term contracts for always-needed staff at a discount (Savings Plans) and use cheap on-call temps for interruptible work (Spot), move old paperwork from the expensive front-office cabinet to a cheap basement archive (storage tiering), and switch off the training-room lights every night (scheduled shutdowns).

Understanding the Concepts

What is right-sizing?

Right-sizing means choosing the smallest instance type and size that still meets your performance target. You use CloudWatch metrics and AWS Compute Optimizer to find instances whose CPU, memory, and network sit far below their capacity, and you step them down a size. This is the safest first lever because it directly removes paid-for-but-unused capacity without changing architecture.

BASH
# Check instance utilization with CloudWatch
aws cloudwatch get-metric-statistics \
  --namespace AWS/EC2 \
  --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-0abc123 \
  --start-time 2024-01-01T00:00:00Z \
  --end-time 2024-01-08T00:00:00Z \
  --period 3600 \
  --statistics Average

# Get Compute Optimizer recommendations
aws compute-optimizer get-ec2-instance-recommendations \
  --instance-arns arn:aws:ec2:ap-south-1:123456:instance/i-0abc123
TEXT
# Example finding:
# Instance: m5.xlarge (4 vCPU, 16 GB)
# Average CPU: 12%, Average Memory: 25%
# Recommendation: m5.large (2 vCPU, 8 GB) -- 50% cost reduction
# After resize: CPU 24%, Memory 50% -- still comfortable headroom

How does auto-scaling reduce idle cost?

Auto-scaling adjusts the number of instances or Pods to current demand, so you are not paying for peak capacity around the clock. You scale out when CPU or request rate rises and scale in when it falls. Scaling to zero goes further: for bursty, event-driven, or dev workloads, let the count drop to zero when there is no traffic.

YAML
# Kubernetes HPA: scale banking-api Pods based on CPU
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: banking-api-hpa
  namespace: banking
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: banking-api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
YAML
# KEDA: Scale to zero when no messages in the queue
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: settlement-batch
  namespace: banking
spec:
  scaleTargetRef:
    name: settlement-batch
  minReplicaCount: 0           # scale to zero!
  maxReplicaCount: 10
  triggers:
    - type: aws-sqs-queue
      metadata:
        queueURL: https://sqs.ap-south-1.amazonaws.com/123456/settlement-jobs
        queueLength: "5"

How do Spot Instances and Savings Plans reduce cost?

Spot uses spare EC2 capacity at up to 90% off, ideal for fault-tolerant, interruptible work like batch settlement jobs, report generation, or stateless workers that can be rescheduled if reclaimed. Savings Plans give a large discount in exchange for a 1- or 3-year commitment on steady baseline usage.

BASH
# Launch a Spot Fleet for the nightly settlement batch
aws ec2 request-spot-fleet \
  --spot-fleet-request-config file://spot-fleet-config.json

# The key: commit only to the baseline you always use
# Savings Plan: covers the always-on production API (2 instances 24/7)
# Spot: covers the nightly batch job (runs 2 hours, interruptible)
# On-Demand: covers the variable peak above the baseline
TEXT
# Cost breakdown for National Bank of India:
# Production API:  Savings Plan  ($0.05/hr vs $0.10/hr)  = 50% savings
# Settlement batch: Spot          ($0.01/hr vs $0.10/hr)  = 90% savings
# Peak overflow:   On-Demand      ($0.10/hr)              = full price
# Dev/staging:     Scheduled off   (16 hrs/day off)       = 67% savings

How does storage lifecycle tiering work?

On S3, set lifecycle rules to transition objects from Standard to Infrequent Access after 30 days, then to Glacier after 90 days, and expire or move to Deep Archive after a year. Bank statements and audit logs are rarely read after a month but must be retained for years, so tiering saves significantly without losing data.

JSON
{
  "Rules": [
    {
      "ID": "banking-statements-lifecycle",
      "Status": "Enabled",
      "Filter": { "Prefix": "statements/" },
      "Transitions": [
        { "Days": 30, "StorageClass": "STANDARD_IA" },
        { "Days": 90, "StorageClass": "GLACIER" },
        { "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
      ],
      "Expiration": { "Days": 2555 }
    }
  ]
}
BASH
# Apply the lifecycle policy
aws s3api put-bucket-lifecycle-configuration \
  --bucket banking-statements-bucket \
  --lifecycle-configuration file://lifecycle.json

# Also clean up unattached EBS volumes
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[*].{ID:VolumeId,Size:Size,Created:CreateTime}'
# Delete any that have been unattached for weeks.

How do scheduled shutdowns save cost?

Dev, test, and staging environments do not need to run at night or on weekends. An EventBridge schedule triggering a Lambda can stop them, cutting cost by more than half.

BASH
# Create an EventBridge rule to stop dev instances at 8 PM
aws events put-rule \
  --name stop-dev-instances-nightly \
  --schedule-expression "cron(0 20 ? * MON-FRI *)"

# Lambda function (simplified) to stop tagged instances
# Triggered by the EventBridge rule
PYTHON
import boto3

def lambda_handler(event, context):
    ec2 = boto3.client('ec2', region_name='ap-south-1')
    # Find running dev instances by tag
    response = ec2.describe_instances(
        Filters=[
            {'Name': 'tag:Environment', 'Values': ['Development']},
            {'Name': 'instance-state-name', 'Values': ['running']}
        ]
    )
    instance_ids = []
    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instance_ids.append(instance['InstanceId'])
    if instance_ids:
        ec2.stop_instances(InstanceIds=instance_ids)
        print(f"Stopped {len(instance_ids)} dev instances: {instance_ids}")
    return {'stopped': len(instance_ids)}

What are common mistakes in cloud cost optimization?

BASH
# WRONG: Right-sizing production without headroom
# You resize from m5.xlarge to m5.medium based on average CPU.
# A traffic spike hits, CPU saturates, latency spikes, customers are affected.

# CORRECT: Right-size with headroom
# Resize to m5.large (one step, not two), keeping 40% CPU headroom.
# Re-measure for a week before considering another step down.

# WRONG: Committing to a 3-year Savings Plan for an uncertain workload
# The workload migrates to a different service 6 months later.
# You pay for unused commitment for 2.5 years.

# CORRECT: Commit only to the baseline you are confident you will always use.
# Cover the variable top with On-Demand or Spot.

How do you track and attribute cost?

Tag every resource by environment, team, and owner so cost is attributable. Set budgets and anomaly alerts in AWS Cost Explorer.

BASH
# Tag all resources for cost attribution
aws ec2 create-tags --resources i-0abc123 --tags \
  Key=Environment,Value=Production \
  Key=Team,Value=TransferService \
  Key=Owner,Value=rajesh

# Set a monthly budget alert
aws budgets create-budget \
  --account-id 123456789 \
  --budget file://budget.json \
  --notifications-with-subscribers file://notifications.json

What should a senior engineer know?

Cost optimization is an ongoing practice, not a one-time cleanup. The biggest savings come from continuously matching capacity to demand. A senior engineer reviews Compute Optimizer and Cost Explorer monthly, keeps tagging policies enforced, and treats cost as a first-class metric alongside latency and error rate.

BASH
# Monthly review checklist:
# 1. Check Compute Optimizer for right-sizing recommendations
# 2. Review Cost Explorer for spending trends and anomalies
# 3. Audit unattached EBS volumes and old snapshots
# 4. Verify scheduled shutdowns are running for non-prod
# 5. Check Savings Plan utilization (are you using what you committed to?)
# 6. Review S3 lifecycle policies for new buckets

Visual Overview

DIAGRAM
Cloud Cost Optimization Levers
===============================

  ┌─────────────────┐
  │  1. RIGHT-SIZE  │  Smallest instance that meets load
  │  (Compute       │  CloudWatch + Compute Optimizer
  │   Optimizer)    │
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  2. AUTO-SCALE  │  Match capacity to demand
  │  (HPA / KEDA /  │  Scale to zero for bursty workloads
  │   Serverless)   │
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  3. PRICING     │  Savings Plans for baseline
  │  (Spot / SP /   │  Spot for interruptible work
  │   RI)           │  On-Demand for variable peak
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  4. STORAGE     │  Standard -> IA -> Glacier -> Archive
  │  (Lifecycle     │  Delete unattached volumes
  │   tiering)      │
  └────────┬────────┘
           ▼
  ┌─────────────────┐
  │  5. SCHEDULE    │  Stop non-prod at night/weekends
  │  (EventBridge + │  Cuts non-prod cost by 67%+
  │   Lambda)       │
  └─────────────────┘

  Guardrail: NONE of this touches production capacity.
  Tag everything. Review monthly. Cost is a first-class metric.

Key Takeaway

Reducing cloud cost for idle resources means matching capacity to real demand without hurting performance. The safest first lever is right-sizing: use CloudWatch and Compute Optimizer to find underutilized instances and step them down while keeping headroom. Then rely on auto-scaling so you do not pay for peak capacity around the clock, and for bursty or dev workloads, scale all the way to zero using serverless or KEDA. On pricing, cover the steady always-on baseline with a Savings Plan and run interruptible work like batch settlement jobs on Spot Instances for up to 90% off.

For storage, use lifecycle rules to tier cold data from Standard to Infrequent Access and then to Glacier, which matters in banking because statements and audit logs must be retained for years but are rarely read after a month. Schedule shutdowns of non-production environments at night and on weekends, which typically cuts their cost by more than half. At the National Bank of India, this came together as a cost advisor that recommended a Savings Plan for the always-on production API, scheduled shutdowns for dev and staging, Spot for the interruptible settlement batch, and lifecycle tiering for the statements bucket.

Remember one sentence: tag every resource, match capacity to demand across all five levers, and treat cost optimization as an ongoing practice because the biggest savings come from continuously right-sizing rather than a one-time cleanup.

---

Share
Use ← → arrow keys to navigate