<?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[The SRE Dispatch]]></title><description><![CDATA[Real-world Kubernetes, SRE, multi-cloud, and DevOps engineering. No fluff — just production experience from someone who manages it daily.]]></description><link>https://prateeksrivastav598.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6a86db1ab9bd691c1eb6d3c0/99234821-1313-495e-8f52-cfee20085638.png</url><title>The SRE Dispatch</title><link>https://prateeksrivastav598.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 14 Sep 2026 11:06:04 GMT</lastBuildDate><atom:link href="https://prateeksrivastav598.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[GCP Is Running Out of N2 Machines in us-central1 — And It's Silently Breaking Production Clusters]]></title><description><![CDATA[Engineers running workloads on Google Cloud Platform's us-central1 region are encountering a growing problem: GCP cannot provision new n2 VMs on demand. The autoscaler requests the machines. GCP says ]]></description><link>https://prateeksrivastav598.hashnode.dev/gcp-is-running-out-of-n2-machines-in-us-central1-and-it-s-silently-breaking-production-clusters</link><guid isPermaLink="true">https://prateeksrivastav598.hashnode.dev/gcp-is-running-out-of-n2-machines-in-us-central1-and-it-s-silently-breaking-production-clusters</guid><dc:creator><![CDATA[Prateek Srivastava]]></dc:creator><pubDate>Thu, 27 Aug 2026 17:31:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/0db4b7f0-4cae-4924-8414-aea49abd158a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Engineers running workloads on Google Cloud Platform's us-central1 region are encountering a growing problem: GCP cannot provision new n2 VMs on demand. The autoscaler requests the machines. GCP says no. Your pods stay Pending. And the GCP status dashboard sits on green the entire time.</p>
<p>Google officially defines this error as occurring when "<em>the zone does not have enough resources available to fulfill the request"</em> — distinguishing it from quota limits, which are a separate class of problem. The error, when you eventually find it buried in GKE cluster-level logs, looks like this:</p>
<blockquote>
<p><code>Node scale up in zones us-central1-f associated with this pod failed:</code><br /><code>GCE out of resources. Pod is at risk of not being scheduled.</code></p>
</blockquote>
<p>The issue has been documented across Google's own developer forums since April 2026, with fresh reports appearing through August. According to community threads, it has affected n1, n2, and e2 instance types across all availability zones in us-central1 — zones a, b, c, and f — making the standard "try a different zone" advice ineffective when the shortage is regional.</p>
<hr />
<p><strong>What Engineers Are Reporting on Google's Own Forums The reports started quietly in spring and have grown louder through summer.</strong></p>
<blockquote>
<p>"For many years I've been deploying Compute Engine VMs to us-central-1 region but for the past couple days I've constantly received error ZONE_RESOURCE_POOL_EXHAUSTED."</p>
<p>— Kevin_Koehler · April 13, 2026 · Google Developer Community</p>
</blockquote>
<blockquote>
<p>"Assumed it was a temporary resource shortage but it's been happening consistently for the past week, which has been very frustrating."</p>
<p>— nju · May 18, 2026 · Google Developer Community</p>
</blockquote>
<blockquote>
<p>"I tried zones a, b, c, and f. Same issue. I tried e2, n1, n2. Same issue... I guess GCP doesn't want my money anymore 🤷"</p>
<p>— standev · August 13, 2026 · Google Developer Community</p>
</blockquote>
<p><code>⚠️ No Official Response. As of the time of writing, no Google employee has responded to these forum threads, and no incident has been posted to the GCP Status Dashboard.</code></p>
<hr />
<p><strong>The Failure Mode That Looks Like Slowness</strong></p>
<p>What makes this particularly dangerous for production systems is how the failure presents itself. When GCP cannot provision a requested machine type, it does not return an error to your application. The GKE cluster autoscaler keeps retrying silently. Your worker pods stay in Pending state. Your job scheduler marks tasks as still running. Your monitoring dashboards show activity. Nothing appears broken.</p>
<p>The only place the truth surfaces is in GKE cluster-level logs — not in your application logs, not in your job scheduler UI. Most engineers only look there when something is visibly broken, which by then is hours later.</p>
<p>In distributed batch workloads on GKE, a common pattern is a lightweight driver pod that coordinates the job and schedules work across executor (worker) pods that do the actual computation. When this capacity issue strikes, the driver pod starts successfully — it's small and fits on an existing node. The executor pods never arrive.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/c78483e5-ca69-4aae-b7a3-d2888f50d93f.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p>"The driver node got created around 19:30 UTC but the executors were allocated only around 00:30 UTC — 5 hours later. This is the case with all the tasks."</p>
<p>— Platform engineer's documented incident report</p>
</blockquote>
<hr />
<p><strong>Which Machine Types Are Affected</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/fca712c5-29cf-4703-9c00-29a4713dbd68.png" alt="" style="display:block;margin:0 auto" />

<hr />
<p><strong>Three Actions You Can Take Today</strong></p>
<ul>
<li><strong>Stop autoscaling from zero on SLA-critical node pools</strong><br />When your minimum node count is zero, a capacity crunch becomes an indefinite stall. Raising the minimum floor means your workloads always have somewhere to land.</li>
</ul>
<pre><code class="language-javascript"># Terraform — raise minimum node count

# Before — zero floor, entirely dependent on autoscaler
min_node_count = 0 
max_node_count = 10

# After — warm baseline; autoscaler supplements from here
min_node_count = 4 
max_node_count = 10 
</code></pre>
<p>Always commit this through your IaC tooling. A manual GCP Console change will be silently overwritten on the next <code>apply</code>.</p>
<ul>
<li><strong>Try a different machine type</strong><br />Google's official troubleshooting documentation explicitly lists <em>"selecting a different machine series or type"</em> as a recommended workaround. Some teams have had better provisioning success with <code>n2d</code> compared to <code>n2</code>.</li>
</ul>
<pre><code class="language-javascript"># gcloud — update node pool machine type

gcloud beta container node-pools update YOUR-NODEPOOL-NAME \
  --project      YOUR-PROJECT-ID \
  --cluster      YOUR-CLUSTER-NAME \
  --region       us-central1 \
  --machine-type n2d-highmem-16
</code></pre>
<p>Plan for ~30 minutes of node pool downtime. Validate on a non-production cluster first.</p>
<ul>
<li><strong>Alert on pod pending time — not just job failure</strong><br />This failure mode presents as slowness, not an error. Set a Kubernetes-level alert on pod pending duration.</li>
</ul>
<pre><code class="language-plaintext"># kubectl — find pods stuck in Pending

# List all Pending pods across namespaces
kubectl get pods -A --field-selector=status.phase=Pending

