\n\n\n\n My May 2026 Cloud Bill: The Serverless Lie? - AgntMax \n

My May 2026 Cloud Bill: The Serverless Lie?

📖 10 min read•1,934 words•Updated May 13, 2026

Hey everyone, Jules Martin here, back on agntmax.com. It’s May 13, 2026, and if you’re anything like me, you’ve probably spent the last few weeks staring at your cloud bills with a mixture of dread and disbelief. What gives? We all preach about serverless, about autoscaling, about paying only for what you use. But lately, it feels like “what you use” is a euphemism for “everything, all the time, forever.”

Today, I want to talk about cost. Specifically, about the silent killer of tech budgets: idle resource waste in our serverless and containerized environments. This isn’t about picking the wrong instance type or over-provisioning a database (though those are certainly problems). This is about the insidious little charges that pile up when your perfectly scaled-down Lambda function still has cold starts, or when your Kubernetes pods are just sitting there, waiting for the next request that might never come, all while consuming some baseline resources.

I’ve been deep in the trenches on a project for a client, a mid-sized e-commerce platform that saw a massive spike in traffic during a holiday sale last year. They scaled up beautifully, handled the load like champs. The problem? They didn’t scale down with the same grace. Their post-sale cloud bill looked like they were still running a Black Friday event in February. It was a wake-up call, not just for them, but for me too.

The Illusion of “Pay-Per-Use” and the Reality of Idle Charges

We’ve been sold a dream, haven’t we? Serverless means you pay only when your code runs. Containers mean you pack more into less. Both are true, to an extent. But there’s a crucial caveat: there’s always a cost to keeping things ready. Think about your car. You pay for gas when you drive it. But you also pay for insurance, maintenance, and depreciation even when it’s just sitting in your driveway. Cloud resources are similar.

For Lambda, it’s the provisioned concurrency you might enable to avoid cold starts. For Kubernetes, it’s the baseline CPU/memory requested by pods, even if they’re mostly idle, plus the cost of the underlying nodes themselves. Even with auto-scaling groups, there’s a lag. You scale up quickly, but scaling down often involves waiting for connections to drain or for a minimum number of instances to remain active.

I remember one specific incident. We had a Lambda function, critical for processing post-purchase analytics. During peak hours, it would get hundreds of invocations a second. Off-peak, maybe one every few minutes. To mitigate cold starts during those critical peak hours, we enabled provisioned concurrency for 10 instances. Smart move, right? For the peak, absolutely. For the 20 hours a day it was mostly idle? We were paying for 10 warm instances, doing almost nothing. It wasn’t a huge amount individually, but multiply that by dozens of functions across several environments, and suddenly you’re looking at a significant chunk of change.

Spotting the Silent Resource Drainers

So, how do we find these hidden costs? It’s not always obvious from a high-level cloud bill. You need to dig into the specifics.

1. CloudWatch/Monitoring Logs: Your Best Friend

This is where the rubber meets the road. For AWS Lambda, look at invocation counts versus `ConcurrentExecutions` and `ProvisionedConcurrentExecutions`. If your `ProvisionedConcurrentExecutions` is consistently higher than `ConcurrentExecutions` during non-peak hours, you’re paying for idle capacity.

For Kubernetes, you need to look at actual CPU/memory utilization inside your pods versus what’s `requested` and `limited`. Tools like Prometheus and Grafana are invaluable here. If a pod `requests` 1 CPU core but only uses 0.1 CPU core for 90% of its uptime, that 0.9 CPU core is essentially idle waste, especially if it prevents other pods from being scheduled on that node or forces the cluster autoscaler to spin up more nodes than necessary.


# Example Prometheus query for average CPU utilization vs. requests over time
avg_over_time(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace="my-app"}[5m])
/
avg_over_time(kube_pod_container_resource_requests{namespace="my-app",resource="cpu"}[5m])

This kind of query gives you a utilization percentage. If it’s consistently low across many pods, you have a sizing problem.

