<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tal Shafir</title>
    <description>The latest articles on DEV Community by Tal Shafir (@tal_shafir_49b67973e9d3b4).</description>
    <link>https://dev.to/tal_shafir_49b67973e9d3b4</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3367011%2F9f68fb5b-a368-4a15-9c14-444f865fe456.png</url>
      <title>DEV Community: Tal Shafir</title>
      <link>https://dev.to/tal_shafir_49b67973e9d3b4</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tal_shafir_49b67973e9d3b4"/>
    <language>en</language>
    <item>
      <title>10 Mistakes You're making in Kubernetes that cost you money</title>
      <dc:creator>Tal Shafir</dc:creator>
      <pubDate>Sat, 14 Feb 2026 17:55:44 +0000</pubDate>
      <link>https://dev.to/tal_shafir_49b67973e9d3b4/10-mistakes-youre-making-in-kubernetes-that-cost-you-money-48c5</link>
      <guid>https://dev.to/tal_shafir_49b67973e9d3b4/10-mistakes-youre-making-in-kubernetes-that-cost-you-money-48c5</guid>
      <description>&lt;p&gt;Kubernetes is an incredible tool, but it's also a complex tool with a lot of buttons and levers for you to tweak.&lt;br&gt;
It's easy to make a mistake and end up paying more than you should.&lt;/p&gt;

&lt;p&gt;In this article, I'll try to list some of the most common mistakes I've seen teams make and how to avoid them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not upgrading your cluster
&lt;/h2&gt;

&lt;p&gt;This point is mainly focusing on managed Kubernetes services like GKE, EKS, AKS, etc.&lt;br&gt;
Once your Kubernetes version is old enough you need to "upgrade" your cluster to use "extended support".&lt;/p&gt;

&lt;p&gt;The Kubernetes community supports minor versions for approximately 14 months.&lt;br&gt;
Old clusters aren't just a security risk. They are a hidden tax.&lt;br&gt;
Once a version reaches its end-of-life, cloud providers force you into "extended support" to keep running it securely.&lt;br&gt;
The cost for this is high - often jumping from &lt;strong&gt;$0.10/hr&lt;/strong&gt; to &lt;strong&gt;$0.60/hr&lt;/strong&gt; for the control plane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relying on the 'Power of 2' Instinct
&lt;/h2&gt;

&lt;p&gt;We are wired to love powers of 2. It feels right. But in Kubernetes, this instinct is killing your cluster utilization.&lt;br&gt;
It's a relic of a time where we used to choose specific VMs for our workloads. In a containerized world, it's a costly habit.&lt;/p&gt;

&lt;p&gt;"How much resources does my app need?" - "Well, I'm not sure, but let's go with 2 vCPUs and 4GiB of RAM."&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the problem you ask?
&lt;/h3&gt;

&lt;p&gt;Let's think about our example with common cloud providers VM sizes.&lt;br&gt;
(For this example I chose AWS latest generation with AMD based instances of the most common families C / M / R)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;InstanceType&lt;/th&gt;
&lt;th&gt;vCPUs&lt;/th&gt;
&lt;th&gt;RAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;c8a.medium&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;m8a.medium&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r8a.medium&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;8 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c8a.large&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;m8a.large&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r8a.large&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;16 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c8a.xlarge&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;m8a.xlarge&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;16 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r8a.xlarge&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;32 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c8a.2xlarge&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;16 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;m8a.2xlarge&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;32 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r8a.2xlarge&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;64 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You're probably thinking, what's the problem? I'll give the cluster to choose from &lt;code&gt;c8a.large&lt;/code&gt; and &lt;code&gt;c8a.xlarge&lt;/code&gt; and will get 100% utilization, that would be awesome right?&lt;/p&gt;

&lt;p&gt;Not exactly.&lt;/p&gt;