# Inspect a specific pod — look in Events for the root cause
kubectl describe pod &lt;pod-name&gt; -n &lt;namespace&gt;
# GCE out of resources  →  capacity problem (this article)
# Insufficient cpu/memory  →  resource request too large
</code></pre>
<ul>
<li><p><strong>The Long-Term Answer: Migrate to C4</strong><br />The C4 machine series — powered by Intel Emerald Rapids processors and Google's Titanium offload chips — is Google's current-generation compute offering, and no documented community reports of <code>ZONE_RESOURCE_POOL_EXHAUSTED</code> for C4 have been found as of August 2026.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/d0a64e2f-4b8f-4fb0-885c-832592a8d491.png" alt="" style="display:block;margin:0 auto" /></li>
</ul>
<blockquote>
<p>💡 Migration approach: Create a new C4 node pool alongside your existing n2 pool, validate your workloads, then drain and delete the old one. This avoids any single-pool downtime and lets you roll back cleanly.</p>
</blockquote>
<hr />
<p><strong>Key Takeaways</strong></p>
<ul>
<li><p><strong>The GCP status page is not your monitoring</strong> <em>ZONE_RESOURCE_POOL_EXHAUSTED does not appear as a GCP incident. Monitor your cluster directly — pod pending duration is a more reliable early-warning signal.</em></p>
</li>
<li><p><strong>Minimum node count zero is a risk for production batch</strong><br /><em>For jobs with SLAs, maintain a warm baseline that can absorb workloads without needing GCP to provision new hardware immediately.</em></p>
</li>
<li><p><strong>Multi-zone helps — regional shortages need a different response</strong><br /><em>When the shortage spans all zones, machine type diversity or capacity reservations are the only effective responses.</em></p>
</li>
<li><p><strong>Know your machine type fallback before you need it</strong><br /><em>Have a tested alternative ready in your runbook. The wrong time to figure it out is during a production incident at 3 AM.</em></p>
</li>
</ul>
<p>The frustrating reality of <code>ZONE_RESOURCE_POOL_EXHAUSTED</code> is that it sits in a grey zone: widespread enough to affect multiple teams across months, specific enough that Google doesn't surface it as a regional incident. The community has been documenting it since April. The status page has stayed green throughout.</p>
<p>If you're running SLA-critical workloads in us-central1 on n2 — especially with a minimum node count of zero — the fixes above are worth reviewing this week, not after the next unexplained multi-hour delay.</p>
<hr />
<p><strong>Sources &amp; Further Reading</strong></p>
<ol>
<li><p><a href="https://discuss.google.dev/t/sudden-vm-unavailability-in-us-central-1/349095">Sudden VM Unavailability in us-central-1 — Google Developer Community</a></p>
</li>
<li><p><a href="https://discuss.google.dev/t/shortage-of-compute-engine-resource-in-us-central-1/97319">Shortage of Compute Engine Resource in us-central-1 — Google Developer Forums</a></p>
</li>
<li><p><a href="https://docs.cloud.google.com/compute/docs/troubleshooting/troubleshooting-resource-availability">Troubleshooting Resource Availability Errors — Google Cloud Docs</a></p>
</li>
<li><p><a href="https://cloud.google.com/blog/products/compute/a-closer-look-at-compute-engine-c4-and-n4-machine-series/">C4 Machine Series Deep Dive — Google Cloud Blog</a></p>
</li>
<li><p><a href="https://docs.cloud.google.com/kubernetes-engine/docs/troubleshooting/troubleshoot-node-pools">Troubleshoot GKE Standard Node Pools — Google Cloud Docs</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Claude Went Down Today. And It Says More About AI Than You Might Think !!!!]]></title><description><![CDATA[On August 24, 2026, Anthropic’s Claude experienced a service disruption that affected multiple models. Anthropic acknowledged elevated errors and said it had identified the cause and was working on a ]]></description><link>https://prateeksrivastav598.hashnode.dev/claude-went-down-today-and-it-says-more-about-ai-than-you-might-think</link><guid isPermaLink="true">https://prateeksrivastav598.hashnode.dev/claude-went-down-today-and-it-says-more-about-ai-than-you-might-think</guid><dc:creator><![CDATA[Prateek Srivastava]]></dc:creator><pubDate>Mon, 24 Aug 2026 08:56:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/b7ceca2d-a613-4ad7-8e54-eb7eeaaf1191.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>On <strong>August 24, 2026</strong>, Anthropic’s Claude experienced a service disruption that affected multiple models. Anthropic acknowledged elevated errors and said it had identified the cause and was working on a fix.</p>
<p>The interesting part isn’t just that Claude had an outage.</p>
<p>The interesting part is <strong>how much this kind of outage matters now.</strong></p>
<p>A few years ago, an AI chatbot going down would have been annoying.</p>
<p>Today, it can stop someone from writing code, analyzing a document, finishing a project, or even running part of a business.</p>
<p>And that’s a pretty big change.</p>
<h3>So, What Actually Happened?</h3>
<p>Reports started appearing Monday as users ran into problems with Claude.</p>
<p>Anthropic’s own incident updates described the problem as <strong>“elevated errors” affecting multiple models</strong>. The affected services included models such as Claude Mythos 5, Fable 5, Opus 5 and other Claude models. Anthropic said it had identified the cause and was working on a fix.</p>
<p>Users were also reporting problems with Claude Code and other parts of Anthropic’s ecosystem.</p>
<p>That’s important because Claude isn’t just a chatbot anymore.</p>
<p>For many developers, <strong>Claude Code is part of the development workflow itself.</strong></p>
<p>When that stops working, it’s not the same as losing access to a website for a few minutes.</p>
<p>It’s closer to a developer losing one of their tools in the middle of a workday.</p>
<h3>And Then I Started Thinking About Something Else</h3>
<p>We’ve become incredibly comfortable with AI.</p>
<p>Maybe too comfortable.</p>
<p>Think about your own workflow.</p>
<p>You might open Claude to write something.</p>
<p>Then use it to review code.</p>
<p>Then ask it to explain an error.</p>
<p>Then use it to summarize a document.</p>
<p>Then ask it to generate another piece of code.</p>
<p>At some point, you stop thinking of AI as a tool you occasionally use.</p>
<p>It becomes part of the workflow.</p>
<p>And that’s where outages become interesting.</p>
<p>Because when Claude disappears, even temporarily, you suddenly realize how much of your work has quietly moved onto someone else’s infrastructure.</p>
<h3>AI Is Becoming Infrastructure</h3>
<p>This is probably the bigger story here.</p>
<p>We’re used to thinking about AI in terms of intelligence.</p>
<p>Which model is smarter?</p>
<p>Which one writes better code?</p>
<p>Which one reasons better?</p>
<p>Which one gives better answers?</p>
<p>But as AI becomes embedded in products and businesses, another question becomes just as important:</p>
<p><strong>Can I depend on it being there when I need it?</strong></p>
<p>That’s a very different question.</p>
<p>A model can be incredibly intelligent and still be a terrible dependency if your application completely breaks when the model has an outage.</p>
<p>This is something the cloud industry learned years ago.</p>
<p>And AI developers are now learning the same lesson.</p>
<h3>One AI Provider Shouldn’t Be Your Entire Architecture</h3>
<p>If your application depends entirely on one AI provider, an outage can become your outage.</p>
<p>That’s a dangerous position to be in.</p>
<p>A more resilient setup might look something like this:</p>
<p><strong>Primary model → fallback model → cached response → graceful degradation</strong></p>
<p>If Claude works, great.</p>
<p>If Claude doesn’t work, the application can switch to another model.</p>
<p>If neither is available, maybe the user can still continue using the non-AI parts of the product.</p>
<p>It doesn’t have to be complicated.</p>
<p>But you have to think about it <strong>before</strong> the outage happens.</p>
<h3>This Is Especially Important for AI Coding</h3>
<p>Claude’s developer tools make this even more interesting.</p>
<p>A growing number of developers are using AI not simply to autocomplete a line of code, but to work through entire tasks.</p>
<p>Give the agent a feature.</p>
<p>Ask it to inspect the repository.</p>
<p>Let it modify files.</p>
<p>Run tests.</p>
<p>Fix errors.</p>
<p>Repeat.</p>
<p>That’s a completely different relationship with an AI model.</p>
<p>The AI isn’t just helping you type.</p>
<p>It’s participating in the development process.</p>
<p>So when the service goes down, the impact isn’t necessarily:</p>
<blockquote>
<p><em>“I can’t ask my chatbot a question.”</em></p>
</blockquote>
<p>It can be:</p>
<blockquote>
<p><em>“My development workflow just stopped.”</em></p>
</blockquote>
<p>That’s a much bigger deal.</p>
<h3>And This Isn’t Happening in Isolation</h3>
<p>Anthropic’s own status history shows several incidents involving Claude models and services during August.</p>
<p>The company recorded issues affecting multiple models on August 12, August 13, August 17, August 18, August 19 and August 20, along with broader service disruptions affecting Claude services on other dates.</p>
<p>That doesn’t automatically mean Claude is unreliable.</p>
<p>Large-scale infrastructure is difficult to operate, especially when demand and system complexity keep increasing.</p>
<p>But it does highlight something that every serious AI user should start thinking about:</p>
<p>R<strong>eliability is becoming a feature. Not an afterthought.</strong></p>
<h3>The “Best Model” Might Not Be the Best Model</h3>
<p>This is where I think the AI conversation needs to evolve.</p>
<p>We spend an enormous amount of time comparing models.</p>
<p>Model A beats Model B on a benchmark.</p>
<p>Model B writes better code.</p>
<p>Model C has better reasoning.</p>
<p>But imagine two models:</p>
<p><strong>Model A:</strong> slightly better, but occasionally unavailable.</p>
<p><strong>Model B:</strong> slightly worse, but your application can automatically fail over to it.</p>
<p>For a production application, Model B might actually be the better choice.</p>
<p>Because users don’t care about your benchmark score when your application returns an error.</p>
<p>They care whether it works.</p>
<h3>What Should Developers Do?</h3>
<p>If you’re building something serious with AI, today’s outage is a good reminder to check a few things.</p>
<p>Do you have a fallback model?</p>
<p>Do you retry failed requests properly?</p>
<p>Are you monitoring API errors?</p>
<p>Can your application continue working without AI for a while?</p>
<p>Are you storing useful results so you don’t have to regenerate everything?</p>
<p>And perhaps most importantly:</p>
<blockquote>
<p><strong>Do you know what happens when your AI provider goes offline?</strong></p>
</blockquote>
<p><em>If the answer is “everything breaks,” that’s something worth fixing.</em></p>
<h3>There’s a Bigger Shift Happening</h3>
<p>AI companies used to compete primarily on model capability.</p>
<p>Now they’re increasingly competing on something that looks much more like traditional infrastructure:</p>
<ul>
<li><p>uptime</p>
</li>
<li><p>latency</p>
</li>
<li><p>reliability</p>
</li>
<li><p>capacity</p>
</li>
<li><p>enterprise controls</p>
</li>
<li><p>predictable APIs</p>
</li>
<li><p>developer experience</p>
</li>
</ul>
<p>That’s actually a sign of maturity.</p>
<p>When people start complaining about uptime instead of asking whether the technology is useful, it means the technology has become important enough to depend on.</p>
<p>And Claude is definitely at that stage.</p>
<h3>So, Is Claude “Down”?</h3>
<img src="https://cdn-images-1.medium.com/max/1600/1*yqeEiMKnceRAxKMOgc7zwQ.png" alt="" style="display:block;margin:0 auto" />

