<?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"><channel><title><![CDATA[Reads]]></title><description><![CDATA[Everything about distributed systems, cloud infrastructure and AI engineering]]></description><link>https://shehroz.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Reads</title><link>https://shehroz.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 14 Oct 2026 09:34:44 GMT</lastBuildDate><atom:link href="https://shehroz.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Achieving 99.99% uptime on single Pod rollout using NEG-based Network Load Balancing]]></title><description><![CDATA[If you’re using an external passthrough Network Load Balancer sitting in front of your Kubernetes cluster, facts are most of the times its not aware of your Service Pod’s container health which result]]></description><link>https://shehroz.hashnode.dev/achieving-99-99-uptime-on-single-pod-rollout-using-neg-based-network-load-balancing</link><guid isPermaLink="true">https://shehroz.hashnode.dev/achieving-99-99-uptime-on-single-pod-rollout-using-neg-based-network-load-balancing</guid><category><![CDATA[Platform Engineering ]]></category><category><![CDATA[Cloud Engineering ]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Load Balancing]]></category><category><![CDATA[google cloud]]></category><dc:creator><![CDATA[Shehroz Ali]]></dc:creator><pubDate>Sun, 04 Oct 2026 20:13:53 GMT</pubDate><content:encoded><![CDATA[<p>If you’re using an external passthrough Network Load Balancer sitting in front of your Kubernetes cluster, facts are most of the times its not aware of your Service Pod’s container health which results in users receiving Connection Reset (RST) or invalid response.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/a96b250d-3cda-472f-9b0e-30d199a2ae36.png" alt="" style="display:block;margin:0 auto" />

<p>This becomes increasingly more critical during peak hours of your traffic or especially during times when RPS is extremely high and you can’t afford to drop any network packet or cause connection reset as it can long-term hurt you business or revenue.</p>
<p>In our company, we’ve been noticing for a long time that some of our uptime monitoring checks starts failing randomly especially during node upgrades, rollouts, pod restarts or any upgrade/maintenance work going on. At first, we thought this could be a random network blip over the wire, but sooner it became clear that this was happening specifically whenever a Kubernetes node goes upgrading or workloads migrate to existing/new nodes.</p>
<p>We started digging down and after a while it got clear to us that this was happening in our single-replica deployment meaning 1 proxy (NGNIX) pod on each node sitting behind 1 global external Network Load Balancer.</p>
<p>Let me get into straight</p>
<p>In a traditional NLB setup, the Load Balancer picks any random VM from the list (target-pool based) and forwards the TCP packet to that VM. Once the packet is forwarded to the VM, LB did its job and moves on to forwarding next packet. That’s all. So in short, the LB is not aware of the running Service Pod health, if Pod is Not Ready/Terminating LB will still end up forwarding traffic to that VM.</p>
<p>That’s what causing connection lost and reset.</p>
<p>Google Cloud offers another type of more modern Network Load Balancer and its called Regional service-based Network Load Balancer. So instead of maintaing a fixed target-pool of instances, it maintains NEGs (Network Endpoint Groups) which contains the VM IP inside. The interesting thing is the NEG list gets updated by a dedicated NEG-controller running inside GKE control plane which watches Kubernetes <code>EndpointSlice</code> specifically for the app defined in Service selector label for Load Balancer.</p>
<p>To enable regional external NLB, add this in your manifest and apply (immutable):</p>
<pre><code class="language-yaml">apiVersion: v1
kind: Service
metadata:
  labels:
    app: proxy
  name: tls-proxy
spec:
  externalTrafficPolicy: Local
  loadBalancerClass: networking.gke.io/l4-regional-external # add this
</code></pre>
<ol>
<li>Pod goes in Terminating state</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/298ac0ae-4194-400c-8909-a96683d07050.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li>EndpointSlice gets updated marking that Pod Not Ready and Cilium reponds with 503 to mark node as unhealthy</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/42270138-b70d-474f-8318-0326261307af.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li>NEG controller watches EndpointSlice and updates the NEGs removing the VM IP of the terminating Pod</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/58629fa6-a290-4961-a395-0aef3b5ee7a0.png" alt="" style="display:block;margin:0 auto" />

<ol>
<li>LB send new connections to other nodes running health replica</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/a441fec4-a2fe-43af-a961-d26d24ea0977.png" alt="" style="display:block;margin:0 auto" />

<p>You might will think we’re done here and no more connection reset right? The answer is no!</p>
<p>Now either could be your situation:</p>
<p>Pod goes in Terminating state or shutting down during node upgrade, rollout, restart, etc. (we can fix) Pod dies immediately, crashed, killed, server error (your luck!) If a Pod is in terminating state and you want to gracefully handle all existing connections without dropping any packets you need to tweak and play-around your proxy settings and LB connection draining timeout.</p>
<p>In our case since we’re using NGNIX as our proxy layer for TLS and backend routing, we tweaked these settings and observed close to 99.99% uptime without connection loss.</p>
<ul>
<li><p>Added sleep 40s in <code>preStop</code> to let NGNIX stay alive and keep serving existing connections</p>
</li>
<li><p>Set Connection Draining duration of regional LB to 30s to allow existing connections to finish before cutting off and removing from NEGs</p>
</li>
<li><p>Added <code>keepalive_time</code> to 15s (or your choice) to gracefully close existing connections after 15s and let user/client open fresh TCP connection with other VMs running healthy replica</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/88b18496-4f6f-432b-867f-07c599e441fd.png" alt="" style="display:block;margin:0 auto" />

<ul>
<li><p>During 40s NGNIX is still alive and serving so readiness probe keeps passing which means any packet entered in VM until draining Cilium will forward it to NGNIX pod as <code>EndpointSlice</code> is still <code>serving: true</code> for terminating pod. Also we’ve <code>externalTrafficPolicy: Local</code> set which means no internal network hop allowed so the terminating NGNIX Pod stays serving and Cilium uses it as a fallback</p>
</li>
<li><p>Make sure to increase <code>terminationGracePeriodSeconds</code> to sleep + N seconds so you allow enough time for shutdown before <code>SIGKILL</code></p>
</li>
<li><p>All existing connections gracefully closes within 40s sleep duration and no packet lost!</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/44d8d33f-d28a-41d8-8d2d-4871124f319f.png" alt="" style="display:block;margin:0 auto" />

<ul>
<li>New connections gets routed to other nodes running healthy replica of your <code>LoadBalancer</code> Service Pod</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6ac2496a34776c6712e8683d/d7405af8-38e9-474f-bf9c-3506e92322e1.png" alt="" style="display:block;margin:0 auto" />

<p>Once the new Pod is up and Ready, NEG controller will attach the same VM to NEGs again and new traffic starts coming.</p>
]]></content:encoded></item></channel></rss>