CloudBudgetMasterCloudBudgetMaster

← All articles

Strategy

Advanced Cloud Cost Optimization Strategy Teams Miss

August 30, 2026·6 min read·CloudBudgetMaster

The hidden cost of always‑on resources

Most engineering and platform teams focus on rightsizing instances, buying Reserved Instances, or trimming storage. A far more profitable tactic—yet rarely automated—is scheduling idle resources to stop when they are not needed and start them back up on demand. This strategy cuts compute spend without sacrificing availability, and it works across EC2, RDS, Redshift, Elasticsearch, and even SageMaker notebooks.

Step 1 – Identify truly idle resources

The first prerequisite is a reliable inventory of resources that spend money while delivering no workload. Use a combination of tags, CloudWatch metrics, and AWS Config rules.

Tagging convention

Create a mandatory tag set:

Apply the tags via the console (EC2 → Tags), the CLI, or a bulk tagging script:

aws ec2 create-tags \
  --resources $(aws ec2 describe-instances --filters "Name=tag:IdleSchedule,Values=true" --query "Reservations[].Instances[].InstanceId" --output text) \
  --tags Key=IdleSchedule,Value=true

CloudWatch metrics to spot inactivity

For each service, pick a metric that indicates work:

Service Metric Typical idle threshold
EC2 CPUUtilization < 5 % for 24 h
RDS CPUUtilization < 3 % for 48 h
Redshift CPUUtilization < 4 % for 12 h
Elasticsearch CPUUtilization < 6 % for 24 h
SageMaker notebook CPUUtilization < 2 % for 8 h

Create a CloudWatch alarm that triggers when the metric stays below the threshold for the defined period. Example for EC2:

aws cloudwatch put-metric-alarm \
  --alarm-name "Idle-EC2-CPU" \
  --metric-name CPUUtilization \
  --namespace AWS/EC2 \
  --statistic Average \
  --period 3600 \
  --evaluation-periods 24 \
  --threshold 5 \
  --comparison-operator LessThanOrEqualToThreshold \
  --dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
  --actions-enabled

Step 2 – Automate stop/start with AWS Instance Scheduler or Lambda

AWS provides a ready‑made solution called Instance Scheduler that uses Amazon EventBridge, DynamoDB, and Lambda to start and stop instances on a calendar. For finer‑grained control (e.g., per‑resource tags), a custom Lambda function is often simpler.

Using the AWS Instance Scheduler

  1. Deploy the solution from the AWS Solutions Library.
  2. Define a schedule in the DynamoDB table, e.g., workhours (08:00‑18:00 UTC, Monday‑Friday).
  3. Tag resources with Schedule=workhours.
  4. The scheduler Lambda reads the tag and starts or stops the instance accordingly.

Building a custom Lambda for tag‑driven scheduling

Create a Lambda function that runs every hour via EventBridge. The function: 1. Queries all resources with IdleSchedule=true. 2. Checks the latest CloudWatch metric. 3. Calls stop-instances or start-instances when the idle condition is met.

Sample Python snippet (run in Lambda runtime Python 3.9):

import boto3, os

ec2 = boto3.client('ec2')
cloudwatch = boto3.client('cloudwatch')

def lambda_handler(event, context):
    # Find instances with the IdleSchedule tag
    resp = ec2.describe_instances(Filters=[{'Name': 'tag:IdleSchedule', 'Values': ['true']}])
    for reservation in resp['Reservations']:
        for instance in reservation['Instances']:
            iid = instance['InstanceId']
            # Get average CPU for the last 6 hours
            metrics = cloudwatch.get_metric_statistics(
                Namespace='AWS/EC2',
                MetricName='CPUUtilization',
                Dimensions=[{'Name':'InstanceId','Value':iid}],
                StartTime=datetime.utcnow() - timedelta(hours=6),
                EndTime=datetime.utcnow(),
                Period=3600,
                Statistics=['Average']
            )
            avg_cpu = sum(p['Average'] for p in metrics['Datapoints']) / len(metrics['Datapoints'])
            if avg_cpu < 5:
                ec2.stop_instances(InstanceIds=[iid])
            else:
                ec2.start_instances(InstanceIds=[iid])