2. Reviewing Serverless Concurrency Settings

This is low-hanging fruit. For AWS Lambda, check your functions’ “Configuration” -> “Concurrency” settings. Do you have specific reserved concurrency or provisioned concurrency configured?

Reserved concurrency can be good to protect critical functions, but it effectively dedicates a slice of your account’s total concurrency limit to that function, whether it’s running or not. Provisioned concurrency is even more direct: you pay for those instances to be warm and ready.

My client had provisioned concurrency set to 5 for a batch processing function that only ran for an hour every night. For the other 23 hours, those 5 instances were just sitting there, costing money. We switched it to a scheduled scaling policy:


# Example AWS CLI command for updating provisioned concurrency on a schedule
# This isn't a direct "schedule" but you can use EventBridge to trigger updates.

# Set provisioned concurrency to 5 during peak window (e.g., 9 AM to 5 PM UTC)
aws lambda put-function-concurrency \
 --function-name MyBatchProcessorFunction \
 --provisioned-concurrency-config '{"RequestedProvisionedConcurrentExecutions": 5}'

# Set provisioned concurrency to 0 during off-peak window (e.g., 5 PM to 9 AM UTC)
aws lambda put-function-concurrency \
 --function-name MyBatchProcessorFunction \
 --provisioned-concurrency-config '{"RequestedProvisionedConcurrentExecutions": 0}'

This needs to be automated with something like AWS EventBridge rules triggering Lambda functions that run these `put-function-concurrency` commands on a schedule. It added a tiny bit of operational overhead, but the cost savings were immediate and substantial.

3. Kubernetes Resource Requests and Limits

This is a big one. Many teams, in the interest of stability, set generous CPU and memory requests for their pods. The thinking goes, “better safe than sorry.” While understandable, it’s a direct path to overspending.

When you set `requests` in your pod YAML, you’re telling Kubernetes, “I need at least this much.” The scheduler uses this to decide where to place your pod. If your `request` is too high, you might end up with nodes that are “full” on paper but have a lot of actual idle capacity, leading the cluster autoscaler to spin up new nodes prematurely.

My advice? Start with conservative requests and monitor actual utilization. Gradually increase if you see throttling or OOM errors. Better yet, use a Vertical Pod Autoscaler (VPA) if your cluster supports it. VPA can observe your pod’s historical resource usage and recommend (or even automatically apply) optimal CPU and memory requests.

For a basic deployment, you might have something like this:


apiVersion: apps/v1
kind: Deployment
metadata:
 name: my-api-deployment
spec:
 replicas: 3
 selector:
 matchLabels:
 app: my-api
 template:
 metadata:
 labels:
 app: my-api
 spec:
 containers:
 - name: my-api-container
 image: myrepo/my-api:v1.0.0
 resources:
 requests:
 cpu: "100m" # 0.1 CPU core
 memory: "128Mi"
 limits:
 cpu: "500m" # 0.5 CPU core
 memory: "256Mi"

If monitoring shows that `my-api-container` rarely goes above 20m CPU and 50Mi memory, those `requests` are too high. Adjust them downwards. The `limits` are important for preventing runaway processes, but the `requests` are what drive scheduling decisions and, consequently, node costs.

Strategies for Cutting the Fat

Once you’ve identified where the idle resources are lurking, it’s time to take action.

1. Dynamic Provisioned Concurrency for Lambda

As mentioned, don’t just set and forget provisioned concurrency. Use scheduled events (EventBridge) or even metric-based auto-scaling for provisioned concurrency (if your cloud provider supports it, AWS recently added this) to match demand. If your function only sees heavy traffic during business hours, scale provisioned concurrency down to zero or a minimal amount overnight and on weekends.

2. Rightsizing Kubernetes Pods and Nodes

This is an ongoing process. Use monitoring data to regularly review and adjust your `requests` and `limits`. Don’t just set them once and forget them. For nodes, consider using spot instances for fault-tolerant workloads to further reduce costs, but be aware of their ephemeral nature.

