Master FinOps for Kubernetes — understand unit economics, implement cost visibility with Kubecost, cut EC2 costs 60-70% with Karpenter and Spot instances, and right-size workloads to eliminate waste.
It is 2pm on a Tuesday. Your CFO walks over with last month's AWS bill. "Why did cloud spend go up 40%?" You stare at the invoice — EC2, EKS, NAT Gateway, data transfer, something called Elastic Load Balancing — and you have no idea which of your fifteen applications caused the spike. This happens at every Indian product company at some point. Zerodha, Razorpay, Swiggy — they all faced it. Kubernetes made deployments easy but created a cost attribution nightmare. When everything runs as pods on shared nodes in shared clusters, the clean lines between "your application" and "my application" disappear into a blur of resource requests and cluster overhead. The deeper problem: most teams are running Kubernetes clusters at 12% average CPU utilisation. They are paying for 100% and using 12%. The rest is either idle capacity, over-provisioned pods, or missing Spot coverage. **FinOps** is the discipline that fixes this. It brings together engineering, finance, and business teams to answer three questions: * What is actually running and what does it cost? * Is the cost proportional to the value it delivers? * What can be eliminated, rightsized, or discounted? This module teaches you the tools and patterns to answer all three. ---
The FinOps Foundation defines three phases that teams cycle through continuously. Understanding this cycle prevents the most common mistake: jumping to cost cuts before you understand what you are cutting. ``` INFORM → OPTIMIZE → OPERATE → back to INFORM ``` **Inform** — Get visibility before doing anything else. You cannot optimise what you cannot see. This phase is about understanding where money is going: which namespaces, which teams, which services, which cloud resources. **Optimize** — Once you have visibility, identify what to change. Rightsizing over-provisioned pods. Moving workloads to Spot instances. Purchasing Reserved Instances for stable baseline workloads. Eliminating idle resources. **Operate** — Implement the changes, measure the results, and build accountability. Give teams ownership of their costs. Set budgets and alerts. Make cost a first-class concern in every deployment decision. > 📌 **Remember:** Most teams start at Optimize — buying commitments, switching to Spot, rightsizing — without going through Inform first. This is how you accidentally cut the wrong thing and break production. Always spend at least two weeks in Inform mode before touching anything. ---
Raw cloud spend is a meaningless number without context. ₹50L per month — is that good or bad? It depends entirely on what that money produces. **Unit economics** is the cost of delivering one unit of product value: ``` Cost per active user = Total infra spend ÷ Monthly active users Cost per API request = API tier spend ÷ Monthly API requests Cost per payment = Payment service spend ÷ Payments processed Cost per order = Backend spend ÷ Orders fulfilled ``` This is how mature engineering teams at Swiggy and PhonePe think about infrastructure cost — not as an absolute number but as a ratio against business output. **Example — a healthy vs unhealthy trend:** ``` Month 1: MAU: 500,000 Infra spend: ₹20L Cost per MAU: ₹4.00 Month 2: MAU: 600,000 (+20%) Infra spend: ₹30L (+50%) Cost per MAU: ₹5.00 ← Getting worse Month 3: MAU: 700,000 (+17%) Infra spend: ₹31L (+3%) Cost per MAU: ₹4.43 ← Getting better (rightsizing worked) ``` The first metric tells you the cloud bill went up. The second tells you whether you are becoming more or less efficient as you scale. They are completely different questions. ### Showback vs Chargeback Before implementing cost attribution, understand what you are actually trying to achieve. **Showback** — Show teams how much their applications cost without affecting their budgets. Informational only. Goal: awareness and behaviour change through transparency. This is where everyone should start. **Chargeback** — Costs actually flow into team budgets. Real money changes hands. This requires defensible accuracy because teams will challenge charges they do not understand. > 💡 **Tip:** Start with showback. Run it for 2-3 months before considering chargeback. In that time you will find attribution gaps, fix labelling issues, and build team trust in the numbers. Chargeback before accuracy is established destroys team relationships faster than any cost savings justify. ---
The hardest part of Kubernetes FinOps is that shared infrastructure costs genuinely cannot be cleanly attributed to individual applications. Trying to force perfect attribution creates false precision. ### What Can Be Directly Attributed | Cost Type | Attribution Method | |:---|:---| | Pod compute (CPU + memory) | Namespace resource consumption | | Persistent volumes | PVC per application | | RDS / managed databases | Tagged per application | | ElastiCache / Redis | Tagged per application | | S3 buckets | Tagged per application | ### What Cannot Be Cleanly Attributed | Shared Cost | Why It Is Shared | |:---|:---| | EKS control plane ($73/month) | One cluster, all applications benefit | | Cluster Autoscaler | Scales nodes for everyone | | Nginx Ingress Controller | Routes traffic for all services | | CoreDNS, kube-proxy | Kubernetes system services | | Prometheus, Grafana | Monitoring for all teams | | NAT Gateway | Outbound internet for all pods | | Idle/headroom capacity | Reserved for spikes, not any one app | ### The Proportional Allocation Formula Rather than forcing attribution of shared costs, distribute them proportionally based on each application's share of directly attributable costs. ``` Direct Attribution (70% of spend): payment-service: ₹4.2L (20%) order-service: ₹6.3L (30%) user-service: ₹4.2L (20%) restaurant-service: ₹6.3L (30%) Total: ₹21L Shared Costs (30% of spend): EKS control plane, ingress, monitoring, idle: ₹9L Each service's share of shared costs = their % of direct costs × ₹9L payment-service: 20% × ₹9L = ₹1.8L order-service: 30% × ₹9L = ₹2.7L Final total per service: payment-service: ₹4.2L + ₹1.8L = ₹6.0L order-service: ₹6.3L + ₹2.7L = ₹9.0L ``` This model is honest, defensible, and easy to explain. It acknowledges that shared infrastructure exists rather than pretending everything can be attributed to individual pods. ---
Cost attribution breaks down without consistent resource tagging. A tag applied to 80% of resources is nearly useless — you will always be chasing the untagged 20%. ### Mandatory Tags for Every Resource ```yaml ## Apply to all Kubernetes workloads labels: team: platform ## owning team app: payment-service ## application name environment: production ## prod / staging / dev cost-center: engineering ## for finance allocation ## Apply to all AWS resources (EC2, RDS, S3, etc.) tags: Team: platform Application: payment-service Environment: production CostCenter: engineering ManagedBy: terraform ``` ### Namespace-Based Attribution — The Simplest Approach The cleanest attribution model uses one namespace per application. Each application owns its namespace. Everything in that namespace is attributed to that application. No complex label matching required. ```bash ## View resource consumption per namespace kubectl top pods -n production --sort-by=cpu kubectl top pods -n production --sort-by=memory ## Check resource requests (what you are paying for) kubectl get pods -n production -o custom-columns=\ NAME:.metadata.name,\ CPU_REQ:.spec.containers[0].resources.requests.cpu,\ MEM_REQ:.spec.containers[0].resources.requests.memory ``` ---
Kubecost is the standard tool for Kubernetes cost monitoring. It breaks down spending by namespace, deployment, service, and label — giving you the visibility that the AWS bill alone cannot provide. ### Installing Kubecost ```bash ## Add Kubecost Helm repository helm repo add kubecost https://kubecost.github.io/kubecost/ helm repo update ## Install Kubecost helm install kubecost kubecost/kubecost \ --namespace kubecost \ --create-namespace \ --set global.clusterId="production-cluster" ## Wait for pods to be ready kubectl get pods -n kubecost -w ## Access the dashboard kubectl port-forward -n kubecost svc/kubecost-frontend 9090:9090 ## Open: http://localhost:9090 ``` ### Production Kubecost Configuration ```yaml ## kubecost-values.yaml global: clusterId: "production-cluster" ## Persistent storage so cost history survives pod restarts localStore: persistentVolume: enabled: true size: 32Gi ## Enable network cost tracking networkCosts: enabled: true ## Saved reports for monthly reviews savedReports: enabled: true reports: - title: "Production namespace costs — 30 days" window: "30d" aggregateBy: "namespace" idle: "separate" ## Budget alerts notifications: alertConfigs: globalSlackWebhookUrl: "https://hooks.slack.com/services/xxx" alerts: ## Alert when production spend exceeds ₹50K/day - type: budget threshold: 50000 window: 1d aggregation: namespace filter: production ## Alert when efficiency drops below 50% - type: efficiency efficiencyThreshold: 0.5 spendThreshold: 10000 window: 24h aggregation: namespace filter: production ``` ### Label Your Workloads for Kubecost Attribution ```yaml ## Add these labels to every Deployment for accurate team-level reporting apiVersion: apps/v1 kind: Deployment metadata: name: payment-service namespace: production labels: app: payment-service team: payments environment: production cost-center: CC-001 spec: template: metadata: labels: ## Labels on pods are what Kubecost reads for allocation app: payment-service team: payments environment: production cost-center: CC-001 spec: containers: - name: payment-service resources: ## Always set requests — Kubecost uses these for cost calculation ## Missing requests = inaccurate cost attribution requests: cpu: "500m" memory: "512Mi" limits: cpu: "1000m" memory: "1Gi" ``` ### Querying Kubecost via API ```bash ## Get namespace costs for the last 30 days curl -s "http://localhost:9090/model/allocation?window=30d&aggregate=namespace" | \ jq '.data[0] | to_entries | .[] | {namespace: .key, cost: .value.totalCost}' ## Get team-level costs using label aggregation curl -s "http://localhost:9090/model/allocation?window=30d&aggregate=label:team" | \ jq '.data[0] | to_entries | .[] | {team: .key, cost: .value.totalCost}' ## Get rightsizing recommendations curl -s "http://localhost:9090/model/savings/requestSizingV2?window=7d" | \ jq '.recommendations[] | {container: .containerName, savings: .monthlySavings}' ``` ### Understanding Kubecost Efficiency Score Kubecost calculates an efficiency score for each workload: ``` Efficiency = (Actual Usage) ÷ (Resource Requests) × 100% 90-100% → Excellent. Resources well utilised. 70-89% → Good. Minor optimisation possible. 50-69% → Fair. Rightsizing recommended. Below 50% → Poor. Significant over-provisioning. Act now. ``` A cluster-wide efficiency below 50% is common and means you are paying for roughly twice what you actually need. This is where the biggest savings come from. ---
It is 2pm on a Tuesday. Your CFO walks over with last month's AWS bill. "Why did cloud spend go up 40%?" You stare at th...
The FinOps Foundation defines three phases that teams cycle through continuously. Understanding this cycle prevents the ...
Raw cloud spend is a meaningless number without context. ₹50L per month — is that good or bad? It depends entirely on wh...
The hardest part of Kubernetes FinOps is that shared infrastructure costs genuinely cannot be cleanly attributed to indi...
Cost attribution breaks down without consistent resource tagging. A tag applied to 80% of resources is nearly useless — ...
Kubecost is the standard tool for Kubernetes cost monitoring. It breaks down spending by namespace, deployment, service,...
Over-provisioning is the biggest source of waste in Kubernetes. Most engineers set resource requests generously "just to...
The Cluster Autoscaler scales nodes but uses pre-defined node groups. Karpenter is smarter — it reads pod scheduling req...
AWS Spot Instances are spare EC2 capacity sold at 60-90% discount compared to On-Demand pricing. The trade-off: AWS can ...
Without limits, one team can consume the entire cluster's resources. ResourceQuotas enforce team-level caps. LimitRanges...
Once showback is established and teams trust the numbers, implement chargeback to create real accountability. Monthly Co...
❌ Optimising before establishing visibility 💥 A team switches everything to Spot instances to save money. A stateful Ka...
Step 1 — Identify the top cost drivers Step 2 — Check for over-provisioned pods Step 3 — Find idle resources Step 4 — Ch...
This project implements a complete FinOps setup: Kubecost for visibility, Karpenter for cost-aware provisioning, VPA for...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.