<p>At the time of writing, the situation is better described as a <strong>service disruption/elevated-error incident earlier today</strong>, rather than Claude being universally offline.</p>
<p>Anthropic’s current status page shows its major Claude services as operational, although reports earlier in the day documented significant problems.</p>
<p>So if Claude is working for you now, that’s consistent with the latest status information.</p>
<p>But the outage itself is still worth paying attention to.</p>
<p>Because the real story isn’t that Claude had a bad day.</p>
<p>The real story is that <strong>AI has become important enough for its downtime to become a serious technology story.</strong></p>
<h3>The Takeaway</h3>
<p>I’m not particularly interested in arguing that Claude is better or worse because of today’s outage.</p>
<p>Every major technology platform will eventually have failures.</p>
<p>The lesson is somewhere else.</p>
<p>If you’re a casual AI user, an outage is an inconvenience.</p>
<p>If you’re a developer, it’s an architecture problem.</p>
<p>And if you’re a business that has built critical workflows around AI, it’s a risk-management problem.</p>
<p>AI isn’t just a chatbot anymore.</p>
<p>It’s becoming part of the infrastructure we build on.</p>
<p>And once something becomes infrastructure, <strong>reliability matters just as much as intelligence.</strong></p>
<p>That’s probably the most important thing today’s Claude outage reminds us.</p>
<h3>Sources</h3>
<ol>
<li><p><strong>Anthropic — Claude Status:</strong> Official incident history and current service status. <a href="https://status.claude.com/?utm_source=chatgpt.com">Claude Status</a></p>
</li>
<li><p><strong>Android Authority — Claude outage report:</strong> Coverage of today’s August 24 disruption and Anthropic’s response. <a href="https://www.androidauthority.com/claude-outage-august-24-3702012/?utm_source=chatgpt.com">Android Authority report</a></p>
</li>
<li><p><strong>Notebookcheck — Claude outage:</strong> Reporting on elevated errors affecting multiple Claude models and Claude Code. <a href="https://www.notebookcheck.net/Claude-faces-another-outage-as-errors-hit-multiple-models.1376666.0.html?utm_source=chatgpt.com">Notebookcheck report</a></p>
</li>
<li><p><strong>Economic Times — Claude disruption:</strong> Reporting on user complaints and disruption across Claude, Claude Code and related services. <a href="https://m.economictimes.com/news/new-updates/claude-down-today-users-report-issues-as-downdetector-shows-big-spike-heres-latest-update/articleshow/133456017.cms?utm_source=chatgpt.com">Economic Times report</a></p>
</li>
</ol>
<blockquote>
<p>If you’re dealing with something like this at work — or you have a war story of your own — I’m on <a href="https://www.linkedin.com/in/prateeksrivastava123/">LinkedIn</a> and I actually respond.</p>
</blockquote>
<blockquote>
<p>I publish one production incident breakdown every week. Subscribe free if you want it directly in your inbox — no tutorials, no fluff:</p>
</blockquote>
<blockquote>
<p>Let’s Stay in Touch 🪂 Connect with us on: <a href="https://www.linkedin.com/in/prateeksrivastava123/">LinkedIn</a>, <a href="https://www.instagram.com/prateek1088/">Instagram</a>, <a href="https://medium.com/@prateeksrivastav598">Medium</a></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[A Windows Service is Down. Now What?]]></title><description><![CDATA[It doesn't matter if it's SQL Server, IIS, a background agent, or a custom app — when a Windows service goes down, the investigation is always the same five moves. Learn the pattern once, apply it to ]]></description><link>https://prateeksrivastav598.hashnode.dev/a-windows-service-is-down-now-what</link><guid isPermaLink="true">https://prateeksrivastav598.hashnode.dev/a-windows-service-is-down-now-what</guid><category><![CDATA[SRE]]></category><category><![CDATA[Powershell]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Microsoft]]></category><category><![CDATA[incident response]]></category><dc:creator><![CDATA[Prateek Srivastava]]></dc:creator><pubDate>Sun, 23 Aug 2026 19:33:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/3b349f6a-9980-4803-9139-dc6754a9b3ea.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<p>It doesn't matter if it's SQL Server, IIS, a background agent, or a custom app — when a Windows service goes down, the investigation is always the same five moves. Learn the pattern once, apply it to anything.</p>
<blockquote>
<p>🚫 <strong>Don't restart first.</strong> Restarting a service without knowing why it stopped can hide a real problem — a failing update, an exhausted host, or an automation script that will stop it again in the next cycle. Spend 5 minutes on the evidence first.</p>
</blockquote>
<hr />
<h2>Step 01 — Confirm Current State</h2>
<p>Your first question isn't "why did it stop?" — it's "is it still stopped?" Monitoring systems have polling intervals; by the time an alert reaches you, the service may have already recovered. Establish ground truth before taking any action.</p>
<pre><code class="language-powershell">Get-Service "ServiceName1", "ServiceName2" |
    Select-Object Name, Status, StartType
