<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Clean Compute]]></title><description><![CDATA[Kubernetes, the way you want it]]></description><link>https://blog.cleancompute.net</link><image><url>https://substackcdn.com/image/fetch/$s_!gG-Z!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5bcb1de-4767-41a7-91f5-e780f00b6d67_390x390.png</url><title>Clean Compute</title><link>https://blog.cleancompute.net</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 11:35:51 GMT</lastBuildDate><atom:link href="https://blog.cleancompute.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Clean Compute]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[cleancompute@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[cleancompute@substack.com]]></itunes:email><itunes:name><![CDATA[Clean Compute]]></itunes:name></itunes:owner><itunes:author><![CDATA[Clean Compute]]></itunes:author><googleplay:owner><![CDATA[cleancompute@substack.com]]></googleplay:owner><googleplay:email><![CDATA[cleancompute@substack.com]]></googleplay:email><googleplay:author><![CDATA[Clean Compute]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[But What About Reliability? The Kubernetes Cost Optimization Paradox]]></title><description><![CDATA[This post discover how to apply cost optimization techniques in a large scale Kubernetes platforms without compromising reliability]]></description><link>https://blog.cleancompute.net/p/kubernetes-cost-optimization-paradox</link><guid isPermaLink="false">https://blog.cleancompute.net/p/kubernetes-cost-optimization-paradox</guid><dc:creator><![CDATA[Nibir Bora]]></dc:creator><pubDate>Wed, 08 Apr 2026 17:31:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e6e41f11-fc4b-4461-9f76-3c32a0062709_7341x3848.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post is the follow-up to <a href="https://blog.cleancompute.net/p/kubernetes-cost-optimization">Part 1: Save Millions on Your Cloud Bill</a>, where we focus on the harder question: how do you apply those ideas in a real production environment without compromising reliability?</em></p><p><em>This article is based on a talk presented at KubeCon North America 2025. You can watch the talk <a href="https://www.youtube.com/watch?v=GPo8WLCvaWw">here</a> and view the slides <a href="https://drive.google.com/file/d/1_rhYYd4Zdyc17ethPwRgZ-96gk9kBz2M/view">here</a>.</em></p><p><em>Special thanks to <a href="https://www.linkedin.com/in/thezainm/">Zain Malik</a> for his contributions to the ideas and work behind this talk.</em></p><div><hr></div><p>Business leaders believe reliability can only be achieved at a high cost. There is some truth to this. Cut costs without considering reliability, and application stability takes a hit. Spooked executives abandon cost optimization to preserve customer trust. And you are back at sky high costs.</p><p>This is why every cost optimization initiative is met with the cautionary question:</p><div class="pullquote"><p><strong>But what about reliability?</strong></p></div><p>The fix is simple in principle: reliability needs to be an intentional step in reducing cost. The paradox isn't between cost and reliability. It's between fear and understanding. Once you understand the gaps in your reliability posture, reliability peaks and cost savings follow.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!K9DA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K9DA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 424w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 848w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 1272w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K9DA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png" width="1456" height="714" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:714,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:239147,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!K9DA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 424w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 848w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 1272w, https://substackcdn.com/image/fetch/$s_!K9DA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe00103ec-d70b-4d77-bf9b-9c89cdddbe6f_7850x3848.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The optimization faux pas (left) vs. cost optimization done right (right).</em></figcaption></figure></div><p>In Part 1 of this blog we laid out 11 strategies to reduce Kubernetes costs, starting from absolute basics like:</p><ul><li><p>Use shared multi-tenant clusters</p></li><li><p>Enable Node Pool autoscaling, and ensure scale down to zero</p></li><li><p>Declare resource requests &amp; limits for workloads</p></li><li><p>Use Horizontal Pod Autoscaling (HPA)</p></li></ul><p>Intermediate techniques as your platform scales:</p><ul><li><p>FinOps &amp; cost visibility per team, per service, per namespace, etc.</p></li><li><p>Use spot nodes for ephemeral workloads</p></li><li><p>Align node shapes with workload demands</p></li><li><p>Enable custom metric-based autoscaling</p></li></ul><p>And advanced techniques when infra cost justifies dedicated engineering:</p><ul><li><p>Automatic request tuning for workloads</p></li><li><p>Custom scheduler for optimized bin-packing</p></li><li><p>Cluster Autoscaler expander profiles to scale across node pools</p></li><li><p>Enable controlled evictions to remove any eviction blockers</p></li></ul><p>In this post, we show that cost optimizations done right actually increase platform reliability. This isn&#8217;t a contrarian theory. It&#8217;s a selection of war stories (along with technical solutions) from an organization operating cloud-scale Kubernetes infrastructure.</p><h1>Technical Roadblocks</h1><p>Each optimization technique from Part 1 comes with a reliability concern. Here&#8217;s how we addressed them by extending Kubernetes.</p><h2>Protecting the Data Layer</h2><p>Distributed databases like <a href="https://www.cockroachlabs.com/product/overview/">CockroachDB</a> rely on quorum across regions. If multiple replicas are lost simultaneously in different regions, the database loses quorum or becomes inconsistent. This can take down every transactional service causing a serious global outage.</p><p>Evictions in different regions can happen for a myriad of reasons - Cluster Autoscaler (CA) scaling down an underutilized node, planned maintenance, node pool upgrades, etc.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_j6c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_j6c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 424w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 848w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 1272w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_j6c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png" width="1456" height="904" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:904,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:455471,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_j6c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 424w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 848w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 1272w, https://substackcdn.com/image/fetch/$s_!_j6c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec5a6ca3-8fd7-47f7-b58f-0918be84f52b_5119x3179.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Simultaneous evictions from Cluster Autoscaler in Cluster A and a Node Pool upgrade in Cluster B can break CockroachDB quorum.</em></figcaption></figure></div><p>The instinctive response is to set <a href="https://kubernetes.io/docs/tasks/run-application/configure-pdb/">PodDisruptionBudget</a> (PDB) maxUnavailable to 0 on every CockroachDB pod. This feels safe. But nodes running CockroachDB pods can now never be drained. This isn&#8217;t just idle capacity burning money. It&#8217;s also an operational overhead because any node pool upgrade requires manual steps.</p><h6><strong>Solution</strong></h6><p>We built a multi-cluster distributed lock using the Kubernetes <a href="https://kubernetes.io/docs/concepts/architecture/leases/">Leases API</a>. The Leases API is typically used for leader election within a single cluster. We implemented a custom <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/operator/">Operator</a> extending Leases to coordinate evictions across clusters.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m9ul!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m9ul!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 424w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 848w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 1272w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m9ul!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png" width="1456" height="1592" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1592,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:196118,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m9ul!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 424w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 848w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 1272w, https://substackcdn.com/image/fetch/$s_!m9ul!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F530c3b3f-81d8-4762-a0f5-45714cbc758b_3232x3534.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Multi-cluster eviction coordination using the Leases API. A Validating Webhook in each cluster intercepts eviction requests and acquires a global lease from the management cluster before allowing the eviction to proceed.</em></figcaption></figure></div><p>Before CA in any region attempts to evict a CockroachDB pod, it must first acquire a global lease. Only one cluster can hold that lease at any given moment. If a node pool upgrade in another cluster tries to evict a CockroachDB pod at the same time, it fails to acquire the lease and the eviction request is rejected.</p><p>This guarantees at most one CockroachDB pod is evicted globally at any given time. Quorum is never at risk.</p><div class="pullquote"><p><strong>By extending Kubernetes you can enable controlled evictions without a security blanket of overprovisioned resources. This gives you reliability and cost efficiency at the same time.</strong></p></div><h2>HPA vs. VPA</h2><p><a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/">Horizontal Pod Autoscaler</a> (HPA) and <a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/">Vertical Pod Autoscaler</a> (VPA) cannot be used together. This is a well-known Kubernetes limitation. Platforms that rely on horizontal scaling for reliability are forced to trade off automatically adjusting resource requests based on actual usage.</p><p>The instinctive response is to opt out of VPA entirely. Platform maintainers accept manually adjusting resource requests as an operational overhead. This doesn&#8217;t scale and leads to cumulative waste.</p><h6><strong>Solution</strong></h6><p>The key was figuring out how to use both HPA and VPA together. We built an <strong>automatic resource tuner</strong> to address this.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DX78!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DX78!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 424w, https://substackcdn.com/image/fetch/$s_!DX78!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 848w, https://substackcdn.com/image/fetch/$s_!DX78!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 1272w, https://substackcdn.com/image/fetch/$s_!DX78!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DX78!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png" width="1456" height="1446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1446,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:376031,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DX78!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 424w, https://substackcdn.com/image/fetch/$s_!DX78!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 848w, https://substackcdn.com/image/fetch/$s_!DX78!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 1272w, https://substackcdn.com/image/fetch/$s_!DX78!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2e52797-a17a-4934-a496-3d5c8c1af00f_4680x4648.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Automatic resource tuning pipeline. Resource Recommender produces recommendations based on historical usage data and applies them via a Mutating Admission Webhook at the next rollout.</em></figcaption></figure></div><p>VPA in <strong>recommender mode</strong> analyzes usage and produces recommendations, but never applies them. We built a custom controller that blends these recommendations with a weighted average of usage data over the last several days. This produces a resource recommendation we can control - how frequently it gets generated, variance across regions, and overhead.</p><p>A <a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook">Mutating Admission Webhook</a> applies these recommendations at the next application rollout. We also built in self-service opt-in and opt-out mechanisms along with tuning profiles so developers can customize how their workloads get tuned.</p><div class="pullquote"><p><em><strong>When an upstream tool doesn&#8217;t quite fit your problem, the answer is often to extend it, not abandon it. Using HPA and VPA together by extending Kubernetes reduces both cost and operational overhead.</strong></em></p></div><h2>High Spec Node Flop</h2><p>The instinctive path to reducing per-pod overhead is to use bigger nodes. Larger instance families like 96-core machines mean less amortized cost from DaemonSets, monitoring agents, network interfaces, and kubelet. More pods per node, lower overall cost. At least on paper.</p><p>In reality, cloud providers impose a <strong>max-pods-per-node</strong> limit. Without kernel level tuning you cannot pack too many pods on a node. These huge expensive machines end up half empty.</p><h6><strong>Solution</strong></h6><p>We reverted to smaller 32-core nodes and aligned node shape to the aggregate resource profile of our workloads. Our workloads were mostly memory-heavy. Across our fleet, memory would saturate first while CPU cores sat unused on nodes.</p><p>By switching from a 1:4 CPU to memory ratio to a 1:8, we packed pods more efficiently and reduced the gap between CPU and memory utilization. That&#8217;s where the savings came from.</p><div class="pullquote"><p><em><strong>Sometimes you have to dial back on a path that looks right on paper but doesn&#8217;t deliver in practice. When direct cost optimization isn&#8217;t possible, understand the real constraint before optimizing again.</strong></em></p></div><h2>The Flink Dilemma</h2><p><a href="https://flink.apache.org/">Apache Flink</a> powers critical ETL pipelines at most businesses. Some of these stateful stream processing jobs run for as long as 45 minutes or even hours. When moving workloads to Spot instances (up to 58% cheaper on most cloud providers) Flink is an obvious target.</p><p>The problem is that older versions of Flink didn&#8217;t support partial recovery or checkpoints. If a Spot node running a Flink job is reclaimed, the entire job restarts from scratch. This cascades delays to downstream systems and risks data inconsistencies.</p><p>The instinctive response is to optimize anyway and accept the occasional restart. 58% savings is hard to ignore.</p><h6><strong>Solution</strong></h6><p>We made a deliberate decision not to run Flink on Spot instances. The potential disruption cost overshadowed the potential cost savings.</p><p>Instead, we isolated Flink onto a dedicated on-demand node pool and explicitly allowed safe-to-evict: false annotations so these jobs won&#8217;t be evicted mid-execution. We accepted higher costs for one node pool. But this problem workload didn&#8217;t drag down the overall platform efficiency.</p><div class="pullquote"><p><em><strong>Sustained efficiency in a mature platform comes from knowing when not to optimize to protect reliability. If workload inefficiencies cannot be eliminated, isolate them instead.</strong></em></p></div><h2>Noisy Neighbor</h2><p>Multi-tenant clusters mean workloads compete for shared resources. This is fundamental for cost efficiency, but comes with downsides. For example, a single pod throttling CPU on a node, or latency spikes from a memory-hungry neighbor.</p><p>When users cannot root cause these failures easily, &#8220;noisy neighbor&#8221; becomes the catch-all explanation. The instinctive response is to isolate workloads onto dedicated node pools or clusters. This is one of the most widely accepted arguments against multi-tenancy.</p><p>But isolation at that level destroys the density gains that make multi-tenancy worthwhile. You&#8217;re solving a diagnosis problem with expensive infrastructure.</p><h6><strong>Solution</strong></h6><p>We introduced <a href="https://docs.kernel.org/accounting/psi.html">Pressure Stall Information</a> (PSI) metrics that tell users exactly how long a workload has been waiting for CPU cycles, blocked on I/O, or under memory pressure. A comprehensive node-level dashboard exposing CPU utilization, memory pressure, file descriptor counts, conntrack table usage, context switch rates, and per-workload PSI metrics lets engineers quickly identify what&#8217;s actually constraining their workload.</p><p>For workloads that genuinely need isolation, we introduced <strong>CPU core pinning</strong> via the Kubernetes <a href="https://kubernetes.io/blog/2024/12/16/cpumanager-strict-cpu-reservation/">CPU Manager static policy</a>. This allows latency-sensitive workloads to request dedicated CPU cores on a node, eliminating context switching.</p><div class="pullquote"><p><em><strong>Noisy neighbor is almost always a visibility problem, not a multi-tenancy problem.</strong></em></p></div><h1>Cultural Roadblocks</h1><p>Technical blockers are tough. Organizational resistance is harder. You can&#8217;t debug fear. You can&#8217;t automate trust. Dealing with people requires a different toolkit entirely.</p><h2>FUD &amp; Ownership</h2><p>Engineers pour their careers into making their services stable. The idea of an automated system touching their workloads, let alone modifying resources on a schedule they don&#8217;t control, is genuinely frightening. This is a completely natural response.</p><p>The instinctive reaction from leadership is to accept overprovisioning as an operating principle. Overprovisioning buys perceived reliability. Nobody gets paged for having too much headroom.</p><p>But perceived reliability isn&#8217;t actual reliability. It&#8217;s expensive guesswork. And it doesn&#8217;t scale. When we rolled out automatic resource tuning to over 1000 microservices, the biggest hurdle was pure Fear, Uncertainty, and Doubt (FUD).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZmMK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZmMK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 424w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 848w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 1272w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZmMK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png" width="1456" height="601" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:601,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:244894,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZmMK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 424w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 848w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 1272w, https://substackcdn.com/image/fetch/$s_!ZmMK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d6fa608-901a-470e-a2b2-ad3c2d38a306_6994x2886.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The Fear Loop - overprovisioning creates perceived reliability, which masks waste until instability returns. Breaking the loop - radical visibility and control enables automated resource tuning, eliminating waste while improving reliability.</em></figcaption></figure></div><h6><strong>Solution</strong></h6><p>We countered fear with radical visibility and control.</p><p>We gave developers dashboards showing exact CPU and memory usage vs. requested, alongside wasted dollars. Critically, we showed what the automatic tuner proposed to change those requests to. Automation was no longer a black box. Data replaced fear.</p><p>We also gave every team a self-service opt-out. A simple annotation to revert to their original requests without involving the platform team or raising a support ticket. No panic paging during an incident. This safety valve changed everything. Engineers trusted the automation more because they had the power to say no.</p><div class="pullquote"><p><em><strong>Break the fear loop with radical visibility and control. Build trust with data, transparency, control, and a little bit of empathy.</strong></em></p></div><h2>Sacred Workloads</h2><p>Every organization has services that even the most prolific engineers refuse to touch. They are usually justified by high revenue generation, a big customer promise, or some historical outage story. These workloads run on dedicated hardware or have massive resource buffers.</p><p>The instinctive response is to not question it. If the service makes money and hasn&#8217;t gone down recently, leave it alone.</p><p>We had one critical transactional pipeline running with resource requests set at roughly 2000% of its average baseline usage. The team insisted it was imperative but couldn&#8217;t explain why. There was talk of &#8220;spikiness&#8221; and &#8220;rare edge cases&#8221; and historical incidents. But observability was weak, application behavior wasn&#8217;t well understood, and documentation didn&#8217;t exist. There was no technical truth to this overprovisioning. It just felt safer that way. Organizational scar tissue.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zS8f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zS8f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 424w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 848w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 1272w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zS8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png" width="1456" height="613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/efd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:613,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:258575,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zS8f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 424w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 848w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 1272w, https://substackcdn.com/image/fetch/$s_!zS8f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fefd1881a-ca7d-40ba-83ca-9b1b55300650_6994x2946.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The Sacred Workload Anxiety Loop - historical incident trauma drives overprovisioning, creating perceived safety that persists unchallenged. Breaking the loop - improved telemetry and profiling replaces anxiety with data, enabling right-sized requests built on confidence, not waste.</em></figcaption></figure></div><h6><strong>Solution</strong></h6><p>We invested in better metrics, traces, and profiling for these services first. We expanded developer tools so engineers could quickly take a heap dump from an application during a failure.</p><p>Once teams could actually see what the workload was doing, we could confirm whether it genuinely had unusual needs. In many cases, it didn&#8217;t. Teams were relieved to finally have data rather than anxiety. This enabled us to pull back the security blanket of overprovisioning from these sacred workloads.</p><div class="pullquote"><p><em><strong>Sacred workloads are sacred because people don&#8217;t understand them. When fear fills the knowledge gap, start with visibility, not optimization.</strong></em></p></div><h2>Eviction Blockers</h2><p>When a business grows fast, velocity wins over stability. Teams ship features and stability becomes tomorrow&#8217;s problem. At this inflection point we realized that 80% of nodes on our multi-tenant clusters had at least one pod blocking eviction. These workloads couldn&#8217;t handle shutdown signals gracefully without causing downstream business failures.</p><p>The instinctive response is to treat this as someone else&#8217;s problem. Application teams don&#8217;t want to rewrite shutdown logic. Platform teams don&#8217;t want to force changes that might cause outages. So the blockers stay.</p><p>This is a direct manifestation of organizational and technical debt. Even if workloads were tuned for optimal usage, the savings never materialized because these nodes could not be scaled down.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hTLH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hTLH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 424w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 848w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 1272w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hTLH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png" width="1456" height="601" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:601,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:254739,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hTLH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 424w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 848w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 1272w, https://substackcdn.com/image/fetch/$s_!hTLH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F125ec93b-ed26-4642-a575-4086d09978a0_6994x2886.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The Tech Debt Spiral - rapid feature velocity drives overprovisioning for safety, accumulating overhead and waste under the illusion of perceived safety. Breaking the loop - extending Kubernetes to eliminate eviction blockers safely, removing waste while improving reliability.</em></figcaption></figure></div><h6><strong>Solution</strong></h6><p>We introduced a Disruption Probe - a custom <a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook">Validating Admission Webhook</a> that gives developers full control over when a workload can shut down safely. The webhook intercepts eviction signals and executes a configurable program within the pod&#8217;s container before shutdown. Teams define what &#8220;safe&#8221; means for their service.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6LPH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6LPH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 424w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 848w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 1272w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6LPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png" width="1456" height="1021" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1021,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:357761,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6LPH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 424w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 848w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 1272w, https://substackcdn.com/image/fetch/$s_!6LPH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71cc55d1-6d03-47be-873c-ed937836696b_4844x3396.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The Validating Admission Webhook intercepts eviction requests. It executes a developer-defined eviction probe in the pod&#8217;s container and admits or denies the eviction based on the result.</em></figcaption></figure></div><p>By giving developers control over eviction safety, the platform team no longer had to demand teams remove eviction blockers. Teams removed them voluntarily, without hurting reliability.</p><div class="pullquote"><p><em><strong>Organizational and technical debt is the cancer to any cost optimization effort. Technical innovation that gives developers control back is the only way to reliably cure it.</strong></em></p></div><h2>Personal Incentives</h2><p>All the investment in automation, observability, and developer tooling won&#8217;t move the needle on your cloud bill if the humans responsible have no reason to care. Most engineering organizations reward technical novelty as a proxy for business impact. When efficiency isn&#8217;t rewarded, waste becomes normalized. The company&#8217;s bottom line takes a hit.</p><p>The instinctive response is to mandate cost optimization top-down. Leadership sets targets, platform teams enforce them, and application teams comply reluctantly.</p><p>This breeds resentment, not ownership. Mandates work until the next reorg or priority shift. Then waste creeps back.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y57X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y57X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 424w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 848w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 1272w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y57X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png" width="1456" height="613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:613,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:257121,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Y57X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 424w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 848w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 1272w, https://substackcdn.com/image/fetch/$s_!Y57X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc75063f5-30bf-496c-bba8-b956917e4113_6994x2946.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>The Doom Loop - when cloud spend is opaque and efficiency isn&#8217;t rewarded, waste is normalized. Breaking the loop - gamified accountability and aligned incentives drives proactive optimization and cost savings.</em></figcaption></figure></div><h6><strong>Solution</strong></h6><p>We changed the incentives.</p><p>The dashboards from automatic resource tuning evolved into leaderboards. Teams could see their waste ranked against others. Once waste became visible and measurable, positive peer pressure naturally kicked in.</p><p>Step two was making efficiency a formal performance dimension. Optimization results were folded into team goals, performance reviews, and bonus calculations for both engineers and managers. Once efficiency became personally consequential, the &#8220;don&#8217;t touch my workload&#8221; culture gave way to &#8220;how do I get my cost down?&#8221;</p><div class="pullquote"><p><em><strong>The most effective solution sometimes isn&#8217;t technology at all; It&#8217;s understanding human motivation to gamify accountability.</strong></em></p></div><h1>The Payoff</h1><p>If there is one takeaway - <strong>you don&#8217;t have to choose between cost and reliability</strong>. You get both. But only if reliability is an intentional step in every optimization, not an afterthought. We reduced our annual cloud spend by 40%. Double digit millions saved per year. And our business reliability posture improved alongside it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_f--!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_f--!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 424w, https://substackcdn.com/image/fetch/$s_!_f--!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 848w, https://substackcdn.com/image/fetch/$s_!_f--!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 1272w, https://substackcdn.com/image/fetch/$s_!_f--!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_f--!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png" width="1456" height="937" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:937,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:194529,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164581244?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_f--!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 424w, https://substackcdn.com/image/fetch/$s_!_f--!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 848w, https://substackcdn.com/image/fetch/$s_!_f--!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 1272w, https://substackcdn.com/image/fetch/$s_!_f--!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51670894-1450-4527-8e36-329da3f6a17d_3285x2114.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Before and after optimization. Reduced allocatable capacity (red), tighter resource requests (yellow), and the increased actual usage (green).</em></figcaption></figure></div><p>But <strong>progress wasn&#8217;t always linear</strong>. We tried bigger nodes and had to revert. We wanted Flink on Spot and had to say no. We rolled out automation and had to build escape hatches to earn trust. Success often comes down to how you handle the unexpected. Agility is key.</p><p>The process of optimizing cost forced us to build better tooling, deeper observability, and more resilient shutdown mechanisms. Every reliability concern in this blog was met with a technical solution that made the platform more resilient than before.</p><p><strong>Kubernetes is not the end product</strong>. It is a framework for building platforms. By embracing its extensibility - writing custom controllers, configuring schedulers, leveraging APIs like Leases for novel purposes - you can transform it from a resource allocator into an intelligent, self-optimizing system. One that overcomes the cost of organizational fear.</p><div class="pullquote"><p><em><strong>Because the most expensive infrastructure isn&#8217;t compute. It&#8217;s fear.</strong></em></p></div>]]></content:encoded></item><item><title><![CDATA[In-Place PVC Re-Binding: Zero-Downtime Disk Migration on Kubernetes]]></title><description><![CDATA[In-place PVC re-binding: swap a PersistentVolume's backing disk on Kubernetes with zero downtime using only native APIs. No custom software needed.]]></description><link>https://blog.cleancompute.net/p/pvc-re-binding</link><guid isPermaLink="false">https://blog.cleancompute.net/p/pvc-re-binding</guid><dc:creator><![CDATA[Maxim Nazarenko]]></dc:creator><pubDate>Mon, 23 Mar 2026 17:06:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/900a5901-4382-49bf-8b4e-8803818e208f_4951x2627.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kubernetes has been on a decade-long journey to decouple its core from vendor-specific storage solutions by migrating from in-tree storage plugins to Container Storage Interface (CSI) drivers. On Microsoft Azure, the built-in <code>kubernetes.io/azure-disk</code> storage provisioner was deprecated in v1.19 and entirely removed in v1.26<a href="https://kubernetes.io/docs/concepts/storage/storage-classes/#azure-disk"><sup>1</sup></a><sup>, </sup><a href="https://kubernetes.io/blog/2022/09/26/storage-in-tree-to-csi-migration-status-update-1.25/#timeline-and-status"><sup>2</sup></a>. Failure to migrate meant any scheduling event, including a routine deployment, could prevent a stateful application from re-attaching its underlying storage, causing application failure.</p><p>Standard migration paths require downtime. At our scale, taking hundreds of disks (backing data stores like ClickHouse, CockroachDB, Kafka, Prometheus) offline was off limits. This blog introduces an in-place PVC re-binding technique that swaps a <em>PersistentVolumeClaim</em>&#8217;s backing <em>PersistentVolume</em> while keeping the underlying disk intact. It requires only a single pod restart per volume, done entirely using the Kubernetes API natively with no custom software or control plane hacks. We use Azure managed disks on <a href="https://azure.microsoft.com/en-us/products/kubernetes-service">Azure Kubernetes Service</a> (AKS) to illustrate, but this method works universally on self-managed and cloud-provider managed Kubernetes distributions.</p><p>The CSI migration is old news for most teams. But the PVC re-binding technique itself unlocks operational capabilities often considered too risky by platform teams (e.g. modify performance tier for SSD). We used it to migrate several hundred production disks in under 2 months without a single incident or byte of data loss.</p><h1>What Makes This Hard</h1><p>To understand why this migration is difficult, we need to talk about how Kubernetes handles persistent storage and immutability.</p><p>Kubernetes persistent storage has three core components.</p><ul><li><p>A <em><strong>PersistentVolume</strong></em> (PV) is a cluster-level resource that represents a real piece of storage, like an Azure Disk.</p></li><li><p>A <em><strong>PersistentVolumeClaim</strong></em> (PVC) is a request for storage made by an application, living in the same namespace as its pods.</p></li><li><p>A <em><strong>StorageClass</strong></em> defines the type of storage and, critically, the provisioner responsible for creating it (e.g. <code>disk.csi.azure.com</code>).</p></li></ul><p>These come together through <a href="https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/">dynamic volume provisioning</a>. When a developer creates a PVC that specifies a <em>StorageClass</em>, the provisioner automatically creates a PV meeting the claim&#8217;s specifications. Kubernetes then binds the PVC to the PV. This binding is an exclusive one-to-one mapping enforced by the <code>claimRef</code> attribute on the PV.</p><p>The problem is that nearly every field that matters for this migration is immutable.</p><ul><li><p>The <code>provisioner</code> field in a <em>StorageClass</em> is immutable. We can&#8217;t simply update it to point to the new CSI driver.</p></li><li><p>We could create a new <em>StorageClass</em>. But once a PV is bound to a PVC, we can&#8217;t replace all references to the old one.</p></li><li><p>A PV&#8217;s <code>spec.persistentVolumeSource</code>, which defines the actual storage backend, is also immutable. Patching it returns: &#8220;<em>spec.persistentVolumeSource is immutable after creation</em>&#8221;.</p></li><li><p>A <em>StatefulSet</em>&#8217;s <code>spec.volumeClaimTemplates</code> is immutable too. Changing the <code>storageClassName</code> in this template is rejected with a &#8220;<em>forbidden</em>&#8220; error.</p></li><li><p>Same for a pod&#8217;s <code>spec.volumes</code> section. It&#8217;s immutable and a patch will fail with a &#8220;<em>forbidden</em>&#8220; error.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EUf7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EUf7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 424w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 848w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 1272w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EUf7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png" width="1456" height="730" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:730,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:433703,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/191815844?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EUf7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 424w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 848w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 1272w, https://substackcdn.com/image/fetch/$s_!EUf7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F65a9f71a-edd1-417a-9032-1bb5bc15cc76_5266x2640.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Kubernetes persistent storage lifecycle and immutable fields.</em></figcaption></figure></div><p>These constraints are deliberate. They enforce Kubernetes' persistence principle: <strong>storage is a durable, stable resource, while pods are ephemeral and replaceable</strong>. <em>StorageClasse</em>s, PVs, PVCs, like several other Kubernetes objects are immutable. The only way to change these resources is to destroy and recreate them.</p><h1>Understanding Kubernetes Nuances</h1><p>Given the immutability constraints, a direct migration is impossible. But lesser-known behaviors in Kubernetes provide the building blocks for our live migration strategy.</p><ol><li><p><em><strong>StorageClass</strong></em><strong> objects are passive.</strong> They are only used at the moment of provisioning, after a PV is bound to a PVC, the <em>StorageClass</em> plays no role. This means an existing PV and PVC is completely unaffected if their original <em>StorageClass</em> is deleted. We can exploit this behavior by deleting the deprecated in-tree <em>StorageClass</em> and immediately creating a new CSI-based one with the exact same name. This wouldn&#8217;t impact running applications.</p></li><li><p><strong>A PV&#8217;s </strong><code>claimRef</code><strong> controls binding behavior</strong>. When a PV is firmly bound to a PVC, its <code>spec.claimRef</code> contains the <code>kind</code>, <code>name</code>, <code>namespace</code>, and crucially, the <code>uid</code> and <code>resourceVersion</code> of the PVC. If the reference contains a <code>uid</code>, the PV controller considers the binding <strong>firm</strong>. If it does not, the PV is considered an available candidate for binding to a PVC with a matching <code>name</code> and <code>namespace</code>. This is the key insight. We can manually create a second PV that points to the same underlying Azure Disk but is defined as a CSI volume. By setting <code>name</code> and <code>namespace</code> in its <code>claimRef</code> but omitting the <code>uid</code>, this new PV becomes a &#8220;<strong>honeypot</strong>&#8221; volume, waiting to be claimed by a PVC of the right name.</p></li><li><p><strong>The </strong><code>pvc-protection</code><strong> finalizer prevents premature deletion</strong>. Kubernetes automatically adds the <code>kubernetes.io/pvc-protection</code> finalizer to any PVC actively used by a pod. With this finalizer present, deleting the PVC only sets a <code>deletionTimestamp</code>, putting it into a <em>Terminating</em> state. The PVC object isn&#8217;t actually removed until the pod using it is deleted, which deletes the finalizer. This built-in safety mechanism prevents race conditions. It ensures that when we delete the pod, the StatefulSet controller won&#8217;t immediately create a new empty volume before our &#8220;honeypot&#8221; PV can be claimed.</p></li></ol><h1>In-Place PVC Re-Binding Algorithm</h1><p>Before starting the per-disk migration, we replace the legacy <em>StorageClass</em> with a new CSI-based one that has the exact same name. This tricks the control plane into using the new CSI driver when it automatically re-creates the PVC later.</p><ol><li><p>Create a backup of the legacy <em>StorageClass</em>.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl get sc managed-premium -o yaml &gt; managed-premium-legacy.yaml</code></pre></div><p>The legacy <em>StorageClass</em> will look like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># managed-premium-legacy.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-premium
provisioner: kubernetes.io/azure-disk # The legacy in-tree provisioner
parameters:
  storageaccounttype: Premium_LRS
  kind: Managed
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer</code></pre></div><ol start="2"><li><p>Delete the legacy <em>StorageClass</em>.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl delete sc managed-premium</code></pre></div><ol start="3"><li><p>Create the new CSI <em>StorageClass</em> with the same name.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># managed-premium-csi.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-premium # The exact same name as the old one
provisioner: disk.csi.azure.com # The new CSI provisioner
parameters:
  skuName: Premium_LRS
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer</code></pre></div><p>Apply this new <em>StorageClass</em>:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl apply -f managed-premium-csi.yaml</code></pre></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wp04!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wp04!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 424w, https://substackcdn.com/image/fetch/$s_!wp04!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 848w, https://substackcdn.com/image/fetch/$s_!wp04!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 1272w, https://substackcdn.com/image/fetch/$s_!wp04!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wp04!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png" width="1456" height="623" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:623,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:691434,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/191815844?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wp04!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 424w, https://substackcdn.com/image/fetch/$s_!wp04!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 848w, https://substackcdn.com/image/fetch/$s_!wp04!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 1272w, https://substackcdn.com/image/fetch/$s_!wp04!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F19769cfd-5c5a-40f9-90b1-6967ff355930_6143x2627.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The in-place PVC re-binding algorithm sequence.</figcaption></figure></div><p>With the groundwork laid, we execute the following steps for each individual disk.</p><ol><li><p><strong>Identify the target resource</strong>. Start by identifying the specific <em>StatefulSet</em> pod to migrate, then get the name of its PVC, its bound PV, and the URI of the underlying Azure Disk. The disk URI is our critical identifier for the physical storage.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Set variables for your environment

