$ cat post/nmap-on-the-lan-/-a-certificate-expired-there-/-the-signal-was-nine.md

nmap on the lan / a certificate expired there / the signal was nine


Title: Kubernetes Meltdown: Debugging a Production Issue


January 15, 2018. I remember it like yesterday. The morning started off like any other, but by afternoon, we were in the thick of debugging what turned out to be one of our most challenging issues to date.

We were running a microservices architecture with Kubernetes at the heart of our infrastructure. The service we were working on was crucial for our platform—think of it as the nervous system that kept everything else alive and well. It was built around a REST API, but under the hood, it relied heavily on various services like Redis for caching, PostgreSQL for persistence, and a number of sidecars for logging and monitoring.

Around 2 PM, I got an alert from Prometheus: our API service had taken a nosedive. CPU spikes were through the roof, and requests were timing out left and right. Our monitoring dashboard was showing red flags everywhere, but nothing stood out as particularly suspicious at first glance. I immediately pulled up the Kubernetes Dashboard to get a closer look.

The pod logs looked fine—no errors or warnings that would suggest a bug. But the CPU usage charts were telling an alarming story. The pods were maxing out their CPU limits and then some. The memory usage was staying within reasonable bounds, which initially pointed towards something CPU-bound rather than memory-bound.

I spent a good hour digging through the logs and metrics, trying to pinpoint the issue. That’s when I spotted it: in the Redis cluster metrics, the number of commands processed per second had sky-rocketed over 10x compared to usual levels! This made me suspicious that something was hitting our cache harder than intended.

A quick look at the API logs revealed a flood of requests from what appeared to be random IP addresses. These were mostly read-heavy operations, and given how closely coupled our services were, it seemed likely they could have cascaded down into Redis.

We had enabled rate limiting for incoming API calls, but not for internal service-to-service communication. And here was the kicker: we weren’t even using Prometheus for metrics scraping in those internal services due to performance concerns.

So, the root cause was clear: a misconfiguration in our internal service-to-service requests that led to an excessive load on Redis, which then caused a chain reaction of CPU-intensive tasks across all nodes. This was classic case of not accounting for edge cases and overloading our infrastructure.

After identifying the issue, I quickly patched the configuration files and applied the changes via Helm. The immediate impact was a significant drop in CPU usage across the board. Within an hour, everything was back to normal.

This incident taught us several valuable lessons:

  1. Thorough testing of edge cases is crucial, especially when dealing with microservices.
  2. Monitoring and metrics infrastructure must be comprehensive; we need visibility into all parts of our system, not just the public-facing interfaces.
  3. Consistency in monitoring practices, such as always using Prometheus for scraping, can prevent these kinds of issues from escalating.

Looking back, this was a good reminder that even with robust Kubernetes clusters and well-architected services, human error still plays a significant role in system reliability. The next version of our platform will include better checks and balances to mitigate similar risks.

As the sun set on that day, I felt a mix of relief and pride at having solved what had seemed like an insurmountable problem. Debugging issues like this is always stressful, but it’s also incredibly rewarding when you finally see the light at the end of the tunnel.