</code></pre>
<p>Two things matter: <strong>Status</strong> (is it actually down right now?) and <strong>StartType</strong> (is it still set to Automatic? OS updates occasionally reset this).</p>
<blockquote>
<p>🔵 <strong>SQL Server example:</strong></p>
<pre><code class="language-powershell">Get-Service MSSQLSERVER, SQLSERVERAGENT, MsDtsServer130 |
    Select-Object Name, Status, StartType
</code></pre>
<p>All three came back <code>Running / Automatic</code> — already self-recovered before anyone looked. This told us the alert was valid but not actionable, and shifted focus to understanding root cause.</p>
</blockquote>
<hr />
<h2>Step 02 — Map Service Transitions with Event ID 7036</h2>
<p>Windows logs every service state change — stopped, running, paused — as <strong>Event ID 7036</strong> in the System log. Pull the last 20 transitions and sort them chronologically. This gives you the precise stop-and-start sequence and exact timestamps.</p>
<pre><code class="language-powershell">Get-WinEvent -FilterHashtable @{
    LogName='System'; Id=7036
} | Where-Object {
    $_.Message -match 'Your Service Name'
} | Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20
</code></pre>
<p>Read the output <strong>bottom-up</strong> (oldest first). Look for the last time it went from <code>running → stopped</code>, and whether it came back on its own or stayed down. Multiple stop/start cycles in quick succession often mean a crash-and-restart loop.</p>
<blockquote>
<p>🔵 <strong>SQL Server example:</strong></p>
<pre><code class="language-powershell">Get-WinEvent -FilterHashtable @{LogName='System';Id=7036} |
    Where-Object {$_.Message -match
      'SQL Server Agent \(MSSQLSERVER\)|SQL Server \(MSSQLSERVER\)|SQL Server Integration Services 13.0'} |
    Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20
</code></pre>
<p>The output showed all three services stopped at 10:20 AM IST and returned to running at 10:27 AM IST — a 6-minute outage that overlapped exactly with the alert timestamp.</p>
</blockquote>
<hr />
<h2>Step 03 — Look for System-Level Triggers</h2>
<p>A service rarely stops in isolation. Before blaming the application, check whether the <strong>host itself</strong> caused the stop. Four event IDs tell this story:</p>
<table>
<thead>
<tr>
<th>Event ID</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>1074</td>
<td>Intentional shutdown/restart — includes initiating process (TrustedInstaller, shutdown.exe, Ansible), user, and reason code</td>
</tr>
<tr>
<td>6005</td>
<td>Event log service started = OS finished booting. Your "server is up" timestamp</td>
</tr>
<tr>
<td>6006</td>
<td>Event log service stopped = OS going down. Pair with 6005 to measure reboot windows</td>
</tr>
<tr>
<td>6008</td>
<td>Unexpected/dirty shutdown — previous shutdown was unclean. A crash or power loss leaves this</td>
</tr>
</tbody></table>
<pre><code class="language-powershell">Get-WinEvent -FilterHashtable @{
    LogName='System'; Id=1074,6005,6006,6008
} | Select-Object TimeCreated, Id, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# For recent 1074s with full detail:
Get-WinEvent -FilterHashtable @{LogName='System';Id=1074} |
    Where-Object {$_.TimeCreated -gt (Get-Date).AddHours(-24)} |
    Format-List TimeCreated, Message
</code></pre>
<blockquote>
<p>🔵 <strong>SQL Server example:</strong></p>
<p>Event 1074 revealed two reboots in the same maintenance window. The first was triggered by <code>o9ansibleuser</code> via Ansible. The second was chained by <code>TrustedInstaller.exe</code> with reason "Operating System: Upgrade (Planned)" — Windows Update had quietly queued a second reboot on top of the Ansible reboot. Without checking Event 1074, this would have looked like an unexplained outage.</p>
</blockquote>
<blockquote>
<p>💡 If you find a <strong>6008 (dirty shutdown)</strong> near your service stop, the host itself crashed — investigate the host before the service.</p>
</blockquote>
<hr />
<h2>Step 04 — Read the Application's Own Logs</h2>
<p>Windows Event logs tell you <strong>when</strong> the service stopped. The application's own logs tell you <strong>why</strong>. Every serious Windows service writes its own log — find it and read the entries immediately before the service stopped.</p>
<pre><code class="language-powershell"># Common log locations:
# SQL Server → C:\Program Files\Microsoft SQL Server\MSSQL{ver}.{instance}\MSSQL\Log\ERRORLOG
# IIS        → C:\inetpub\logs\LogFiles\W3SVC1\

# For services that write to Windows Application log:
Get-WinEvent -FilterHashtable @{LogName='Application';Level=1,2} |
    Where-Object {$_.ProviderName -match 'YourService'} |
    Select-Object TimeCreated, Message |
    Sort-Object TimeCreated -Descending |
    Select-Object -First 20
</code></pre>
<p>You're looking for one of three signatures:</p>
<ul>
<li><p><strong>Error/exception before stop</strong> → crash</p>
</li>
<li><p><strong>Clean shutdown message</strong> → planned stop</p>
</li>
<li><p><strong>Nothing unusual</strong> → external trigger (reboot killed the process)</p>
</li>
</ul>
<blockquote>
<p>🔵 <strong>SQL Server example — ERRORLOG:</strong></p>
<p>SQL Server rotates its log on every restart. Find the file that covers your outage window by <code>LastWriteTime</code>:</p>
<pre><code class="language-powershell"># Find the right log file
Get-ChildItem "C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\ERRORLOG*" |
    Select-Object Name, LastWriteTime, Length |
    Sort-Object LastWriteTime