&lt;p&gt;We're forgetting 2 things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DaemonSets - Your cluster definitely has some DaemonSets running, like node-exporter, kube-proxy, etc. They need resources too&lt;/li&gt;
&lt;li&gt;Node allocation overhead - the values we see in the table are the node's capacity not the allocatable resources (see &lt;a href="https://github.com/awslabs/amazon-eks-ami/blob/main/templates/al2/runtime/bootstrap.sh#L267-L302" rel="noopener noreferrer"&gt;how EKS calculates allocatable resources&lt;/a&gt; or check out this &lt;a href="https://learnkube.com/allocatable-resources" rel="noopener noreferrer"&gt;great article about allocatable resources&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's assume for a second we kept only &lt;code&gt;c8a.large&lt;/code&gt; and &lt;code&gt;c8a.xlarge&lt;/code&gt; and that our DaemonSets need around 100m cpu and 256MiB of memory.&lt;br&gt;
&lt;code&gt;c8a.large&lt;/code&gt;, even when ignoring allocatable vs capacity, is not enough for a single pod.&lt;br&gt;
&lt;code&gt;c8a.xlarge&lt;/code&gt; is enough for a single pod, but not for 2 - so we'll end up with 1 pod on a &lt;code&gt;c8a.xlarge&lt;/code&gt; node with utilization of 53% CPU / 60% Memory (2,100m / 3,910m and 4,352MiB / ~7,168 MiB).&lt;/p&gt;

&lt;p&gt;We'll be wasting almost half of our node.&lt;br&gt;
Going for a larger instance can make this issue less bad, for example if we would go with &lt;code&gt;c8a.2xlarge&lt;/code&gt; we'll end up with 3 pods on a &lt;code&gt;c8a.2xlarge&lt;/code&gt; node with utilization of 77% CPU / 81% Memory (6,100m / 7,900m and 12,544MiB / 15,360 MiB).&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;Try to avoid the power of 2 instinct and try to think about where your workloads will run.&lt;br&gt;
If for example we needed 3 pods of 2 VCPU and 4 GiB of RAM, unless we have a good reason to go with this specific size, choosing smaller/bigger pods and changing replicas accordingly will save us a lot of money.&lt;br&gt;
For example, reducing the request to &lt;strong&gt;1.8 vCPU&lt;/strong&gt; and &lt;strong&gt;3 GiB RAM&lt;/strong&gt; allows the pod to fit efficiently on &lt;code&gt;c8a.large&lt;/code&gt; with &lt;strong&gt;95% CPU / 98% Memory&lt;/strong&gt; utilization, or 2 pods on &lt;code&gt;c8a.xlarge&lt;/code&gt; with &lt;strong&gt;94% CPU / 89% Memory&lt;/strong&gt; utilization.&lt;/p&gt;

&lt;p&gt;Specific usage numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;c8a.large&lt;/code&gt;: 1,900m / 2,000m used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c8a.xlarge&lt;/code&gt;: 3,700m / 3,910m used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example we made the pods smaller, but sometimes it makes more sense to go larger — requesting 3.8 vCPU instead of 2 vCPU can pack better on certain node sizes for example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8g5ote3hu45wh1owtdy.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8g5ote3hu45wh1owtdy.png" alt="Power of 2 Bin Packing Efficiency" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; Avoid "over-fitting" your resource requests to specific node sizes or DaemonSet configurations—these can change over time. Aim for small improvements (like avoiding exact powers of 2) rather than calculating exact values to maximize utilization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Not rightsizing your resources
&lt;/h2&gt;

&lt;p&gt;In the previous section, we've seen that small tweaking of manual pod sizing can make a big change.&lt;br&gt;
In general we want our resources to be accurate as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allocating too much
&lt;/h3&gt;

&lt;p&gt;For example, requesting 3 GiB of memory for a workload that rarely uses more than 2 GiB of memory is a waste of resources. The same can be said with allocating CPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allocating too little
&lt;/h3&gt;

&lt;p&gt;Requesting too few resources can result either in failures in the workloads that are under-allocated or with a harder thing to detect - the issue of noisy neighbors.&lt;br&gt;
If many of your workloads are using 110% of their allocation, it's likely that some of them won't have available resources on the actual node.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;Don't guess the workload resource requirements, measure them.&lt;br&gt;
Usually you should start with higher resources than what you think is suitable and after a while you can measure the actual usage and adjust accordingly.&lt;/p&gt;

