If your monthly cloud bill keeps climbing while nobody can explain why, the fastest fix is a FinOps framework: a repeatable operating model that gives engineering, finance, and product a shared view of spend and a shared responsibility for reducing it. In my experience, most overspend comes from oversized instances, forgotten resources, and pricing commitments left on the table, not from any single dramatic mistake. This guide walks through a practical, step-by-step approach to cloud cost optimization on AWS and Google Kubernetes Engine (GKE) that you can start applying this week.
FinOps is not a tool you buy. It is a discipline: measure, allocate, optimize, and govern, on a loop. Below I break down each phase with concrete commands and checkpoints so you can reduce AWS costs and tighten GKE cost management without slowing your teams down.
Why a FinOps Framework Beats One-Off Cost Cuts
Ad hoc cost cutting produces a sawtooth pattern. Someone deletes idle resources in a panic, spend drops, then quietly creeps back up because nothing changed structurally. A FinOps framework fixes the structure. It assigns ownership, makes cost visible where engineers already work, and builds optimization into the normal delivery cycle.
The FinOps Foundation describes three iterative phases: Inform, Optimize, Operate (finops.org). I use those phases as the backbone here, with specific AWS and GKE tactics attached to each.
Phase 1: Inform (Get Visibility and Allocation Right)
You cannot optimize what you cannot see. Before touching a single instance, make spend visible and attributable.
Step 1: Enforce a tagging and labeling standard
Untagged resources are the single biggest blocker to cost allocation. Decide on a small, mandatory set of tags and enforce them.
A minimal standard I recommend:
owner(team or email)env(prod, staging, dev)service(the application or component)cost-center(for chargeback)
On AWS, activate cost allocation tags in the Billing console, then enforce them with a Service Control Policy or AWS Config rule. On GKE, use labels on namespaces, workloads, and the underlying node pools:
# Label a GKE namespace for cost allocation
kubectl label namespace payments \
owner=payments-team env=prod service=checkout cost-center=cc-4471
# Enforce required labels at admission with a policy engine
# (Gatekeeper / Kyverno) rather than relying on discipline alone
Step 2: Turn on the native cost tools
Both platforms give you enough to start without third-party spend.
- AWS Cost Explorer for trend analysis and forecasting.
- AWS Cost and Usage Report (CUR) delivered to S3 for granular, queryable data. Query it with Athena.
- GKE cost allocation, which breaks spend down by namespace and label when enabled on the cluster.
- BigQuery billing export for Google Cloud, so you can join usage with labels in SQL.
A quick Athena query against the CUR to find your top-spending services:
SELECT line_item_product_code,
ROUND(SUM(line_item_unblended_cost), 2) AS cost
FROM cur_table
WHERE line_item_usage_start_date >= DATE '2024-01-01'
GROUP BY line_item_product_code
ORDER BY cost DESC
LIMIT 10;
Step 3: Publish spend where teams see it
Visibility that lives only in a finance spreadsheet changes nothing. Push a weekly per-team cost summary into Slack or a dashboard the engineers already open. The goal is to make cost a normal engineering metric, next to latency and error rate. When we structure this for clients across our cloud and infrastructure capabilities, the behavioral shift from visibility alone often accounts for the first meaningful drop in spend.
Phase 2: Optimize (Cut the Waste)
With allocation in place, you can attack cost directly. Work in order of effort-to-savings: idle resources first, then rightsizing, then pricing commitments.
Step 4: Kill idle and orphaned resources
These are pure waste with no downside to removing.
On AWS, look for:
- Unattached EBS volumes and old snapshots.
- Idle Elastic IPs (charged when unassociated).
- Load balancers with no healthy targets.
- Dev and staging environments running 24/7.
# Find unattached EBS volumes
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[].{ID:VolumeId,Size:Size,AZ:AvailabilityZone}' \
--output table
On GKE, the equivalent waste is idle node capacity. Enable the cluster autoscaler and, for spiky workloads, node auto-provisioning so you are not paying for nodes that hold nothing.
Step 5: Schedule non-production down
Development and staging rarely need to run outside working hours. Shutting them down nights and weekends removes roughly two thirds of their runtime. Use a scheduler like AWS Instance Scheduler, or a simple CronJob-driven scale-to-zero for GKE workloads:
# Scale a deployment to zero overnight via CronJob (illustrative)
apiVersion: batch/v1
kind: CronJob
metadata:
name: scale-down-staging
spec:
schedule: "0 20 * * 1-5" # 20:00 weekdays
jobTemplate:
spec:
template:
spec:
serviceAccountName: scaler
containers:
- name: kubectl
image: bitnami/kubectl
command:
- kubectl
- scale
- deployment/api
- --replicas=0
- -n
- staging
restartPolicy: OnFailure
Step 6: Rightsize compute
Most instances and pods are provisioned for a peak that never arrives. Use real utilization data, not guesses.
- On AWS, Compute Optimizer recommends smaller instance families based on observed CPU, memory, and network. Move workloads to newer generations (for example, Graviton-based instances) where compatible, since they often deliver better price-performance.
- On GKE, use the Vertical Pod Autoscaler in recommendation mode to see how far your CPU and memory requests are from actual use. Overstated requests directly inflate node count.
# Get VPA recommendations without auto-applying them
kubectl get vpa api-vpa -n prod -o \
jsonpath='{.status.recommendation.containerRecommendations}'
Set requests close to real usage, keep limits sane, and let the autoscaler pack pods more densely. Bin-packing efficiency is where a lot of GKE cost management wins hide.
Step 7: Commit to the right pricing model
Once your baseline is stable, buy discounts for it. This is often the largest single lever for reducing AWS costs.
- AWS Savings Plans or Reserved Instances for steady-state compute. Compute Savings Plans give the most flexibility across instance families and regions.
- Spot Instances for fault-tolerant, interruptible work such as batch jobs and stateless workers.
- On Google Cloud, Committed Use Discounts (CUDs) for predictable usage and Spot VMs for GKE node pools running interruption-tolerant workloads.
A practical rule: cover your stable floor with commitments, run the volatile top with on-demand and spot. Do not over-commit. A commitment you cannot use is just prepaid waste.
Phase 3: Operate (Make It Stick)
Optimization without governance decays. This phase turns cost control into a habit.
Step 8: Set budgets and anomaly alerts
Create budgets per team and environment, with alerts at 80% and 100% of forecast. Enable AWS Cost Anomaly Detection and Google Cloud budget alerts so a runaway job pages someone within hours, not at the end of the month.
Step 9: Assign clear ownership
Each service should have a named owner accountable for its spend. FinOps works when the person who provisions resources also sees the bill. This accountability model matters more than any tool, and it looks different depending on your sector. We have seen it play out across regulated and high-scale industries we work with, where compliance constraints shape how aggressively you can schedule or move workloads.
Step 10: Review on a cadence
Run a short monthly FinOps review with engineering and finance in the same room. Standing agenda:
- Top movers in spend, up and down.
- Commitment coverage and utilization.
- Open optimization actions and their owners.
- Anomalies and what caused them.
Keep it to 30 minutes. The point is momentum, not ceremony.
A Realistic Sequencing Plan
If you are starting from zero, resist the urge to do everything at once:
- Weeks 1-2: Tagging standard, native cost tools on, weekly report published.
- Weeks 3-4: Delete idle resources, schedule non-prod down.
- Weeks 5-8: Rightsize with Compute Optimizer and VPA data.
- Week 8 onward: Buy Savings Plans and CUDs for the stabilized baseline, then operate the monthly loop.
Front-loading visibility means every later step is measurable. You will know exactly what each change saved, which is what keeps a FinOps program funded.
FAQ
What is the difference between FinOps and traditional cost cutting?
Traditional cost cutting is reactive and one-time. A FinOps framework is a continuous operating model that makes cost visible to engineers, assigns ownership, and builds optimization into the delivery cycle. The result is durable savings rather than a temporary dip.
Which should I optimize first, AWS or GKE?
Optimize wherever your spend and waste are highest, which the Inform phase reveals. The tactics differ (Savings Plans and instance rightsizing on AWS, autoscaling and pod request tuning on GKE) but the sequence is the same: visibility, then waste removal, then rightsizing, then commitments.
How much can a FinOps framework save?
Savings depend entirely on your current maturity, so any fixed percentage would be a guess. In general, the largest early wins come from eliminating idle resources, scheduling non-production down, and rightsizing overprovisioned compute, before you even touch pricing commitments.
Do I need a third-party FinOps tool to start?
No. AWS Cost Explorer, the Cost and Usage Report with Athena, GKE cost allocation, and BigQuery billing export are enough to run the full loop. Add third-party tooling later if reporting overhead justifies it.
Who should own FinOps in my organization?
Ownership is shared. Engineering owns provisioning decisions, finance owns budgeting and forecasting, and a small FinOps function or working group coordinates the loop. The key is that whoever spends can also see the resulting cost.
Production-grade cloud, software, and engineering teams for scaling companies.