# Read the last 50 lines of the relevant file
Get-Content "...\MSSQL\Log\ERRORLOG.4" | Select-Object -Last 50
</code></pre>
<p>The critical line at the tail of our log:</p>
<pre><code class="language-plaintext">SQL Server is terminating in response to a 'stop' request from Service Control Manager.
</code></pre>
<p>That's a <strong>clean stop</strong> — no crash, no error. Case closed on fault; focus shifts to who stopped it and why.</p>
</blockquote>
<blockquote>
<p>⚠️ SQL ERRORLOG uses <strong>local server time</strong>, not UTC. Convert your alert timestamp before searching.</p>
</blockquote>
<hr />
<h2>Step 05 — Classify the Stop, Then Decide</h2>
<p>By now you have enough to classify into one of three categories:</p>
<h3>🔴 Crash</h3>
<ul>
<li><p>Exceptions/errors in app log immediately before stop</p>
</li>
<li><p>Event 6008 (dirty shutdown) present</p>
</li>
<li><p>Dump files in the app's log directory</p>
</li>
<li><p>No clean stop message</p>
</li>
</ul>
<p><strong>Response:</strong> Don't just restart — find the root cause first. Check memory (<code>Get-Process</code>), disk (<code>Get-PSDrive</code>), dump files. Restarting a crashing service without fixing the cause fails again.</p>
<h3>🟢 Clean Stop</h3>
<ul>
<li><p>"Stop request from SCM" in app log</p>
</li>
<li><p>Config/agent disabled just before stop</p>
</li>
<li><p>No preceding errors — manual or scripted</p>
</li>
</ul>
<p><strong>Response:</strong> Safe to restart, but find out who stopped it. Was it automation? Is it expected to auto-restart?</p>
<h3>🟡 External Trigger</h3>
<ul>
<li><p>Event 1074 near the stop time</p>
</li>
<li><p>6005/6006 reboot pair visible</p>
</li>
<li><p>Ansible, Windows Update, manual reboot</p>
</li>
</ul>
<p><strong>Response:</strong> The service is a passenger — the host was the cause. Verify the reboot was planned, confirm all services are back, close the ticket.</p>
<hr />
<h2>Going Further: From Reactive to Proactive</h2>
<p><strong>🔕 Maintenance Windows</strong> — Before any planned reboot, open a monitoring suppression. Automate it as a pre-task in your Ansible playbook, not a manual step someone might forget.</p>
<p><strong>📋 Parse App Logs Continuously</strong> — Ship application logs to a central store. Alert on <code>terminating</code>, <code>severity 20+</code>, <code>exception</code> before a service hits the floor.</p>
<p><strong>🧠 Watch Memory Before It Matters</strong> — Many crashes are preceded by hours of memory pressure. A service paging to disk for 4 hours before crashing gave you warning you didn't act on.</p>
<p><strong>🤖 Tag Automation in Monitoring</strong> — Have Ansible write a comment to your alert system before rebooting. A ticket that says "Ansible reboot — expected" closes in seconds. One without context takes 15 minutes.</p>
<p><strong>📅 Track TrustedInstaller Reboots</strong> — Windows Update's chained reboots are invisible unless you watch Event 1074. Add a post-patch check that logs TrustedInstaller-initiated reboots to your CMDB.</p>
<p><strong>📈 Trend Restart Frequency</strong> — A service that restarts once a quarter is healthy. One that restarts three times in a week has a problem. Track restart counts over time — the trend tells you before a crash does.</p>
<hr />
<h2>Quick Reference: The Diagnostic Playbook</h2>
<p>Save this to your runbook.</p>
<pre><code class="language-powershell"># 1 — Current state
Get-Service "ServiceA","ServiceB" | Select-Object Name,Status,StartType

# 2 — Service transitions
Get-WinEvent -FilterHashtable @{LogName='System';Id=7036} |
    Where-Object {$_.Message -match 'YourServiceName'} |
    Select-Object TimeCreated,Message | Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# 3 — Shutdown events
Get-WinEvent -FilterHashtable @{LogName='System';Id=1074,6005,6006,6008} |
    Select-Object TimeCreated,Id,Message | Sort-Object TimeCreated -Descending |
    Select-Object -First 20

# 4 — App event log (errors/criticals)
Get-WinEvent -FilterHashtable @{LogName='Application';Level=1,2} |
    Where-Object {$_.ProviderName -match 'YourService'} |
    Select-Object TimeCreated,Message | Select-Object -First 20

# 5 — Server uptime
(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime

# SQL Server bonus — find the right ERRORLOG
Get-ChildItem "C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log\ERRORLOG*" |
    Select-Object Name,LastWriteTime | Sort-Object LastWriteTime
</code></pre>
<blockquote>
<p>💡 The three root causes — crash, clean stop, external trigger — each have a different recovery path. <strong>Classify before you act</strong>, and you'll never restart a service into the same problem twice.</p>
</blockquote>
<hr />
<p>If you're dealing with something like this at work — or you have a war story of your own — I'm on <a href="https://www.linkedin.com/in/prateeksrivastava123/">LinkedIn</a> and I actually respond.</p>
<p>I publish one production incident breakdown every week — real commands, real dead ends, real fix. <strong>Follow on</strong> <a href="http://prateeksrivastav598.medium.com"><strong>Medium</strong></a> if you want the next one in your feed: <a href="https://prateeksrivastav598.medium.com">prateeksrivastav598.medium.com</a></p>
]]></content:encoded></item><item><title><![CDATA[I Managed Kubernetes Across AWS, Azure, and GCP Simultaneously — Here's What Nobody Tells You"
]]></title><description><![CDATA[The day the same Helm chart behaved differently on three clouds in the same hour was the day I stopped trusting "cloud-agnostic" as a real thing.
Nobody plans to manage Kubernetes on three clouds at t]]></description><link>https://prateeksrivastav598.hashnode.dev/i-managed-kubernetes-across-aws-azure-and-gcp-simultaneously-here-s-what-nobody-tells-you</link><guid isPermaLink="true">https://prateeksrivastav598.hashnode.dev/i-managed-kubernetes-across-aws-azure-and-gcp-simultaneously-here-s-what-nobody-tells-you</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Devops]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Azure]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[multicloud]]></category><dc:creator><![CDATA[Prateek Srivastava]]></dc:creator><pubDate>Fri, 21 Aug 2026 18:59:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/5728978c-7f11-40c2-affc-785978fcf55a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The day the same Helm chart behaved differently on three clouds in the same hour was the day I stopped trusting "cloud-agnostic" as a real thing.</p>
<p>Nobody plans to manage Kubernetes on three clouds at the same time. It happens gradually — an acquisition brings an Azure footprint, a new business unit commits to GCP, and you already run EKS. Then one morning a page fires and you're staring at three terminal windows, three different cluster behaviours, one very angry incident bridge.</p>
<p>I've spent the better part of two years in exactly that situation. What follows isn't a comparison chart you can find on any vendor blog. It's the stuff I learned the hard way — the silent differences that don't show up until something breaks in production at 2 AM.</p>
<p>{% callout type="warning" %} <strong>The Incident That Started It All</strong> We deployed the same Helm chart — identical values, same image tag — to EKS, AKS, and GKE within the same 20-minute release window. EKS came up healthy. AKS came up healthy. GKE's pods started, ran for about 90 seconds, then began OOMKilling in a loop. Same YAML. Same limits. Three different outcomes. Four hours to find why.</p>
<hr />
<h2>1. Networking: The Biggest Lie — "Pods Are Just Pods"</h2>
<p>This is where most multi-cloud pain originates. Every Kubernetes networking tutorial tells you that pods get their own IPs and can talk to each other. What it doesn't tell you is that <em>where those IPs come from</em> completely changes your blast radius, your subnet planning, your security posture, and the failure modes you'll face at 3 AM.</p>
<h3>EKS: Your pods eat your VPC subnet IPs</h3>
<p>EKS uses the AWS VPC CNI by default. Every pod gets a real, routable IP from your VPC subnet. This sounds great until you have a <code>/24</code> subnet and someone deploys a service with 200 replicas. The error you get isn't "out of IPs" — it's an ENI attachment timeout. The CNI pre-warms ENIs and exhausts capacity before you hit the IP limit.</p>
<p>The harder gotcha: each EC2 instance type has a max ENI count × max IPs per ENI cap. A <code>t3.medium</code> can hold 3 ENIs × 6 IPs = 18 pod IPs max, minus 1 for the node. Run 20 pods per node and you'll see Pending pods on nodes with plenty of CPU and memory — the constraint is invisible to the default scheduler.</p>
<pre><code class="language-bash"># Check ENI and IP capacity on a node
kubectl describe node &lt;node-name&gt; | grep -A5 "Allocatable"