For the client’s e-commerce platform, we found that many of their internal service pods were requesting 500m CPU and 512Mi memory. After analyzing their actual usage over a month, we saw they rarely spiked above 50m CPU and 100Mi memory. We adjusted the requests downwards significantly. This allowed their existing nodes to host more pods, reducing the need for the cluster autoscaler to provision new nodes. The savings on node hours alone were eye-opening.

3. Aggressive Scaling Policies

Be more aggressive with your downscaling policies. For AWS Auto Scaling Groups (ASG), ensure your scale-in policies are active and have appropriate cooldown periods. Don’t be afraid to scale down to zero instances if your architecture supports it (e.g., stateless applications behind a load balancer). For Kubernetes, configure your cluster autoscaler to be more aggressive in removing underutilized nodes.

One common pitfall I see is setting a minimum instance count that’s too high. While it provides peace of mind, it directly translates to idle costs. Challenge those minimums. Can you handle a slightly slower ramp-up if it means significant savings?

4. Spot Instances and Serverless Containers (e.g., Fargate Spot)

For workloads that can tolerate interruptions, spot instances are a goldmine for cost savings. AWS Fargate Spot, for instance, allows you to run your containers on spare Fargate capacity at a steep discount. If your application components are designed to be fault-tolerant and can resume work after an interruption, this is a fantastic way to cut costs on idle or fluctuating workloads.

5. Optimize for Cold Starts (When Necessary)

Sometimes, avoiding cold starts is critical for user experience. But don’t pay for it unnecessarily. Instead of blanket provisioned concurrency for all functions, consider optimizing the functions themselves. For Lambda, this means:

  • Using smaller deployment packages.
  • Choosing lighter runtimes (Node.js, Python often have faster cold starts than Java, .NET).
  • Optimizing initialization code.

Only if these optimizations aren’t enough and the cold start impact is truly detrimental, then consider targeted provisioned concurrency or reserved concurrency for that specific function during its actual peak hours.

Actionable Takeaways for Today, May 13, 2026

Alright, let’s wrap this up with some concrete steps you can take starting right now:

  1. Audit Your Cloud Bills: Don’t just look at the total. Drill down into specific services. Identify the top spenders. Then, for those top spenders, look for resource types that often correlate with idle time (e.g., Lambda concurrency, EC2 instances, Kubernetes nodes).
  2. Monitor Utilization vs. Provisioned/Requested: This is non-negotiable. Set up dashboards that clearly show actual CPU/memory usage against what you’re paying for (provisioned concurrency, pod requests). If you’re not doing this, you’re flying blind.
  3. Review Lambda Concurrency Settings: Go through every Lambda function. Do you have `ReservedConcurrency` or `ProvisionedConcurrency` set? If so, is it truly necessary 24/7? Can you dynamically adjust it based on schedules or metrics?
  4. Rightsize Kubernetes Resources: For your Kubernetes deployments, review `requests` and `limits` for all containers. Use your monitoring data (Prometheus, etc.) to inform these adjustments. Aim for `requests` that are closer to actual average utilization, allowing `limits` to handle spikes.
  5. Aggressive Downscaling: Re-evaluate your auto-scaling policies. Can you scale down faster? Can you scale down to fewer minimum instances/pods? Test these changes carefully in a lower environment first to understand the impact.
  6. Consider Spot Instances: For non-critical, fault-tolerant workloads, explore using spot instances or Fargate Spot. The cost savings can be immense.

Idle resource waste is a silent killer, but it doesn’t have to be. With a bit of vigilance and the right tools, you can trim the fat from your cloud bill and ensure you’re truly only paying for what you use, when you use it. It’s not always glamorous work, but it pays off, literally.

That’s all for now. Let me know your own experiences with idle resource costs in the comments below. What strategies have worked for you?

đź•’ Published:

✍️
Written by Jake Chen

AI technology writer and researcher.

Learn more →
Browse Topics: benchmarks | gpu | inference | optimization | performance
Scroll to Top