&lt;p&gt;There are tools for doing that automatically or semi-automatically - like &lt;a href="https://github.com/robusta-dev/krr" rel="noopener noreferrer"&gt;krr&lt;/a&gt; or &lt;a href="https://kubernetes.io/docs/tasks/run-application/vertical-pod-autoscaler/" rel="noopener noreferrer"&gt;VPA&lt;/a&gt; and other commercial tools.&lt;/p&gt;

&lt;p&gt;Personally, I think that for realtime needs of your workloads Horizontal scaling should be preferred over Vertical scaling - but now that &lt;a href="https://kubernetes.io/blog/2025/12/19/kubernetes-v1-35-in-place-pod-resize-ga/" rel="noopener noreferrer"&gt;in-place pod resize&lt;/a&gt; has reached stable in Kubernetes v1.35 and many of its earlier limitations have been removed, Vertical scaling has become a much more viable option for certain use-cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the wrong instance types
&lt;/h2&gt;

&lt;p&gt;A lot of times, teams choose a limited amount of instance types for their clusters.&lt;br&gt;
This was very common during the early days of Cluster Autoscaler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not allowing for enough sizes
&lt;/h3&gt;

&lt;p&gt;Let's take our example from the previous section, we have a 2 VCPU and 4 GiB of RAM workload.&lt;br&gt;
If we would only allow for &lt;code&gt;c8a.large&lt;/code&gt; and &lt;code&gt;c8a.xlarge&lt;/code&gt; we would end up with 1 pod on a &lt;code&gt;c8a.xlarge&lt;/code&gt; node with utilization of around 50% but by allowing for &lt;code&gt;c8a.2xlarge&lt;/code&gt; we would &lt;em&gt;sometimes&lt;/em&gt; end up with 3 pods for closer to 80% utilization.&lt;/p&gt;

&lt;p&gt;Generally speaking, larger nodes are more cost-efficient, you only need one set of DaemonSets and the Kubelet overhead and similar are lower for more resources you use - for example in CPU 6% is reserved for the first core, while only 0.25% will be reserved for the fourth core onwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not mixing instance families
&lt;/h3&gt;

&lt;p&gt;The cloud-providers have different categories for instance types, for example AWS has &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt; families - compute optimized / general purpose / memory optimized, respectively.&lt;br&gt;
Depending on your use-case, some families may suit your workload better than others. &lt;/p&gt;

&lt;p&gt;I recall a specific case where a workload needed to be scaled up due to memory issues. Our DevOps team was concerned that the new instance size would be too large - some of the largest in our fleet. &lt;br&gt;
Upon investigation, we found that our cluster was mostly configured with &lt;code&gt;c&lt;/code&gt; and &lt;code&gt;m&lt;/code&gt; families. We weren't utilizing the CPU we already had, we just needed more RAM. Switching to &lt;code&gt;r&lt;/code&gt; family instances allowed us to use a smaller tier (e.g., replacing &lt;code&gt;c&lt;/code&gt;/&lt;code&gt;m&lt;/code&gt; 8xlarge with &lt;code&gt;r&lt;/code&gt; 4xlarge), effectively solving the issue while saving money.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not allowing for instance variants
&lt;/h3&gt;