export POD_NAME=&#8221;&lt;your-pod-name&gt;&#8221;
export PVC_NAME=$(kubectl get pod $POD_NAME -o jsonpath=&#8217;{.spec.volumes[?(@.persistentVolumeClaim)].persistentVolumeClaim.claimName}&#8217;)
export PV_NAME=$(kubectl get pvc $PVC_NAME -o jsonpath=&#8217;{.spec.volumeName}&#8217;)

echo &#8220;Pod: $POD_NAME&#8221;
echo &#8220;PVC: $PVC_NAME&#8221;
echo &#8220;PV:  $PV_NAME&#8221;

# Get the Azure Disk URI from the legacy PV object and save it

export DISK_URI=$(kubectl get pv $PV_NAME -o jsonpath=&#8217;{.spec.azureDisk.diskURI}&#8217;)

echo &#8220;Disk URI: $DISK_URI&#8221;
</code></pre></div><ol start="2"><li><p><strong>Set the legacy PV&#8217;s reclaim policy to &#8220;Retain&#8221;</strong>. This is an essential safety measure that ensure the physical Azure Disk is not automatically deleted when we delete the Kubernetes PV object later.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl patch pv $PV_NAME -p &#8216;{&#8221;spec&#8221;:{&#8221;persistentVolumeReclaimPolicy&#8221;:&#8221;Retain&#8221;}}&#8217;</code></pre></div><ol start="3"><li><p><strong>Create a new CSI PV</strong>. Create a new PV object that points to the same underlying Azure Disk. Set its <code>name</code> and <code>namespace</code> to match the legacy PVC in the PV&#8217;s <code>claimRef</code> section, but <strong>omit </strong>the <code>uid</code> and <code>resourceVersion</code> fields to allow re-binding. This is our &#8220;honeypot&#8221; PV.</p></li></ol><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># pv-csi-yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-migrated-csi # A new, unique name for the PV object
spec:
  capacity:
    storage: 100Gi # IMPORTANT: Use the actual size of your disk
  accessModes:
    - ReadWriteOnce # Match the original access modes
  persistentVolumeReclaimPolicy: Retain # Or Delete, if you prefer post-migration
  storageClassName: managed-premium # The name of the StorageClass we replaced
  claimRef:
    # IMPORTANT: These must match the original PVC exactly
    name: my-claim # Use your PVC_NAME variable here
    namespace: default # The namespace of your PVC
    # CRITICAL: Do NOT include &#8216;uid&#8217; or &#8216;resourceVersion&#8217;. This is intentional.
  csi:
    driver: disk.csi.azure.com
    volumeHandle: &lt;YOUR_AZURE_DISK_URI&gt; # Paste the DISK_URI from Step 1
    volumeAttributes:
      fsType: ext4 # Or xfs, matching your original disk</code></pre></div><p>Apply the new PV.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl apply -f pv-csi.yaml</code></pre></div><p>4. <strong>Trigger the re-binding</strong>. Delete the legacy PVC and the corresponding <em>StatefulSet</em> pod.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl delete pod $PVC_NAME
kubectl delete pod $POD_NAME</code></pre></div><p>The following happens automatically:</p><ul><li><p>Deleting the PVC puts it into a &#8220;Terminating&#8221; state. The <code>pvc-protection</code> finalizer keeps it alive as long as the pod is running.</p></li><li><p>The pod goes through its shutdown sequence and is deleted.</p></li><li><p>When the pod is deleted, the finalizer is removed from the PVC, and the PVC is fully deleted.</p></li><li><p>The <em>StatefulSet</em> controller creates a new pod to replace the deleted one. The new pod creates a new PVC with the same name.</p></li><li><p>Kubernetes finds the honeypot CSI PV we created in Step 3 and binds it to the new PVC.</p></li><li><p>The new pod starts and the Azure Disk is mounted to it.</p></li></ul><p>5. <strong>Verify the migration</strong>. Watch the pod start successfully and verify the application is running correctly.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl get pods -w</code></pre></div><p>Check the PVC status is &#8220;Bound&#8221;.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl get pvc $PVC_NAME

# NAME        STATUS   VOLUME              CAPACITY   ACCESS MODES   STORAGECLASS      AGE
# my-claim    Bound    pv-migrated-csi     100Gi      RWO            managed-premium   15m
</code></pre></div><p>Confirm the PVC is bound to the new CSI PV.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl get pv pv-migrated-csi

# NAME              CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS      REASON   AGE
# pv-migrated-csi   100Gi      RWO            Retain           Bound    default/my-claim       managed-premium            5m</code></pre></div><p>Confirm the legacy PV&#8217;s status is &#8216;Released&#8217;, indicating it is no longer bound and can be safely cleaned up.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">kubectl get pv $PV_NAME

# NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM     STORAGECLASS      REASON   AGE
# pv-legacy   100Gi      RWO            Retain           Released   ...       ...                          20m</code></pre></div><p>Once the application is running correctly on the new pod with all data intact, safely delete the legacy PV object.</p><h1>Alternative Approaches</h1><p>There are several other ways to solve this problem. Each comes with tradeoffs in service disruption, data loss risk, and operational complexity.</p><p><strong>Microsoft Static Volume</strong></p><p>Microsoft&#8217;s <a href="https://learn.microsoft.com/en-us/azure/aks/csi-migrate-in-tree-volumes">official documentation</a> for migrating from in-tree to CSI drivers on AKS proposes a similar but more manual method. The process involves patching the original PV&#8217;s reclaimPolicy to &#8220;Retain&#8221;, manually creating new PV and PVC manifests that point to the same underlying Azure Disk, and then updating the application deployment to reference the newly created PVC.</p><p>This approach preserves data on the disk. However, it requires a full application redeployment to switch to the new PVC, which means downtime and an operational maintenance window for each migration.</p><p><strong>Orphan and Adopt</strong></p><p>Another approach is to <a href="https://kubernetes.io/docs/tasks/run-application/delete-stateful-set/#deleting-a-statefulset">orphan</a> pods from their controlling <em>StatefulSet</em>. This involves deleting the <em>StatefulSet</em> with the <code>--cascade=orphan</code> flag, which leaves the pods and their PVCs running but unmanaged. A new <em>StatefulSet</em> using the updated CSI StorageClass can then be created to &#8220;adopt&#8221; the existing pods.</p><p>The risk here is significant. Without a controller, pods won&#8217;t get restarted or rescheduled in case of a node failure or eviction. For critical stateful workloads, this exposure window can lead to permanent data loss.</p><p><strong>Backup and Restore</strong></p><p>Platforms with mature Day-2 operations can perform a &#8220;cold&#8221; migration using tools like <a href="https://velero.io/">Velero</a>. This takes a complete snapshot of the application and its data, which can then be restored with modifications applied to the <em>StorageClass</em> before restore.</p><p>Backup-restore is powerful for disaster recovery but requires pausing applications. For large disks this introduces significant downtime. In a microservices architecture where pausing one service can cause cascading failures, this is a non-starter.</p><p><strong>Forking the Control Plane (The Datadog Approach)</strong></p><p>At KubeCon EU 2024, Datadog <a href="https://www.youtube.com/watch?v=sVQtO55910I">presented an approach</a> that involved forking the Kubernetes source code and patching the API server to bypass immutability constraints on live objects. This gives ultimate control over storage definitions of running pods.</p><p>This strategy isn&#8217;t suitable for managed Kubernetes services like AKS, GKE, or EKS, where access to modify control plane components is restricted. Forking the Kubernetes codebase also introduces long-term maintenance overhead and the risk of deviating from upstream. Unsustainable for most platform teams.</p><p><strong>Custom Operator for Disk Swaps (The &#8220;ATOM&#8221;-ic Approach)</strong></p><p><a href="https://atoms.co/">ATOMS</a> implemented a <a href="https://techblog.atoms.co/p/swapping-disks-in-kubernetes">custom operator</a> to handle shrinking a cloud provider managed disk. It uses a custom resource, mutating webhook, and <code>volume-populator</code> to provision new disks and transfer data between old and new PVCs. It handles volume resizing declaratively without manual operation.</p><p>For our use case this was more machinery than needed. We did not need to make any changes to the underlying Azure Disk. No data copy required. That said, a custom operator is a natural automation layer on top of the re-binding technique for teams that need ongoing storage operations.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3Q__!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3Q__!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 424w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 848w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 1272w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3Q__!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png" width="2613" height="1163" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1163,&quot;width&quot;:2613,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:281705,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/191815844?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4f9cec6-555b-4687-9181-550a6a743b89_3094x1648.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3Q__!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 424w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 848w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 1272w, https://substackcdn.com/image/fetch/$s_!3Q__!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99ddaa03-6f1f-4c76-9193-7b462606d524_2613x1163.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Alternative Approaches and their tradeoffs</figcaption></figure></div><h1>Conclusion</h1><p>We used this technique to migrate several hundred PVs on a platform operating <a href="https://techblog.atoms.co/p/managing-100s-of-kubernetes-clusters">100s of Kubernetes clusters</a> across a multi-region topology. The bulk of the complexity came from coordinating across large-scale data stores (like ClickHouse, CockroachDB, ElasticSearch, Kafka, and Prometheus), all running on cloud managed disks for durability and resilience where downtime or data loss was off limits. The migration was completed in under 2 months with a lean platform team and zero incidents.</p><p>A few learnings from this project:</p><ol><li><p><strong>Deep systems knowledge trumps brute force</strong>. The solution came from understanding the less obvious mechanics of the Kubernetes control plane (how <code>claimRef</code> binding works, when finalizers fire, and <em>StorageClass</em> behavior at runtime). Working with the system&#8217;s guardrails produced a simpler, safer result than any brute force approach.</p></li><li><p><strong>Experimentation builds operational excellence</strong>. We uncovered critical edge cases (like premature PV deletion causing Multi-Attach errors during node drains) only by pushing the system to failure on staging. Confidence in production comes from understanding how a system breaks, not just how it works.</p></li><li><p><strong>Automation is the key to reliability at scale</strong>. Automation lets us move fast and consistently, reducing the risk of human error. We automated the entire algorithm but gated the final pod restart with human approval so teams have control over when it&#8217;s safe to restart an application.</p></li></ol><div><hr></div><p><em>Shoutout to <a href="https://dk.linkedin.com/in/rasmusbachkrabbe">Rasmus Bach Krabbe</a> and the storage team at <a href="https://atoms.co/">ATOMS</a> for walking us through the inner workings of their <a href="https://techblog.atoms.co/p/swapping-disks-in-kubernetes">PvcAutoscaler</a>. We took one look at all that machinery and decided there had to be a lazier way. Their operator is a serious piece of infrastructure at scale.</em></p>]]></content:encoded></item><item><title><![CDATA[Save Millions on Your Cloud Bill: 11 Strategies for Kubernetes Cost Optimization]]></title><description><![CDATA[Are your cloud bills spiraling out of control?]]></description><link>https://blog.cleancompute.net/p/kubernetes-cost-optimization</link><guid isPermaLink="false">https://blog.cleancompute.net/p/kubernetes-cost-optimization</guid><dc:creator><![CDATA[Nibir Bora]]></dc:creator><pubDate>Tue, 27 May 2025 18:52:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!GOI-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GOI-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GOI-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 424w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 848w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 1272w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GOI-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png" width="1456" height="783" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:783,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:363389,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164579601?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GOI-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 424w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 848w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 1272w, https://substackcdn.com/image/fetch/$s_!GOI-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e48cce5-352d-459f-9411-2a423e0e57f3_4794x2578.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Figure: A multi-dimensional Kubernetes cost optimization model.</figcaption></figure></div><p>Are your cloud bills spiraling out of control? You're not alone. 84% of organizations struggle to manage their cloud spend<a href="https://www.flexera.com/about-us/press-center/new-flexera-report-finds-84-percent-of-organizations-struggle-to-manage-cloud-spend"><sup>1</sup></a>. 69% of IT organizations experience budget overruns<a href="https://www.gartner.com/peer-community/oneminuteinsights/omi-keeping-cloud-costs-check-it-leader-perspectives-rfz"><sup>2</sup></a>. A whopping 28% of cloud spending is wasted annually, and an astonishing 70% of companies are unsure about their exact spend on cloud<a href="https://www.g2.com/articles/cloud-cost-management-statistics"><sup>3</sup></a>.</p><p>As infrastructure scales, cloud compute costs can quickly snowball, especially when <a href="https://techblog.cloudkitchens.com/p/managing-100s-of-kubernetes-clusters">operating 100s of Kubernetes clusters</a>. In this blog we will lay out 11 actionable strategies to improve compute utilization on Kubernetes.</p><p>Keep these principles in mind as you craft your own cost optimization blueprint:</p><ol><li><p><strong>There's no single magic bullet</strong>. Optimizing costs extends beyond implementing clever technical solutions; it demands understanding and navigating the nuances and operational realities of your applications and underlying infrastructure.</p></li><li><p><strong>You can't optimize what you don't see</strong>. Before you can effectively control costs, you must be able to accurately measure and attribute where your money is going. Optimization efforts are merely guesswork without visibility</p></li><li><p><strong>High utilization doesn&#8217;t always equal low cost</strong>. Don&#8217;t fall for the illusion of high utilization. Ultimately, cost should remain the overarching measure of success for any optimization effort.</p></li><li><p><strong>Optimization vs. reliability is a delicate dance</strong>. Overly aggressive cost optimization will compromise system stability and performance. Balance with reliability indicators while only eliminating true waste.</p></li><li><p><strong>Shift Left by building cost consciousness</strong>. Cost optimization isn&#8217;t solely the responsibility of a central FinOps or platform team. Foster a culture where developers are empowered with cost insights and tools to operate efficient applications.</p></li><li><p><strong>Architect for efficiency early</strong>. While it&#8217;s wise to avoid premature optimization on unconfirmed needs, foundational architecture choices like multi-tenant clusters, or planning data residency, have long-term impact on your cloud spend.</p></li></ol><h1>1. FinOps &amp; Cost Visibility</h1><p>Kubernetes workloads often autoscale and are distributed across diverse node types, especially in shared multi-tenant clusters. This obscures compute cost origins, prevents identifying inefficiencies, and assigning accountability of resources to specific teams or applications. Cloud providers usually have built in cost dashboards, but only provide visibility only at the VM or node level and lack attribution at the application level,</p><p><strong>Solution</strong>: Adopt cost visibility and attribution for your platform. For simpler deployments, off-the-shelf tools like <a href="https://opencost.io/">OpenCost</a> provide real-time cost allocation by pod, label, namespace, and service, capturing price signals for CPU-seconds, memory bytes, storage IOPS, network egress, etc. For complex, multi-cloud, or customized platforms, consider developing an in-house attribution system by aggregating utilization metrics and reconciling them with cloud provider billing data.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Delayed Adoption</strong>: Cost visibility is frequently an afterthought. The painful result? Substantial, untraceable waste.</p></li><li><p><strong>Umbrella Cost Models</strong>: This rarely works for shared resources (databases, metrics, blog storage, etc.) due to unclear ownership. Define a clear cost model that allocates shared resource costs based on usage or pre-defined criteria to teams or applications.</p></li><li><p><strong>Lack of Governance</strong>: Without continuous audits and automated alerts, optimization efforts can easily regress. Implement regular review processes to flag anomalies based on projected modeling.</p></li></ol><h1>2. Custom Scheduler for Bin-Packing</h1><p>The default Kubernetes scheduler distributes workloads uniformly across nodes. This leads to persistent overprovisioning resulting in unused capacity across multiple nodes and sparse bin-packing.</p><p><strong>Solution</strong>: Configure a custom Kubernetes scheduler to favor tighter bin-packing using <code>MostAllocated</code> or <code>RequestedToCapacityRatio</code> scoring strategies. This fills existing nodes more completely before provisioning new ones, boosting resource utilization. Combine with cost-aware scheduling (e.g. prioritize cheaper node types) when multiple node pools are involved.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Scheduler Unavailability</strong>: The self-managed custom scheduler can become unavailable and lead to pending pods. Design for high availability and consider using it in conjunction with the default scheduler with fail-open mechanics.</p></li><li><p><strong>Pods per node limits</strong>: Cloud providers&#8217; max-pods-per-node limits on larger node instance types can restrict how tightly you can bin-pack pods on them. Carefully plan for use of larger instance types, or use a combination of large and small nodes.</p></li></ol><h1>3. Cluster Autoscaler Optimization</h1><p>Default Cluster Autoscaler (CA) settings like <code>--scale-down-utilization-threshold</code> of 0.5 (50% node utilization) and <code>--scale-down-unneeded-time</code> of 10 minutes, lead to slow scale-down operations. In dynamic platforms, this conservative behavior results in nodes lingering longer than necessary translating into unnecessary costs.</p><p><strong>Solution</strong>: Configure CA to more aggressively consolidate nodes by increasing <code>--scale-down-utilization-threshold</code> to a higher value (e.g. 0.7 to scale down nodes when utilization falls below 70%), and decreasing <code>--scale-down-unneeded-time</code> (e.g. to 5 minutes) to consolidate nodes faster. Combine this with appropriate CA expander strategies (e.g., priority, least-waste, spot-instance) to optimize node selection when multiple node pools are involved. This strategy works with CA alternatives like <a href="https://karpenter.sh/">Karpenter</a> as well.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Scaling Oscillation or Thrashing</strong>: Overly aggressive scale-down can lead to nodes being removed then immediately added back. This is wasteful as most cloud providers price nodes per hour. Balance stability by fine-tuning scale-down delays timers like <code>--scale-down-delay-after-add</code> and <code>--scale-down-delay-after-delete</code>.</p></li><li><p><strong>Anti-affinity Rules</strong>: Pods with anti-affinity or topology spread constraint can block node scale-down and remove underutilized nodes. Use multi-tenant clusters to alleviate this.</p></li><li><p><strong>Workloads Blocking Eviction</strong>: Workloads configured with PodDisruptionBudgets (PDBs) set to 0 or annotations like safe-to-evict: false explicitly block node scale-down by preventing pods from being drained from a node.</p></li></ol><h1>4. Spot Nodes for Ephemeral Workloads</h1><p>Short-lived ephemeral workloads like analytics pipelines, batch jobs, data ingestion agents, etc. frequently spin-up and spin-down. This prevents Cluster Autoscaler from scaling down nodes. Running these workloads on on-demand nodes doesn&#8217;t make financial sense.</p><p><strong>Solution</strong>: Schedule ephemeral workloads onto spot nodes. Spot nodes are significantly cheaper (at least 60% cheaper on AWS EKS, GCP GKE and Azure AKS) than on-demand instances. Also use spot nodes for non-business-critical workloads where occasional interruptions are acceptable.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Sudden Eviction</strong>: Cloud providers reclaim spot nodes with short notice (e.g., 30 seconds on Microsoft Azure). Ensure workloads are fault tolerant and can withstand abrupt termination.</p></li><li><p><strong>Non-Standard Shutdowns</strong>: Some cloud providers may not follow standard Kubernetes shutdown processes (e.g., sending SIGTERM). See <a href="https://techblog.cloudkitchens.com/i/145625273/handling-abrupt-spot-node-preemptions">this blog</a> that describes hardening spot nodes with custom tooling.</p></li><li><p><strong>Spot Capacity Shortages</strong>: Spot availability fluctuates. De-risk by diversifying your spot instance types. Combine with a baseline of on-demand instances for stability, allowing workloads to spill over to on-demand nodes only when spot capacity is unavailable. Configure Cluster Autoscaler expander to prioritize scaling up spot nodes before others.</p></li></ol><h1>5. Automatic Request Tuning</h1><p>Manually configuring CPU and memory requests and limits for pods is inefficient. Developers often err on the side of overprovisioning, driven by concerns about performance, stability, and the potential impact of noisy neighbors. Furthermore, initial resource requests are rarely audited or adjusted over time as application needs evolve. This leads to wasted resources.</p><p><strong>Solution</strong>: Automate resource request setting and tuning. Continuously monitor actual workload usage and dynamically adjust requests and limits to match consumption patterns. Kubernetes Horizontal Pod Autoscaler (HPA) and Vertical Pod Autoscaler (VPA) cannot be used in conjunction. But you can leverage VPA recommendations to tune requests alongside HPA, paired with cool-off logic to prevent thrashing. Note that newer Kubernetes versions support VPA in initial mode where it assigns resource requests on pod creation and never changes them later.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Phased Rollout and Escape Hatches</strong>: Implement with a fail-open approach and provide clear escape hatches for developers to temporarily disable or override automation for specific workloads during critical issues.</p></li><li><p><strong>Developer Control and Trust</strong>: For platforms with hundreds of microservices foster trust by providing dashboards with tuning recommendations.</p></li><li><p><strong>Resource Use Profiles</strong>: Craft tuning profiles (e.g. guaranteed, burstable, etc.) to cater to diverse workload consumption patterns and criticality.</p></li><li><p><strong>Application of Scaled-Down Requests</strong>: If tuned down requests are applied only at deploy time, it can confuse developers troubleshooting new changes. Implement safe, programmatic restarts that attribute changes clearly.</p></li></ol><h1>6. Custom Metric-Based Autoscaling</h1><p>HPA natively supports scaling based on CPU and memory utilization. However, this is insufficient for applications with scaling needs reflected best in business or application-level metrics like requests per second, queue depth, active connections, etc. Scaling solely on CPU or memory can cause instability and failures, leading to reliability concerns. Consequently, teams often overprovision to handle peak loads.</p><p><strong>Solution</strong>: Enable custom metric-based autoscaling. Deploy a custom metrics adapter (e.g. Prometheus Adapter) that exposes metrics from your monitoring system to the Kubernetes Custom Metrics API (<code>custom.metrics.k8s.io</code>). Alternatively, <a href="https://keda.sh/">KEDA</a> provides flexible, event-driven autoscaling with built-in &#8220;scalers&#8221; for various event sources (message queues, databases, cloud services), including the ability to scale down to zero pods.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Metrics Infrastructure Reliability</strong>: Scaling behavior is tied to metrics pipeline&#8217;s availability, and can lead to incorrect scaling decisions. Ensure high reliability for your metrics infrastructure.</p></li><li><p><strong>Metric Accuracy</strong>: Inaccurate metrics can lead to undesirable scaling behavior (e.g., thrashing or flapping).</p></li><li><p><strong>Single Custom Metrics Server Limitation</strong>: Historically, Kubernetes environments only supported one custom metrics server. Carefully plan your metrics ecosystem.</p></li><li><p><strong>Failure Modes and Defaults</strong>: Design for failure modes. Implement sane default replica counts or fallbacks to ensure application stability during metric outages.</p></li></ol><h1>7. Multi-Tenant Clusters</h1><p>It is common to provision single-tenant Kubernetes clusters per team or application when starting off. This approach, driven by a perceived need for strict isolation or sometimes developer insistence, is a classic recipe for overprovisioning.</p><p><strong>Solution</strong>: Transition to a multi-tenant cluster architecture. Kubernetes offers robust controls for diverse workloads to coexist securely and efficiently on shared hardware:</p><ul><li><p><em>Namespaces</em>: Logical tenant isolation within a cluster.</p></li><li><p><em>Resource Requests and Limits</em>: Manage pod resource consumption, preventing individual workloads from monopolizing resources.</p></li><li><p><em>Resource Quotas and LimitRanges</em>: Enforce aggregate resource consumption per namespace.</p></li><li><p><em>Role-Based Access Control (RBAC)</em>: Restrict tenant access to only their designated namespaces, ensuring API isolation.</p></li><li><p><em>Network Policies</em>: Providing network isolation by controlling inter-pod communication across namespaces.</p></li><li><p><em>Pod Security Standards (PSS) or Security Contexts</em>: Enforce security hygiene and prevent privilege escalation.</p></li></ul><p>Pitfalls to avoid:</p><ol><li><p><strong>"Noisy Neighbor" Phenomenon</strong>: Workloads can still spike CPU or memory usage, impacting applications co-located on nodes. Applications that constantly exceed their requests are problematic as Kubernetes schedules by resource requests not real-time use.</p></li><li><p><strong>Network and Disk I/O Bottlenecks</strong>: Kubernetes doesn&#8217;t currently allow specifying network and disk I/O requests. I/O intensive applications can starve colocated workloads of shared bandwidth on nodes. Implement monitoring and consider pod anti-affinity or topology spread constraints.</p></li></ol><h1>8. Align Node Shapes with Workload Demands</h1><p>Discrepancies between node CPU:memory ratios and that of workload consumption lead to resource imbalances. For example, memory-intensive workloads on high CPU:memory nodes can underutilize CPU while bottlenecking memory. This leads to more nodes than actually required.</p><p><strong>Solution</strong>: Migrate each node pool to node shapes that closes the gap between CPU and memory efficiency. To do so, adjust your node instance types&#8217; CPU:memory ratio to align with aggregate workload consumption, &#931;(CPU Used):&#931;(memory Used). This will reduce overall compute costs. You can easily use an off-the-shelf tool like <a href="https://karpenter.sh/">Karpenter</a> to automate this.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>In-place Node Type Changes</strong>: Node instance types cannot be changed in place. Build custom tooling to orchestrate node pool replacement without disrupting workloads. See <a href="https://techblog.cloudkitchens.com/i/142916610/automating-node-pools">this blog</a> for a highly automated way of replacing a node pool.</p></li><li><p><strong>Premature Optimization</strong>: Best executed after workloads are right-sized. Optimizing node shape before workload rightsizing is ineffective as the CPU and memory efficiency will change later, requiring replacing node instance type again.</p></li><li><p><strong>System Overhead</strong>: Kubernetes components (kubelet, kube-proxy, container runtime) consume a portion of node resources. Account for this overhead when evaluating available CPU and memory, especially on smaller nodes.</p></li></ol><h1>9. Enable Controlled Evictions</h1><p>Workloads with PodDisruptionBudgets (PDBs) set to 0 or safe-to-evict: false annotations block Cluster Autoscaler node scale-down operations. These configurations are common for singletons or critical workloads, and are problematic in multi-tenant platforms.</p><p><strong>Solution</strong>: Instate policies to disallow PDB set to 0 and safe-to-evict: false annotations. For most cases, proper application architecture hygiene (handling SIGTERM, setting terminationGracePeriodSeconds) suffices. For complex workloads, build custom tooling to orchestrate graceful workload eviction by exposing a pre-shutdown hook. For example, in stateful applications like CockroachDB this may execute steps like draining connections, committing transactions, or backing up data.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Long-Running Jobs</strong>: Long-running workloads, like Apache Flink, with significant internal state, may not recover gracefully from disruptions. Restarts are costly due to re-processing or extended execution times. Isolate such workloads onto a dedicated node pool or cluster. Newer versions of Flink may support checkpointing (or similar specialized recovery mechanisms).</p></li><li><p><strong>Cost of Exceptions</strong>: Strictly control non-evictable workloads by isolating them onto dedicated node pools or clusters. This simplifies cost accounting for these exceptions and prevents impacting overall cluster efficiency.</p></li></ol><h1>10. Right-Size Persistent Volumes</h1><p>Persistent storage costs in Kubernetes can accumulate rapidly when using cloud managed Persistent Volumes (PVs). Without active management, teams default to expensive storage classes, over-provision volume sizes, or leave unused volumes lingering, leading to accumulating costs.</p><p><strong>Solution</strong>: Continuously monitor storage consumption. Cloud managed disks are easy to size up as needed, so always start with the smallest possible volume. Encourage the use of different StorageClass definitions exposing various cloud storage types based on workload performance needs. For large-scale complex platforms, consider building custom tooling to dynamically resize PVs to align with actual usage.</p><p>Pitfalls to avoid:</p><ul><li><p><strong>Accidental Data Loss</strong>: Implement backup and retention strategies to avoid accidental data loss from aggressive deletion policies, or when resizing.</p></li><li><p><strong>Unused or Orphaned Volumes</strong>: Unused volumes often liner after application decommissioning or even from incomplete pod evictions sometimes. Automate identifying and deleting unused or orphaned PVCs and their underlying PVs.</p></li></ul><h1>11. Optimize Network Costs</h1><p>Network costs can become an unexpected line item in cloud bills, because cloud providers charge for all ingress and egress traffic, cross-region data transfer, load balancers, gateways, etc. A multi-region Kubernetes architecture built for resilience can come at an exorbitant price. Applications with high data transfer or public-facing services can rapidly accumulate network charges too.</p><p><strong>Solution</strong>: Minimize cross-region and inter-zone traffic by carefully architecting your data residency. For example, prohibit stateless services from direct cross-region data access. Prefer internal Load Balancers, Ingress Controllers, and private endpoints for internal traffic. Minimize data flowing out of the cloud provider&#8217;s network to the internet, and use Content Delivery Networks (CDNs) for static content.</p><p>Pitfalls to avoid:</p><ol><li><p><strong>Network Complexity</strong>: Advanced networking solutions (e.g., custom ingress setups, service mesh for traffic routing) add complexity to your Kubernetes environment, and come with management and troubleshooting overhead.</p></li><li><p><strong>Reduced Resilience</strong>: Confining network traffic to a single zone or region, without implementing robust failover mechanisms, increases the risk of application downtime during cloud provider zone or regional outages.</p></li><li><p><strong>Provider Pricing Maze</strong>: All cloud providers charge differently for network traffic, so an architecture that works for one may not work for another. Study your specific cloud provider's cost structure. For instance, it may be cheaper to perform data backup onto another region instead of maintaining continuous cross-region data consistency.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g6dx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g6dx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 424w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 848w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 1272w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g6dx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png" width="1456" height="755" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:755,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:320342,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.cleancompute.net/i/164579601?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g6dx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 424w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 848w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 1272w, https://substackcdn.com/image/fetch/$s_!g6dx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a3516f-401a-4fc4-8c63-583e5e85973e_4735x2456.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Figure: Cost optimization strategies applied to different parts of the platform.</figcaption></figure></div><div><hr></div><p><em>Continue reading <a href="https://blog.cleancompute.net/p/kubernetes-cost-optimization-paradox">Part 2: But What About Reliability?</a> of this blog, where we share a case study detailing real-world application of these strategies by an organization operating cloud-scale Kubernetes infrastructure across multiple cloud providers and continents. Get ready for behind-the-scenes war stories and first-hand lessons.</em></p>]]></content:encoded></item></channel></rss>