# Check aws-node daemonset for ENI attachment errors
kubectl logs -n kube-system -l k8s-app=aws-node --tail=50 | grep -i "err\|fail\|exhaust"
</code></pre>
<p><strong>Fix:</strong> Enable VPC CNI prefix delegation — one ENI prefix gives you 16 IPs instead of 1.</p>
<h3>AKS: Azure CNI pre-allocates IPs whether you like it or not</h3>
<p>AKS with Azure CNI reserves IPs per node based on <code>--max-pods</code> (default: 30) — even before any pod runs. A 100-node cluster pre-consumes 3,000 VNet IPs. Plan your address space first. If you're IP-constrained, use <strong>Azure CNI Overlay mode</strong>.</p>
<h3>GKE: Clean until you need to peer networks</h3>
<p>GKE uses alias IP ranges, isolated from your main VPC. It's the cleanest story — until you need to peer your GKE VPC with an on-premises network and your pod CIDR overlaps your on-prem range, because you let GKE auto-assign ranges six months ago. <strong>Always explicitly define secondary ranges on GKE.</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>EKS</th>
<th>AKS</th>
<th>GKE</th>
</tr>
</thead>
<tbody><tr>
<td>Pod IP source</td>
<td>VPC subnet (real IPs)</td>
<td>VNet or overlay</td>
<td>Alias IP ranges</td>
</tr>
<tr>
<td>IP exhaustion risk</td>
<td>High — ENI limits</td>
<td>High — pre-allocated</td>
<td>Low — isolated</td>
</tr>
<tr>
<td>Common 3 AM failure</td>
<td>ENI attachment timeout</td>
<td>VNet IP exhaustion</td>
<td>CIDR overlap during peering</td>
</tr>
</tbody></table>
<hr />
<h2>2. IAM + RBAC: Three Identity Models, One Misconfiguration Away from Disaster</h2>
<h3>EKS: The IRSA silent fallback trap</h3>
<p>If your IRSA annotation has a typo, the assume-role call silently fails and the pod falls through to the node's instance profile — often over-permissive. You won't see an error. Verify assumed identity from inside the pod:</p>
<pre><code class="language-bash">kubectl exec -it &lt;pod-name&gt; -- aws sts get-caller-identity
</code></pre>
<h3>AKS: Workload Identity federation is fragile on setup</h3>
<p>Three pieces must align exactly: Managed Identity, federated credential (with the exact OIDC issuer URL — including trailing slashes), and the Kubernetes service account annotation. One mismatch = silent 401.</p>
<h3>GKE: Node rotation breaks implicit identity</h3>
<p>Enabling Workload Identity on a node pool removes the node's default Google service account. Any workload relying on implicit node identity breaks on the next node rotation. Audit before enabling.</p>
<hr />
<h2>3. Memory + cgroups: Why the Same Container OOMKilled on GKE but Not on EKS</h2>
<p>GKE had moved to <strong>cgroup v2</strong> on newer node images. EKS and AKS were still on cgroup v1. Our Java service used JVM ergonomics to auto-detect heap size.</p>
<ul>
<li><p>cgroup v1: JVM reads from <code>/sys/fs/cgroup/memory/memory.limit_in_bytes</code></p>
</li>
<li><p>cgroup v2: JVM reads from <code>/sys/fs/cgroup/memory.max</code></p>
</li>
</ul>
<p>Our old JVM didn't handle cgroup v2 — it read host memory (64GB) instead of the container limit (2GB), allocated an 8GB heap into a 2GB container, and OOMKilled every 90 seconds.</p>
<pre><code class="language-bash"># Check which cgroup version the container sees
kubectl exec -it &lt;pod-name&gt; -- cat /proc/1/cgroup
# cgroup v1: "12:memory:/kubepods/..."
# cgroup v2: single line "0::/"

# Check what heap the JVM allocated
kubectl exec -it &lt;pod-name&gt; -- java -XshowSettings:all -version 2&gt;&amp;1 | grep -i heap
</code></pre>
<p><strong>Fix:</strong> JDK 15+ for native cgroup v2 support. Always explicitly set <code>-Xmx</code> and <code>-Xms</code>. Never trust JVM ergonomics in a container without verifying cgroup version on the target nodes.</p>
<table>
<thead>
<tr>
<th></th>
<th>EKS</th>
<th>AKS</th>
<th>GKE</th>
</tr>
</thead>
<tbody><tr>
<td>Default node OS</td>
<td>Amazon Linux 2023</td>
<td>Ubuntu 22.04 / Azure Linux</td>
<td>Container-Optimized OS</td>
</tr>
<tr>
<td>cgroup version</td>
<td>v2 (AL2023), v1 (AL2)</td>
<td>v2 (Ubuntu 22.04+)</td>
<td>v2 (since mid-2022)</td>
</tr>
</tbody></table>
<hr />
<h2>4. Storage: The AZ-Pinning Trap</h2>
<p>Block storage is AZ-specific on every cloud. Your PVC and its pod must be in the same AZ. When Cluster Autoscaler scales nodes in a different AZ, pods stay Pending — and the on-call engineer stares at CPU/memory graphs seeing nothing wrong.</p>
<pre><code class="language-bash"># The event buried in pod describe that tips you off
kubectl describe pod &lt;pending-pod&gt; | grep "had volume node affinity conflict"
</code></pre>
<p><strong>Fix:</strong> Use <code>volumeBindingMode: WaitForFirstConsumer</code> on all storage classes. This delays PV creation until the pod schedules, guaranteeing same-AZ placement.</p>
<hr />
<h2>5. Load Balancers: Same Service, Three Different Outcomes</h2>
<p>Each cloud's controller uses completely different annotation namespaces:</p>
<pre><code class="language-yaml">annotations:
  # EKS — get NLB instead of legacy Classic ELB
  service.beta.kubernetes.io/aws-load-balancer-type: "external"
  service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"

  # AKS — internal (private) load balancer
  service.beta.kubernetes.io/azure-load-balancer-internal: "true"

  # GKE — completely different namespace for internal LB
  networking.gke.io/load-balancer-type: "Internal"