&lt;p&gt;Within each family, there are multiple variants. For example, within the &lt;code&gt;c&lt;/code&gt; (compute) family, we have for the latest generation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;c8a&lt;/li&gt;
&lt;li&gt;c8g&lt;/li&gt;
&lt;li&gt;c8gb&lt;/li&gt;
&lt;li&gt;c8gd&lt;/li&gt;
&lt;li&gt;c8gn&lt;/li&gt;
&lt;li&gt;c8i-flex&lt;/li&gt;
&lt;li&gt;c8i&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Usually the "special" instance types are more expensive than the "regular" ones, but can offer better performance in some areas (like better EBS performance for &lt;code&gt;c8gb&lt;/code&gt; or better network performance for &lt;code&gt;c8gn&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Not preparing for ARM instances
&lt;/h3&gt;

&lt;p&gt;All those instance types that ended with &lt;code&gt;g&lt;/code&gt; (&lt;code&gt;c8g&lt;/code&gt; for example) are ARM instances based on AWS Graviton.&lt;br&gt;
They are usually cheaper than their Intel/AMD based instances and offer better price-to-performance.&lt;br&gt;
Unlike the previous recommendation, this is usually not just "plug and play" and you need to have your workloads support ARM (in a lot of languages and tools it's very easy).&lt;/p&gt;

&lt;h2&gt;
  
  
  Lack of visibility
&lt;/h2&gt;

&lt;p&gt;It can be tough in large environments to find where you're less efficient or where most of the money goes.&lt;br&gt;
Optimizing by hunch often fails. You might spend a week improving a service by &lt;strong&gt;80%&lt;/strong&gt;, only to realize the total cost was just $200/month. Meanwhile, a &lt;strong&gt;5%&lt;/strong&gt; improvement on another area could have saved you $5,000/month.&lt;br&gt;
There are some great Open-source tools built for that, like &lt;a href="https://opencost.io/" rel="noopener noreferrer"&gt;OpenCost&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not considering Spot Instances and Reserved Capacity
&lt;/h2&gt;

&lt;p&gt;My view about this one may be a bit skewed as I used to work on Spot Ocean for 4 years.&lt;br&gt;
At least some parts of your workload can run on Spot Instances. This is yet again another thing that is not a "plug and play" solution — Not all workloads can run on spot instances.&lt;/p&gt;

&lt;p&gt;One of the things that was surprising to me when I started is that Spot was fully committed to "drinking your own champagne" and most of our workloads ran on spot instances and Spot products (when I started it was Spot Elastigroup and during my time there we migrated to Spot Ocean) - I would say that over 90% of our workloads ran on spot instances (excluding managed databases and very specific services/databases).&lt;/p&gt;

&lt;p&gt;Spot Instances can be a great way to save A LOT of money, but it should be handled with care.&lt;/p&gt;

&lt;p&gt;For workloads that are stable and predictable, don't forget about &lt;strong&gt;Reserved Instances&lt;/strong&gt; (or &lt;strong&gt;Savings Plans&lt;/strong&gt; on AWS / &lt;strong&gt;Committed Use Discounts&lt;/strong&gt; on GCP). If you know you'll be running a baseline capacity 24/7, committing to 1-3 years can save 30-60% compared to on-demand pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not thinking about Network costs
&lt;/h2&gt;

&lt;p&gt;Network cost is something that is often overlooked, but can be a significant cost.&lt;br&gt;
For example in AWS:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traffic Type&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Internet → EC2 (inbound)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EC2 → Internet (outbound)&lt;/td&gt;
&lt;td&gt;Free first 100 GB, then $0.09/GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EC2 → Another AWS region&lt;/td&gt;
&lt;td&gt;$0.02/GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Within same AZ&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Between AZs (same region)&lt;/td&gt;
&lt;td&gt;$0.02/GB ($0.01 in + $0.01 out)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a usual cluster, transfer to outside is not "negotiable" (e.g it's what you return to your customers) but transfer within the same region is.&lt;br&gt;
Optimizing your workloads to be closer to each other can save you a lot of money and improve performance.&lt;br&gt;
There are other Kubernetes features you can use to optimize this, like &lt;a href="https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/" rel="noopener noreferrer"&gt;topology-aware routing&lt;/a&gt; and &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#traffic-distribution" rel="noopener noreferrer"&gt;service traffic distribution&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not using Auto-scaling
&lt;/h2&gt;

&lt;p&gt;Auto-scaling can save you money when done right, there are 2 "layers" for it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Workload auto-scaling - you can use tools like &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/" rel="noopener noreferrer"&gt;HPA&lt;/a&gt; or &lt;a href="https://keda.sh/" rel="noopener noreferrer"&gt;KEDA&lt;/a&gt; to scale your workloads based on metrics or events.&lt;/li&gt;
&lt;li&gt;Node auto-scaling - you can use tools like &lt;a href="https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler" rel="noopener noreferrer"&gt;Cluster Autoscaler&lt;/a&gt;, &lt;a href="https://karpenter.sh/" rel="noopener noreferrer"&gt;Karpenter&lt;/a&gt; or &lt;a href="https://spot.io/product/ocean/" rel="noopener noreferrer"&gt;Spot Ocean&lt;/a&gt; to scale your nodes to your workload's requirements.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⚠️ Warning:&lt;/strong&gt; Be careful with aggressive HPA configurations on latency-sensitive workloads. Too-tight thresholds can cause oscillation—rapidly scaling up and down—which wastes resources and can actually hurt performance. Test your scaling behavior under realistic load before going to production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When discussing cost, it's obvious that we want our compute capacity to fit our workload's requirements with as little waste as possible. However, our workloads' demands change over time according to our load and other factors (like holidays, etc).&lt;br&gt;
Paying for peak capacity while your customers are asleep is simply burning money.&lt;/p&gt;

&lt;p&gt;Beyond standard auto-scalers, specialized tools can help with niche use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.vcluster.com/" rel="noopener noreferrer"&gt;Vcluster&lt;/a&gt;&lt;/strong&gt;: Runs virtual clusters inside a host cluster. Perfect for isolating multi-tenant dev/test environments without paying for multiple control planes (among other use cases).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/moonorange/snorlax" rel="noopener noreferrer"&gt;Snorlax&lt;/a&gt;&lt;/strong&gt;: Automatically sleeps selected workloads on nights and weekends, ensuring you only pay for resources when developers are actually working.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or if you have serverless workloads, you can use a tool like &lt;strong&gt;&lt;a href="https://knative.dev/" rel="noopener noreferrer"&gt;Knative&lt;/a&gt;&lt;/strong&gt; which offers the ability to scale to zero and scale up to the required capacity. This can be great for cases where you can "afford" cold starts. &lt;/p&gt;

&lt;h2&gt;
  
  
  Mismanaging Node Pools
&lt;/h2&gt;

&lt;p&gt;Most node auto-scaling tools group different "kinds" of nodes into different pools, for Karpenter it's called Node Pools, for Spot Ocean it's called Virtual Node Groups.&lt;/p&gt;

&lt;p&gt;These are similar in concept and allow you to create a group of nodes with the same configurations, you can filter different instance types, different behaviors (different set of labels/taints, how often can it be scaled down, how many at a time, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  Separating too much
&lt;/h3&gt;

&lt;p&gt;One of Kubernetes' main cost advantages is resource sharing. Workloads with different needs (e.g., CPU-intensive vs. Memory-intensive) can run on the same node, maximizing overall utilization.&lt;/p&gt;

&lt;p&gt;However, teams often over-segment their node pools, isolating workloads and losing this efficiency. A common mistake is creating separate pools for Spot and On-Demand instances. This can lead to situations where Spot pods trigger a new Spot node while your existing On-Demand nodes have ample free space. The cheapest instance is no instance at all.&lt;/p&gt;

&lt;p&gt;Instead, consider combining them. By using Pod PriorityClasses, you can allow Spot workloads to run on "spare" On-Demand capacity. If a critical On-Demand pod needs that space later, the scheduler will simply evict the lower-priority Spot pod to make room.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not separating enough
&lt;/h3&gt;

&lt;p&gt;A common case where you probably should separate your node pools is when you have workloads that shouldn't be scaled down, such as long-running batch jobs or StatefulSets with slow recovery times.&lt;br&gt;
In this case, it can help you avoid the case where you have this very large node that made sense when it was scaled up, but now after a while only one pod that can't be scaled down is running on it, and you're paying for a very large node that is only running one pod.&lt;/p&gt;

&lt;p&gt;It's important to note that you can make this scenario uncommon even without a dedicated node pool but it requires some more work and planning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Cost of Rapid Scale-Down
&lt;/h2&gt;

&lt;p&gt;Karpenter, for example, by default will scale down nodes as soon as they are underutilized, but you can configure it to wait for a certain amount of time before scaling down a node.&lt;br&gt;
Now you're probably wondering why would I do that? It's wasting money right?&lt;/p&gt;

&lt;p&gt;Technically, yes. However, since developers often lack access to configure node pools, they tend to react with the only tools they have: locking down workloads. They might set restrictive PDBs or annotations to prevent eviction, which ironically leads to worse bin-packing.&lt;/p&gt;

&lt;p&gt;Depending on your use case, even a few minutes of consolidation delay can make a huge difference in developer experience without significantly impacting costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;Kubernetes is powerful, but without proper planning, it can become a financial black hole.&lt;/p&gt;

&lt;p&gt;Go check your node utilization right now. I bet you'll find a 'perfect' 4GB pod sitting on a partially empty node.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Sunk Cost Fallacy in Software: How to Recognize It and What to Do About It</title>
      <dc:creator>Tal Shafir</dc:creator>
      <pubDate>Sat, 29 Nov 2025 12:58:12 +0000</pubDate>
      <link>https://dev.to/tal_shafir_49b67973e9d3b4/the-sunk-cost-fallacy-in-software-how-to-recognize-it-and-what-to-do-about-it-3l3a</link>
      <guid>https://dev.to/tal_shafir_49b67973e9d3b4/the-sunk-cost-fallacy-in-software-how-to-recognize-it-and-what-to-do-about-it-3l3a</guid>
      <description>&lt;h2&gt;
  
  
  What is The Sunk Cost Fallacy?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The sunk cost fallacy is our tendency to follow through with something that we've already invested heavily in (be it time, money, effort, or emotional energy), even when giving up is clearly a better idea.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An everyday example: imagine you buy a $20 movie ticket, and halfway through the movie you realize you're not enjoying it. The rational choice would be to leave and use your time more enjoyably - but many people stay just to "get their money's worth." &lt;br&gt;
That's sunk cost fallacy in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it relate to Software?
&lt;/h2&gt;

&lt;p&gt;We've all most likely been there, we made a decision that made sense at the time, sometimes because of external reasons.&lt;/p&gt;

&lt;p&gt;I bet at least some of these quotes will sound familiar&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need to move fast, no time for tests / documentation / design&lt;/li&gt;
&lt;li&gt;We don't have capacity to learn to use X for this new use case, let's keep using Y that we're already familiar with&lt;/li&gt;
&lt;li&gt;We don't have enough DevOps to manage another DB, let's use the same DB for all these microservices&lt;/li&gt;
&lt;li&gt;Let's use language X - most of our founding team already knows it, and we'll just implement anything missing in its ecosystem ourselves.&lt;/li&gt;
&lt;li&gt;We must use this new cool technology, it will scale us great when we reach thousands of customers (only 982 more customers to go until we reach the first thousand)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A lot of times these are good reasons early on and most commonly in small scales, you don't always have the time or capacity to engineer a solution for 1000x customers and load - and a lot of times you shouldn't.&lt;/p&gt;

&lt;p&gt;Ultimately, delivering value to your customers through your product is far more important than using perfect tools under the hood. The ocean floor is littered with well-designed ships that never left port.&lt;/p&gt;

&lt;p&gt;It's usually a balancing act that we almost definitely will miss at least sometimes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Consequences of Past Decisions
&lt;/h2&gt;

&lt;p&gt;Looking back at those examples, it seems inevitable that we'll eventually make decisions we regret. How can we know that we've reached the point that we need to do something about it?&lt;/p&gt;

&lt;p&gt;Usually there are some signs that we've reached a point that we already start feeling the cost of previous decisions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Over-engineered systems and processes&lt;/li&gt;
&lt;li&gt;Framework lock-in or bad platform choices&lt;/li&gt;
&lt;li&gt;Investing a lot of time and effort on stuff that is not your core business&lt;/li&gt;
&lt;li&gt;Slowed feature development&lt;/li&gt;
&lt;li&gt;Performance Issues&lt;/li&gt;
&lt;li&gt;System Instability&lt;/li&gt;
&lt;li&gt;Increasing maintenance effort&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are all common in the modern lifecycle of software products, the industry learned that building the "perfect" system from the get-go is nearly impossible, requirements change, scale change and it's almost impossible to predict those changes without getting your product in the hands of your customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Recognize When You're Falling for It
&lt;/h2&gt;

&lt;p&gt;It's not the past decisions that hurt us, it's ignoring them and delaying action that causes real damage.&lt;br&gt;
It's tempting to band-aid these issues instead of addressing root causes.&lt;br&gt;
Performance problems? Throw more compute at them. &lt;br&gt;
Database struggling? Scale it up.&lt;/p&gt;

&lt;p&gt;The more we push forward with our mitigations and workarounds the more sunk cost we have. If we'd left the 3-hour movie after the first hour we would've lost $20 and an hour of our lives, if we waited 2 hours we'll lose $20 and 2 hours of our lives.&lt;/p&gt;

&lt;p&gt;Scale this up to a software company: it's not $20, it's likely $20,000+ in cloud bills. It's not an hour - it's hundreds of person-hours and significant opportunity cost.&lt;/p&gt;

&lt;p&gt;A good sign for it is if you start hearing phrases like&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We've invested too much to change it now.&lt;/li&gt;
&lt;li&gt;The rewrite will take too long.&lt;/li&gt;
&lt;li&gt;We'll lose political capital if we admit it didn't work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ask yourself these&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are we defending this decision only because of past effort?&lt;/li&gt;
&lt;li&gt;Is this architecture still serving us today?&lt;/li&gt;
&lt;li&gt;What would we do if we started from scratch?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What to Do Instead: Strategies to Move Forward
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfjjaptuabg3lw0uda4d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfjjaptuabg3lw0uda4d.jpg" alt="I'm in this photo and I don't like it" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, we've started to fall for it, what can we do?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run cost-benefit analyses&lt;/strong&gt; (fresh, not based on past costs). Compare "cost to migrate away" vs. "cost to keep maintaining" without factoring in what you've already spent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small rewrites over big-bang&lt;/strong&gt;. Instead of rewriting the entire legacy authentication system, start by replacing it piece by piece in new services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build confidence with spikes and proof of concepts&lt;/strong&gt;. Before committing to a database migration, run a 2-week spike to validate the approach works for your use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communicate tradeoffs openly with stakeholders&lt;/strong&gt;. "Migrating off this framework will slow feature development for 2 quarters but reduce maintenance overhead by 40%" is better than silence and bailing mid-work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embrace "build to replace" design patterns&lt;/strong&gt;. Write new code assuming it might be replaced, making it easier to incrementally modernize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Invest in modularization to isolate painful components&lt;/strong&gt;. If you're working on a component you know will need to be replaced, abstract it so you can upgrade it independently.&lt;/p&gt;

&lt;p&gt;It's not always possible to handle these cases immediately but detecting and reacting fast can mitigate a lot of the cost of these cases. The solution is to stay vigilant: document decisions and their rationale, hold regular architecture reviews, and foster open discussions that help you catch issues early.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Can You Make a Change
&lt;/h3&gt;

&lt;p&gt;Always surface the issues you find. Silence helps no one - problems can't get solved if decision-makers don't know they exist.&lt;br&gt;
Before raising concerns, keep these important principles in mind. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember you're on the same team&lt;/strong&gt;, even when you disagree. The goal isn't to annoy people into agreement - it's to align on how addressing this issue helps everyone reach shared goals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn to take "no" gracefully&lt;/strong&gt;. They're saying no to your idea, not to you personally. You mustn't take it personally and understand that there are factors outside your scope. For instance, "if we don't do X, we won't scale to 100x customers" may not be a valid concern if there are urgent issues that could end your runway before you reach 1.5x customers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Come with a plan&lt;/strong&gt;, not just cool-sounding ideas. It's much easier for stakeholders to agree to a reasonable, well-thought-out plan than to a half-baked idea that may not be realistic.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;filter your ideas carefully&lt;/strong&gt;. Not every interesting technology you read about is worth implementing. Focus on real pain points you're encountering, not solutions designed for companies at the scale of Google or Netflix. "Let's use chaos monkey, gorilla, and kong in production" is probably not what a small company providing non-critical services in a single region should invest time in.&lt;/p&gt;

&lt;p&gt;I must admit that I've fallen into some, if not all of these pitfalls at some point.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Leadership Angle: Creating Space for Rational Change
&lt;/h3&gt;

&lt;p&gt;The people that feel these issues the most are those in the trenches, it's the developers that keep writing the same boilerplate or the PM that keep hearing that "we can't do it in this timeframe" or "we can't do it the DB won't handle it".&lt;/p&gt;

&lt;p&gt;It's important to build an environment where raising those issues is rewarded. It's also important to act on it, it's very easy for teams to become numb to these issues and feel that no matter how hard they try to advocate, it won't change or even worse, being framed as a troublemaker and the developer who cried legacy.&lt;/p&gt;

&lt;p&gt;Managers and architects should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reward truth-seeking behavior and try to act on it&lt;/li&gt;
&lt;li&gt;Protect engineers who raise hard truths&lt;/li&gt;
&lt;li&gt;Avoid framing rewrites as personal failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Case Studies: Breaking Free from Sunk Cost
&lt;/h2&gt;

&lt;p&gt;After discussing the theory, let's look at some well-known scenarios where companies pivoted - reworking decisions they had already heavily invested in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon Prime Video&lt;/strong&gt; &lt;a href="http://archive.today/2023.05.21-052950/https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90" rel="noopener noreferrer"&gt;migrated their monitoring service&lt;/a&gt; from serverless distributed services to a monolithic application, helping them achieve higher scale and resilience, while reducing their costs by 90%.&lt;br&gt;
(For some reason, the original blog post link doesn't work anymore, but the internet doesn't forget.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slack&lt;/strong&gt; has pivoted more than once!&lt;br&gt;
Slack originated from the gaming company &lt;em&gt;Tiny Speck&lt;/em&gt;, which created an online multiplayer game called Glitch. The company developed an internal communication tool for game development, which ultimately proved more valuable than the game itself.&lt;br&gt;
You can read more in their &lt;a href="https://buildingslack.com/the-death-of-glitch-the-birth-of-slack/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; about it 12 years later.&lt;/p&gt;

&lt;p&gt;Since its inception, Slack used MySQL as its storage engine, managing sharding and data access directly within their monolithic application. They maintained their product this way for &lt;strong&gt;years&lt;/strong&gt;.&lt;br&gt;
In 2017, they began migrating to &lt;a href="https://vitess.io/" rel="noopener noreferrer"&gt;Vitess&lt;/a&gt;, a horizontal scaling system for MySQL. For more details about this journey and the decisions behind it, see this &lt;a href="https://slack.engineering/scaling-datastores-at-slack-with-vitess/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;br&gt;
Here are some key highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The migration took about &lt;strong&gt;three years&lt;/strong&gt;, all while their system continued to function as usual.&lt;/li&gt;
&lt;li&gt;Fortuitously, they completed most of the migration just before the COVID-19 pandemic, when many businesses suddenly transitioned to remote work. During this period, they saw query rates increase by 50% in a single week - without Vitess, scaling to meet that demand would likely have caused downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of these examples demonstrate that, while such changes can be costly, wise choices and careful planning can yield substantial long-term benefits.&lt;/p&gt;

&lt;p&gt;Of course, we can't ignore that there are likely many more examples where such attempts have failed. Often, it's difficult to determine whether the failures stemmed from the attempts themselves - or simply from acting too late.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Progress Over Pride
&lt;/h2&gt;

&lt;p&gt;Encountering issues and reaching limits of decision is part of our professional lives, it's nothing to feel shame about but a badge of honor - we did such a good job that we need to scale up.&lt;/p&gt;

&lt;p&gt;Recognizing sunk cost fallacy is a sign of engineering maturity, being able to act on it is a sign of a good engineering environment.&lt;/p&gt;

&lt;p&gt;Sometimes, the best path forward is letting go of what got you here. Start small, audit one decision that may be influenced by sunk costs.&lt;/p&gt;

</description>
      <category>management</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