Deploy the function, grant it ec2:StartInstances, ec2:StopInstances, and cloudwatch:GetMetricStatistics permissions, and attach an EventBridge rule:

aws events put-rule --schedule-expression "rate(1 hour)" --name "IdleSchedulerRule"
aws lambda add-permission --function-name IdleScheduler --principal events.amazonaws.com --statement-id "AllowEventBridge" --action "lambda:InvokeFunction" --source-arn arn:aws:events:us-east-1:123456789012:rule/IdleSchedulerRule
aws events put-targets --rule IdleSchedulerRule --targets Id=1,Arn=arn:aws:lambda:us-east-1:123456789012:function:IdleScheduler

Step 3 – Tie scheduling to cost allocation tags and budgets

Once resources are tagged for scheduling, use Cost Allocation Tags to surface the spend of idle‑eligible assets.

aws ce enable-cost-allocation-tag --tag-key IdleSchedule

Create a budget that alerts when spend on IdleSchedule=true exceeds a threshold:

aws budgets create-budget \
  --account-id 123456789012 \
  --budget file://budget.json

budget.json example:

{
  "BudgetName": "IdleResourceSpend",
  "BudgetLimit": {"Amount": "200", "Unit": "USD"},
  "CostFilters": {"TagKeyValue": ["IdleSchedule$true"]},
  "TimeUnit": "MONTHLY",
  "BudgetType": "COST",
  "BudgetNotifications": [{
    "Notification": {"NotificationType": "ACTUAL", "ComparisonOperator": "GREATER_THAN", "Threshold": 80},
    "Subscriber": {"SubscriptionType": "EMAIL", "Address": "finops@example.com"}
  }]
}

Step 4 – Validate results with the free AWS waste finder

Before committing to a full‑scale rollout, run CloudBudgetMaster’s free AWS waste finder. The tool scans your account in read‑only mode, lists idle instances, unattached volumes, and other waste, and shows the estimated dollar impact. Use the results to prioritize which resources to bring under the scheduling framework.

Manual vs. Automated Scheduling – a quick comparison

Aspect Manual stop/start (CLI/Console) Automated scheduler (Instance Scheduler or Lambda)
Human effort High – requires daily or weekly checks Low – runs on a schedule without intervention
Error risk Medium – accidental stop of production workloads Low – policies enforced by tags and metrics
Granularity Per‑instance only Tag‑driven, can cover EC2, RDS, Redshift, etc.
Cost visibility Limited to after‑the‑fact billing reports Real‑time reduction reflected in Cost Explorer
Scalability Poor – manual steps do not scale beyond dozens of resources Excellent – one Lambda handles thousands of resources

Best practices and common pitfalls

Frequently asked questions

How do I know if an instance is safe to stop?

Check the instance’s role. Development, staging, and CI/CD runners are safe. Production web servers should have a health‑check script that confirms no active sessions before stopping.

Does stopping an EC2 instance delete its data?

No. Stopping preserves the root EBS volume and any attached volumes. However, any data stored on instance store (ephemeral) is lost, so avoid stopping instances that rely on instance store.

Can I schedule RDS snapshots before a stop?

Yes. Add a Lambda step that calls create-db-snapshot before invoking stop-db-instance. This guarantees you can restore the database to the exact pre‑stop state.

Will the scheduler affect my Reserved Instance (RI) discounts?

Stopping an RI‑covered instance does not affect the discount; you still pay the RI hourly rate. The strategy is most valuable for On‑Demand or Savings‑Plan resources that are idle.

Key takeaways

How CloudBudgetMaster helps

CloudBudgetMaster currently scans AWS accounts in read‑only mode, automatically discovers idle and wasted resources, and reports the dollar impact of each finding. GCP, Azure, and Snowflake support are coming soon. To try the detection engine, create a free account and run the free AWS waste finder.

Stop guessing where your AWS bill comes from

Upload a CSV, no signup. CloudBudgetMaster finds idle, unused, and overspending AWS resources automatically. GCP and Azure coming soon.

Run a free check