</code></pre>
<p>We once deployed a chart to GKE with only AWS annotations. GKE ignored them and created a <strong>public</strong> Load Balancer. An internal API was internet-reachable for 40 minutes before SolarWinds monitoring caught it.</p>
<p><strong>Rule:</strong> Validate LB configuration on all three clouds in CI.</p>
<hr />
<h2>6. Autoscaling: Cluster Autoscaler Is Not the Same Everywhere</h2>
<ul>
<li><p><strong>EKS:</strong> Scale-up is 4–8 minutes minimum (ASG → EC2 launch → join → register → schedule)</p>
</li>
<li><p><strong>GKE NAP:</strong> Faster, but creates node pools with unexpected taints — pods without matching tolerations won't schedule even after "scale-up"</p>
</li>
</ul>
<p><strong>The pattern that works:</strong> Use KEDA for pod-level scaling (seconds), Cluster Autoscaler only as a last resort for node-level scale (minutes). Scale pods first, nodes only when necessary.</p>
<hr />
<h2>What I'd Tell Myself Before Starting All Over</h2>
<p>Multi-cloud Kubernetes isn't twice the work — it's about six times the work, because every subtle difference compounds.</p>
<ol>
<li><p><strong>Standardise your observability first.</strong> Same dashboards, same alert expressions, same log structure across all three clouds. Muscle memory beats translation at 2 AM.</p>
</li>
<li><p><strong>Document differences, not just similarities.</strong> Runbooks should say "on EKS check X; on AKS check Y; on GKE check Z."</p>
</li>
<li><p><strong>Test Helm charts on all three before every major release.</strong> 20 minutes of CI is cheaper than one 4-hour incident.</p>
</li>
<li><p><strong>Never trust "cloud-agnostic" on the label.</strong> Especially networking, storage, and identity — they break silently.</p>
</li>
</ol>
<blockquote>
<p>The day you stop being surprised by cloud differences is the day you've actually become a multi-cloud SRE. Everything before that is just surviving the learning curve.</p>
</blockquote>
<hr />
<p><em>🙏 Thank You for Reading!</em></p>
<p><em>Your time and attention mean a lot to us. We greatly appreciate your engagement with our content and would love to hear your thoughts and ideas. Let’s stay connected and continue our journey through the digital world together! 🌐📚💡</em></p>
<p><em>Let’s Stay in Touch 🪂 Connect with us on:</em> <a href="https://www.linkedin.com/in/prateeksrivastava123/"><em>LinkedIn</em></a><em>,</em> <a href="https://www.instagram.com/prateek1088/"><em>Instagram</em></a><em>,</em> <a href="https://prateeksrivastav598.medium.com/"><em>Medium</em></a></p>
]]></content:encoded></item><item><title><![CDATA[Our EKS Node Crashed and Four Auto-Recovery Mechanisms All Failed. Here's Why.]]></title><description><![CDATA[⚡ TL;DR: An EKS worker node running 30+ pods crashed at 08:43 IST on Aug 16. EC2 Auto Scaling didn't act. EKS Node Auto Repair was never enabled. Cluster Autoscaler had no headroom (Min=Max=6). Our me]]></description><link>https://prateeksrivastav598.hashnode.dev/our-eks-node-crashed-and-four-auto-recovery-mechanisms-all-failed-here-s-why</link><guid isPermaLink="true">https://prateeksrivastav598.hashnode.dev/our-eks-node-crashed-and-four-auto-recovery-mechanisms-all-failed-here-s-why</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[EKS]]></category><category><![CDATA[Devops]]></category><category><![CDATA[SRE]]></category><category><![CDATA[AWS]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[incident response]]></category><dc:creator><![CDATA[Prateek Srivastava]]></dc:creator><pubDate>Thu, 20 Aug 2026 11:37:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a86db1ab9bd691c1eb6d3c0/e2aaa4d6-ff60-45d3-b3c8-fb60720d7c36.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>⚡ TL;DR: An EKS worker node running 30+ pods crashed at 08:43 IST on Aug 16. EC2 Auto Scaling didn't act. EKS Node Auto Repair was never enabled. Cluster Autoscaler had no headroom (Min=Max=6). Our memory alert fired 82 seconds after the node was already dead. We fixed it manually at 12:30 IST — 4 hours later. Every fix is one or two CLI commands. Here's the full breakdown.</p>
</blockquote>
<p>When an EKS worker node goes down, Kubernetes is supposed to handle it. That's the whole pitch — self-healing infrastructure. Pods evict, workloads reschedule, the cluster heals itself.</p>
<p>In a recent incident, a node running 30+ pods crashed at 08:43 IST. None of the four auto-recovery mechanisms we had in place did anything. The node sat NotReady for almost 4 hours. We discovered it 82 seconds after it died — from a memory alert that fired when the node was already gone — and fixed it manually at 12:30 IST.</p>
<p>The interesting part wasn't that the node crashed. It was that four different layers of protection failed for four completely different reasons.</p>
<hr />
<p>Here's exactly what failed and why.</p>
<p>The Node That Looked Healthy Until It Didn't</p>
<p>ip-10-<em>-</em>-*.ec2.internal had been running since Jun 28. From Kubernetes' perspective, it was Ready. CPU requests at ~97%. Memory requests at ~69%. Nothing alarming.</p>
<p>The actual picture was very different:</p>
<pre><code class="language-yaml">Allocated resources:
  Resource    Requests       Limits
  cpu         ~97%           ~545%
  memory      ~69%           ~358%
</code></pre>
<p>358% memory limit overcommit. Kubernetes scheduled 37 pods there because requests showed 69% — but if those pods pushed toward their limits, the node had no chance. The requests were lies; the limits were the truth. And the truth said this node was 3.5x overloaded.</p>
<p>Underneath the Ready status, the containerd runtime had been in a degraded state since Jul 20, when the OOM killer had hard-killed a MongoDB process. The kernel had logged two containerd-shim deadlocks (Jul 1 and Jul 29) that the node had somehow absorbed. Neither showed up anywhere in monitoring. The control plane saw nothing wrong.</p>
<p>On Aug 16 at 08:22 IST, a service responsible for processing audit events started leaking memory. ELK showed node memory at 81.6% at 08:22:57 IST. By 08:43 IST the service had grown from 2.0GB to 6.2GB — a 4.2GB spike in 21 minutes — pushing the node from ~81% to ~96%.</p>
<p>The memory pressure triggered a third containerd-shim deadlock on the already-corrupted runtime. This time it was fatal. At 08:43:22 IST, SSM lost contact. Kubelet posted its last heartbeat. At 08:45:10, the node went NotReady.</p>
<p>Now watch how every auto-recovery mechanism missed it.</p>
<hr />
<p>Failure #1 — EC2 Auto Scaling Health Check</p>
<p>The ASG protecting this nodegroup was configured with EC2-level health checks:</p>
<pre><code class="language-yaml">HealthCheckType: EC2 Min: 6 | Max: 6 | Desired: 6
</code></pre>
<p>EC2 health checks have exactly one question: is the VM powered on?</p>
<pre><code class="language-bash">aws ec2 describe-instance-status \
  --instance-ids &lt;id&gt; --region &lt;region&gt; \
  --query 'InstanceStatuses[].[InstanceState.Name,SystemStatus.Status,InstanceStatus.Status]' \
  --output table

+---------+------+------+ 
| running| ok | ok | 
+---------+------+------+
</code></pre>
<p>The instance was running. System status: ok. Instance status: ok. The AWS hypervisor was satisfied. The deadlock inside containerd was completely invisible at the hypervisor layer — the kernel was alive, the VM was up, the NIC was responding to health probes.</p>
<p>EC2 health check never triggered. No replacement instance was launched.</p>
<p>The lesson: EC2 health checks only detect hardware failure or VM termination. They cannot detect OS-level hangs, kubelet death, containerd deadlocks, or any software failure that doesn't take down the underlying VM. For Kubernetes node health, EC2 checks are nearly useless.</p>
<p>Failure #2 — EKS Node Auto Repair</p>
<p>EKS Node Auto Repair is designed exactly for this scenario. When a node stays NotReady for a defined period, it automatically cordons, drains, and replaces it. No manual intervention needed.</p>
<pre><code class="language-bash">aws eks describe-nodegroup \
  --cluster-name &lt;name&gt; \
  --nodegroup-name &lt;nodegroup_name&gt; \
  --query 'nodegroup.nodeRepairConfig' 

