<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Graziano Casto on Medium]]></title>
        <description><![CDATA[Stories by Graziano Casto on Medium]]></description>
        <link>https://medium.com/@graziano__casto?source=rss-ee66157bdb4c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*J0dfFm-jiN_HU_4FmLc6YA.jpeg</url>
            <title>Stories by Graziano Casto on Medium</title>
            <link>https://medium.com/@graziano__casto?source=rss-ee66157bdb4c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 09:00:03 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@graziano__casto/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[I Watched a Microsoft Java Champion Talk About K8s Efficiency. Here is What I Learned.]]></title>
            <link>https://medium.com/javarevisited/i-watched-a-microsoft-java-champion-talk-about-k8s-efficiency-here-is-what-i-learned-c4811d10f7d4?source=rss-ee66157bdb4c------2</link>
            <guid isPermaLink="false">https://medium.com/p/c4811d10f7d4</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[performance]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Graziano Casto]]></dc:creator>
            <pubDate>Wed, 11 Feb 2026 15:15:59 GMT</pubDate>
            <atom:updated>2026-02-12T14:10:22.156Z</atom:updated>
            <content:encoded><![CDATA[<h4>Why 60% of Java workloads on Kubernetes are wasting money and the 4 lessons from Microsoft &amp; Akamas to fix it.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ll2hKizQntwQn_7EYfYImg.png" /></figure><p>Java is the backbone of enterprise software, and Kubernetes is the operating system of the cloud. It would be logical to assume that by 2026, these two giants would work perfectly together out of the box. Yet, after attending a <a href="https://akamas.io/events/java-on-kubernetes-lessons-in-performance-engineering-with-akamas-and-microsoft/">recent deep-dive session</a> between <a href="https://www.linkedin.com/in/brunocborges/"><strong>Bruno Borges</strong></a> (Principal Product Manager at Microsoft and Java Champion) and <a href="https://www.linkedin.com/in/stefanodoni/"><strong>Stefano Doni</strong></a> (CTO at <a href="https://akamas.io/">Akamas</a>), I realized that this assumption is costing companies a fortune in <strong>wasted resources</strong> and <strong>performance issues</strong>.</p><p><a href="https://akamas.io/resources/the-state-of-java-on-kubernetes-2026-why-defaults-are-killing-your-performance/">Analyzing telemetry from thousands of production JVMs</a>, the data they presented was sobering: the vast majority of Java workloads on Kubernetes are running with <em>default configurations</em> that are actively damaging applications.</p><p>Here are the four critical lessons I took away from the session.</p><h3>Lesson 1: “Container-Aware” doesn’t mean “Container-Optimized”</h3><p>The first major misconception is about memory configuration. We are often led to believe that modern Java versions are “container-aware”, which implies the JVM sees container limits and configures itself optimally. In reality, the JVM is aware of the limits but operates on a <strong>conservative</strong> configuration. If an explicit heap size is not set, the JVM typically defaults to using only <strong>25%</strong> of the memory limit for the heap.</p><p>This default configuration leads to a huge waste of resources. For instance, if a container has 1 GB of RAM, the JVM may allocate only 256 MB of heap size. This practice is common, with the majority of surveyed JVMs running with no more than 1 GB of RAM and 1 CPU.</p><blockquote>“Yes, if you don’t set the heap size, you are wasting resources, and as we saw in the data, most containers have at least 1 GB of RAM and with 1 GB of RAM, you’re allocating 256 MB of heap size.” — Bruno Borges</blockquote><p>This conservative default is a legacy of an era when the JVM was designed to share server resources and avoid consuming all available memory. However, in a containerized environment where resources are guaranteed, this conservative behavior prevents the JVM from maximizing resource utilization.</p><h3>Lesson 2: “Micro-Containers” are a latency trap</h3><p>The trend of using “Micro-Containers”, often assigning less than one CPU, creates a fundamental architectural conflict for Java. Java is a highly multi-threaded engine, relying on background threads for core tasks like <strong>Garbage Collection (GC)</strong> and the<strong> Just-In-Time (JIT) </strong>compiler.</p><p>You have to imagine the Kubernetes CPU limit not as a speed limit, but as a <em>time quota</em>. If you give a container half a CPU (500m), you get 50 milliseconds of runtime every 100 milliseconds. But Java is a Just-In-Time (JIT) compiled language: when compilation starts, it consumes that quota instantly.</p><p>If the JVM is not given enough CPU, all utilization may go to GC or JIT, preventing the business code from running. The result is application freezing and high latency, which developers often mistake for high user load.</p><blockquote>“You think it’s because of too many users are hitting the web service when in reality it’s because the garbage collector is working and that’s where CPU throttling is happening.” — Bruno Borges</blockquote><h3>Lesson 3: Scaling out can make things worse</h3><p>Adding more pods (horizontal scaling) can worsen performance if each pod is too small. The JVM is a highly multi-threaded engine that requires resources for internal management threads, such as the GC and JIT compiler. In a small container, these internal threads fight the business logic for limited CPU. If the JVM is not given enough CPU, it spends most of its time performing its own internal work, not the business work.</p><p>The data presented in the webinar showed that a strategy of using small containers and many replicas can actually <strong>result in resource waste</strong>.</p><blockquote>“I would say that’s that’s okay, but do consider if running slightly bigger containers with slightly fewer instances will give you the same amount of resource utilization. You’re still using the same amount of CPU and memory, but will give you much better performance because now the JVM has room to breathe. The JVM has room to operate at a more stable level.” — Bruno Borges</blockquote><p>A strategy of slightly increasing the CPU for existing replicas instead of drastically increasing the replica count is recommended for most of the JVM workloads.</p><h3>Lesson 4: The “silent” GC switch</h3><p>A significant trap lies in Garbage Collector (GC) ergonomics. The JVM automatically selects its default GC algorithm based on the amount of memory and CPU it detects. If developers test their applications in generous staging environments, the JVM is likely to use a high-performance GC, like G1GC. However, if that same code is deployed to small, “cost-optimized” production containers with insufficient CPU or memory, the JVM may silently downgrade to the single-threaded <strong>SerialGC</strong>.</p><p>SerialGC is rarely explicitly configured by developers. While it can be fine for most applications, it often leads to severe tail latency due to its “stop the world” mechanism. The core issue is the unexpected switch from the tested runtime to a different one.</p><blockquote>“The default depends on how much memory and how much CPU you have, which again if it’s not enough CPU or memory you actually default to Serial GC, which can be great for most applications.” — Bruno Borges</blockquote><p>This silent GC downgrade prevents developers from comparing performance against a consistent baseline.</p><h3>Stop Guessing</h3><p>The conclusion of the discussion wasn’t to suggest a single magic flag. The point is that manual tuning at scale has become impossible. You cannot solve the three-variable equation of throughput, latency, and cost by guessing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pd1rqA_XRA7laBugN3UypA.png" /></figure><p>This is where <a href="https://akamas.io/insights/"><strong>Akamas Insights</strong></a> comes into play. Instead of manually auditing YAML files, Akamas connects to your observability stack and runs a comprehensive, automated health check. It tells you immediately where you are wasting memory due to the “25% trap”, where CPU throttling is killing your latency, and how to right-size your containers to stop flying blind.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c4811d10f7d4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/javarevisited/i-watched-a-microsoft-java-champion-talk-about-k8s-efficiency-here-is-what-i-learned-c4811d10f7d4">I Watched a Microsoft Java Champion Talk About K8s Efficiency. Here is What I Learned.</a> was originally published in <a href="https://medium.com/javarevisited">Javarevisited</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes 1.35: In-Place Pod Resizing is Finally GA. Is it the End of Pod Restarts?]]></title>
            <link>https://aws.plainenglish.io/kubernetes-1-35-in-place-pod-resizing-guide-no-restarts-896eff23157b?source=rss-ee66157bdb4c------2</link>
            <guid isPermaLink="false">https://medium.com/p/896eff23157b</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[cloud-native]]></category>
            <category><![CDATA[sre]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Graziano Casto]]></dc:creator>
            <pubDate>Sat, 07 Feb 2026 12:43:19 GMT</pubDate>
            <atom:updated>2026-02-07T12:43:19.902Z</atom:updated>
            <content:encoded><![CDATA[<h4>Kubernetes 1.35 makes resources mutable. Here is how In-Place Resizing works under the hood and where it still requires caution.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eROKKyWTO0JcgYCuWI_TnQ.png" /></figure><p>The ability to change the size of a running Pod feels like a feature that should have existed from day one. However, in the world of Kubernetes, resources like CPU and memory were considered immutable for a very long time. If you got your capacity planning wrong, your only option was to destroy the workload and start over. With the release of <a href="https://kubernetes.io/blog/2025/12/17/kubernetes-v1-35-release/">Kubernetes 1.35</a>, the platform finally embraces the idea that applications are dynamic and that our infrastructure should be able to adapt to them without forcing a reboot.</p><h3>A Feature Years in the Making</h3><p>This capability did not appear overnight. The community began working on <a href="https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources">In-Place Pod Resizing</a> way back in version <strong>1.27</strong>. It started as an Alpha feature, which means it was experimental and hidden behind special feature gates because it was risky. Changing the resource limits of a running process on Linux is technically complex. If the Kubelet tries to shrink memory too aggressively, the application might crash immediately. Over the last few years, the Kubernetes team has slowly refined how the Kubelet talks to the container runtime to ensure safety. Now, in version 1.35, the feature has finally reached General Availability (GA). This means it is considered stable, safe, and ready for critical production environments.</p><h3>How It Works Under the Hood</h3><p>To understand the magic, we need to look at what happens when you actually request a change. In the past, you would update the Pod specification directly, which confused the system into thinking you wanted a new Pod. In Kubernetes 1.35, the process is much more deliberate. You do not touch the main Pod spec; instead, you send a request to a special “subresource” called resize. This tells the Kubernetes API server that your intention is strictly to adjust resources, not to redeploy the application.</p><p>Once the API server accepts your request, the Kubelet (the agent running on the specific node where your Pod lives) takes over. The Kubelet acts like a strict traffic controller. First, it looks at the available capacity on the machine. It calculates if there is enough free CPU or memory to satisfy your new request. If the node is full, the Kubelet will not kill other Pods to make room. Instead, it places your request in a “<em>Pending</em>” state. Your Pod continues running with its old limits, patiently waiting in line until enough resources on that specific node become free.</p><p>If the node does have space, the Kubelet proceeds to the next step. It talks to the Container Runtime (like containerd or CRI-O) using the Container Runtime Interface. It instructs the runtime to update the Linux Control Groups (cgroups) for that specific process. Think of cgroups as invisible walls that define how much of the computer a program can use. The runtime simply moves these walls further out, instantly giving the application access to more CPU cycles or memory pages. If you have configured a resizePolicy that requires a restart, the Kubelet will reboot the container; otherwise, the change happens silently while the code keeps running.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s2zg9FGCC034JMXYVRg3hg.png" /><figcaption>How In-Place Pod Resize Works</figcaption></figure><h3>The Java Paradox: CPU vs. Memory</h3><p>Considering the Pod size it’s not enough, we have to look at how applications actually behave, and there is no better example than the Java Virtual Machine (JVM). Java applications have a unique personality. When they first start up, they are incredibly hungry for CPU power because of the <strong>JIT Compiler</strong>. Once they are up and running, they often settle down and use less CPU.</p><p>In the past, this created a difficult choice. You either gave the Java app a huge amount of CPU just for the first five minutes (wasting money for the rest of the day), or you gave it a small amount of CPU and watched it take twenty minutes to start up. With In-Place Resizing, you get the best solution. You can launch the Pod with high CPU limits to ensure a fast startup. Once the application is ready, an autoscaler (like the <a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/">VPA</a>) can quietly reduce the CPU limit down to a maintenance level. The application stays online, the customers stay happy, and your cloud bill goes down.</p><p>However, memory is a completely different story, and this is where you must be careful. While Kubernetes can easily give a container more memory, the application inside might not notice. For example, when a Java app starts, it looks at the available memory and decides how big its <em>Heap</em> should be.</p><blockquote>If you launch the JVM using default settings (without setting <em>-Xmx</em> or <em>-XX:MaxRAMPercentage</em>), the default Heap size, based on JVM heuristics, will be 25% of the available memory (the Pod&#39;s memory limit).</blockquote><p>It usually makes this decision only once. If you double the container’s memory an hour later, the JVM will still stick to its original, smaller Heap size. It does not automatically expand just because the room got bigger. In these cases, you still need to restart the container so the application can recalculate its settings.</p><blockquote>Java and other runtimes do not currently support on-the-fly memory resizing. There is an <a href="https://bugs.openjdk.org/browse/JDK-8359211">ongoing conversation</a> with the Java community to make this possible.</blockquote><p>While expanding memory requires care, shrinking it is even more complex. You cannot simply take away RAM that an application is currently using to store data. When you ask Kubernetes to lower a memory, the Kubelet performs a ‘best-effort’ safety check. It looks at how much memory the container is actually using at that exact moment. If your app is using 4GB and you try to lower the limit to 2GB, the system will not kill the container. Instead, the resize operation will hang. The status will remain stuck in ‘<em>InProgress</em>’ indefinitely, waiting for the application to voluntarily free up that space. Unlike CPU, which can be throttled instantly, memory cannot be reclaimed until the application decides to let it go.</p><p>This is why Kubernetes 1.35 allows you to set different policies for different resources, letting you resize CPU instantly while requiring a restart for memory changes.</p><h3>Real-World Limitations</h3><p>While this feature is a game-changer, it cannot break the laws of physics. The most obvious limitation is the physical capacity of the node. If your server is full and you ask to double the size of a Pod, the resize operation will simply stop and wait. Kubernetes cannot create hardware out of thin air, and it will not automatically move the Pod to a different node to make room for the new size. You have to wait for other workloads on that specific machine to finish and free up space.</p><p>There is also a strict rule regarding the <a href="https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/"><em>Quality of Service</em></a> (QoS) class that you must respect. Kubernetes classifies every Pod as Guaranteed, Burstable, or BestEffort based on its configuration, and this classification is permanent for the life of the Pod. For example, if you deploy a critical workload as ‘Guaranteed’ (where the resource request exactly equals the limit), you cannot change just one of those values later. If you try to increase the limit without also increasing the request, you would technically be changing the Pod’s class to ‘Burstable,’ which is forbidden. The API server will reject your command immediately to prevent you from accidentally breaking your own production guarantees.</p><p>There are also operating system limitations to consider. Currently, this smooth resizing capability relies heavily on how Linux manages processes specifically through <em>cgroups v2</em>. This means that if you are running Windows containers in your cluster, you are left out of the party for now. Windows nodes still require the traditional recreation of Pods to apply new resource specs.</p><h3>The Future of Autoscaling</h3><p>Ultimately, this update paves the way for a much smarter generation of autoscalers. We are moving away from the era where the <a href="https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/">Vertical Pod Autoscaler</a> was difficult to use because it caused too many disruptions. We are entering a time where our clusters can breathe. They can expand during traffic spikes and shrink during quiet hours, all while the application logic continues to run uninterrupted. It has been a long road from Alpha to GA, but Kubernetes 1.35 has finally made the dream of elastic, restart-free scaling (almost) a reality.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=896eff23157b" width="1" height="1" alt=""><hr><p><a href="https://aws.plainenglish.io/kubernetes-1-35-in-place-pod-resizing-guide-no-restarts-896eff23157b">Kubernetes 1.35: In-Place Pod Resizing is Finally GA. Is it the End of Pod Restarts?</a> was originally published in <a href="https://aws.plainenglish.io/">AWS in Plain English</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>