null
</code></pre>
<p>null. Never configured. Never enabled.</p>
<p>This feature was available. We had just never set it up. The node sat NotReady for nearly 4 hours while the feature that would have replaced it in 10 minutes was turned off by default.</p>
<p>The lesson: EKS Node Auto Repair is not enabled by default. Check every nodegroup right now with the command above. If you get null, you have this gap.</p>
<p>Failure #3 — Cluster Autoscaler</p>
<p>The cluster autoscaler was running. It's supposed to handle exactly this kind of situation. But our configuration made it powerless:</p>
<pre><code class="language-plaintext"> Min: 6 | Max: 6 | Desired: 6
</code></pre>
<p>Min equals Max. The autoscaler has no headroom to operate. To replace a broken node, it needs to launch a new one first (going to 7, violating Max), drain the broken node, then terminate it (back to 6). With Max=6, it couldn't even start that sequence.</p>
<p>The autoscaler logs confirmed it saw the problem — and couldn't act:</p>
<pre><code class="language-plaintext">I0817 12:17:57 pre_filtering_processor.go:67] Skipping ip----.ec2.internal — node group min size reached (current: 6, min: 6)
</code></pre>
<p>It knew the node was bad. It had no authority to fix it.</p>
<p>There was a second problem: the cluster-autoscaler pod itself was running on the broken node, stuck in Terminating state alongside 25+ other pods.</p>
<pre><code class="language-plaintext">kube-system cluster-autoscaler-5********8 1/1 Terminating 0 6d5h
</code></pre>
<p>The thing responsible for replacing the broken node was stuck on the broken node.</p>
<p>The lesson: Min=Max is a zero-headroom configuration that paralyzes automated recovery. Set Max to at least Min+2 on every nodegroup.</p>
<p>Failure #4 — Memory Alert (Fired Too Late to Matter)</p>
<p>We had a memory alert configured — running on an 11-minute cron interval, watching for node memory usage above 95%.</p>
<p>ELK showed the node at 81.6% for hours before the incident:</p>
<pre><code class="language-plaintext">IST timestamp Node memory % 08:22:57 81.6% 08:33:57 81.6% 08:44:57 80.6% ← node already down, stale value
</code></pre>
<p>The 4.2GB memory spike happened entirely between two check cycles. At 08:22 the node was fine. At 08:44 the check returned stale data because the node was already gone.</p>
<p>The alert fired at 08:44 IST. The node went unreachable at 08:43:22 IST. The alert was 82 seconds behind.</p>
<p>This is a structural problem: the metric source is the node itself. When the node dies, metrics stop. If the crash happens between alert evaluation cycles, you miss it entirely. The faster a node crashes, the more likely it dies between evaluations.</p>
<p>The lesson: Metric-based node alerts have a fundamental blind spot. If the node is the source of the metric, the metric disappears when the node dies.</p>
<hr />
<p>What We're Fixing</p>
<ol>
<li><p>Enable EKS Node Auto Repair (do this first)</p>
<pre><code class="language-plaintext">aws eks update-nodegroup-config
--cluster-name
--nodegroup-name &lt;nodegroup_name&gt;
--node-repair-config enabled=true
--region us-east-1
</code></pre>
<p>When a node stays NotReady for the configured threshold, EKS automatically cordons, drains, and replaces it. The control plane makes this decision — it doesn't depend on the broken node reporting its own failure.</p>
</li>
<li><p>Set Max &gt; Min on Every ASG</p>
<pre><code class="language-plaintext">aws autoscaling update-auto-scaling-group
--auto-scaling-group-name
--min-size 6
--max-size 8
--region us-east-1
</code></pre>
<p>Max needs to be at least Min+2 to give the autoscaler room to launch a replacement before removing the broken instance.</p>
</li>
<li><p>Switch to ELB Health Checks</p>
<pre><code class="language-plaintext">aws autoscaling update-auto-scaling-group
--auto-scaling-group-name
--health-check-type ELB
--health-check-grace-period 300
--region us-east-1
</code></pre>
<p>ELB health checks evaluate actual application-layer response, not just hypervisor state.</p>
</li>
<li><p>Replace Metric-Based Node Alert with Condition-Based Alert</p>
<pre><code class="language-plaintext"># This fires even when the node is completely dead.
# kube-state-metrics reads from the API server, not from the node itself.
- alert: NodeNotReady
  expr: kube_node_status_condition{condition="Ready",status="true"} == 0
  for: 90s
  labels:
    severity: critical
  annotations:
    summary: "Node {{ $labels.node }} NotReady for &gt;90s — EKS Auto Repair should engage"
</code></pre>
<p>kube-state-metrics watches the Kubernetes API server — not the node. It fires even when the node is completely unreachable.</p>
</li>
<li><p>Enforce Memory Overcommit Limits</p>
<pre><code class="language-plaintext">apiVersion: v1
kind: LimitRange
metadata:
  name: memory-ratio-limit
  namespace: your-namespace
spec:
  limits:
  - type: Container
    maxLimitRequestRatio:
      memory: "4"   # limit cannot exceed 4x request
</code></pre>
<p>This forces the actual memory ceiling to stay within a predictable range of what the scheduler sees. A pod with a 1Gi request cannot have a 16Gi limit.</p>
</li>
</ol>
<hr />
<p>The Broader Problem</p>
<p>This wasn't an unusual incident. A node accumulated damage silently for 46 days. Nothing alerted. Nothing flagged the degraded containerd state. The node reported Ready to the control plane while internally the runtime was already compromised.</p>
<p>When the fatal event came — a memory spike from an unrelated service — four recovery mechanisms failed in different ways:</p>
<ul>
<li><p>EC2 health checks were asking the wrong question (is the VM up?)</p>
</li>
<li><p>EKS Auto Repair was never turned on</p>
</li>
<li><p>The autoscaler had no room to maneuver (Min=Max)</p>
</li>
<li><p>The metric-based alert fired 82 seconds after the node was already dead</p>
</li>
</ul>
<p>Any one of these gaps would have slowed recovery. All four together meant 4 hours of a NotReady node and a manual reboot at noon.</p>
<p>The fixes are each one or two commands. None of them are complicated. They just require knowing the gaps exist.</p>
<p>Check Your Cluster Right Now. Run this on every nodegroup:</p>
<pre><code class="language-plaintext">aws eks describe-nodegroup \
  --cluster-name &lt;your-cluster&gt; \
  --nodegroup-name &lt;your-nodegroup&gt; \
  --query 'nodegroup.nodeRepairConfig'
</code></pre>
<p>If you get null — you have this gap. Fix it before the next 2 AM alert.</p>
<blockquote>
<p>The names, cluster/node identifiers, timestamps, instance IDs, pod counts, resource values, and other incident-specific details in this article have been intentionally changed or fictionalized for privacy and security. The failure pattern and technical lessons remain representative of the original incident.</p>
</blockquote>
<p><em>🙏 Thank You for Reading!</em></p>
<p><em>Your time and attention mean a lot to us. We greatly appreciate your engagement with our content and would love to hear your thoughts and ideas. Let’s stay connected and continue our journey through the digital world together! 🌐📚💡</em></p>
<p><em>Let’s Stay in Touch 🪂 Connect with us on:</em> <a href="https://www.linkedin.com/in/prateeksrivastava123/"><em>LinkedIn</em></a><em>,</em> <a href="https://www.instagram.com/prateek1088/"><em>Instagram</em></a><em>,</em> <a href="https://prateeksrivastav598.medium.com/"><em>Medium</em></a></p>
]]></content:encoded></item></channel></rss>