Your API Server Is Quietly Choking—Here's How to Catch It Before Your Cluster Does
Here's a scenario that probably sounds familiar: your team's deployments are taking longer than they used to. Node provisioning feels sluggish. Your custom controllers seem to lag behind reality. You've checked CPU and memory on your nodes, scaled up your worker pool, maybe even thrown money at a bigger instance type for your control plane. Nothing meaningfully changes.
The frustrating truth? You might be fighting the wrong battle entirely. The Kubernetes API server—the single gateway through which every piece of cluster state flows—can become a serious bottleneck long before any obvious alarm goes off. And etcd, the distributed key-value store backing it, is often quietly degrading in the background while your dashboards look perfectly fine.
Let's talk about what's actually happening, how to spot it, and what you can realistically do about it.
Why the API Server Is Different From Every Other Bottleneck
Most performance problems in Kubernetes are distributed. A noisy neighbor pod, a misconfigured resource limit, a flapping network interface—these tend to affect specific workloads in specific places. The API server doesn't work that way.
Every controller, every scheduler decision, every kubectl command, every operator reconciliation loop, every kubelet heartbeat—all of it flows through the API server. It's a single logical chokepoint by design, because Kubernetes needs a consistent, authoritative source of cluster state. That design is also its Achilles heel at scale.
When the API server starts struggling, the effects radiate outward in ways that are genuinely easy to misread. Slow node provisioning looks like a cloud provider problem. CRD reconciliation delays look like buggy operators. Controller lag looks like a code issue in your custom tooling. Teams spend weeks chasing symptoms without ever looking at the actual source.
The etcd Factor Nobody Talks About Enough
The API server itself is largely stateless—it delegates persistence to etcd. Which means when etcd performance degrades, the API server has nowhere to hide.
etcd is a consensus-based system. Every write has to be committed across a quorum of members before it's acknowledged. On a healthy cluster with low-latency disk I/O, this is fast enough to be invisible. But a few common real-world conditions can quietly destroy etcd performance:
Disk latency creep. etcd is extremely sensitive to disk write latency. AWS gp2 volumes under sustained I/O pressure, Azure Standard SSDs during noisy periods, GCP persistent disks on over-provisioned hosts—any of these can push fsync latency high enough to start backing up etcd's write-ahead log. The threshold etcd considers healthy is 10ms for disk operations. In practice, many production clusters are running at 30–50ms without anyone realizing it.
Key space bloat. Every object in your cluster—every pod, configmap, secret, event—lives in etcd. Clusters that generate high volumes of short-lived objects (think CI/CD pipelines spinning up and tearing down pods constantly) can accumulate fragmented key space. etcd's MVCC storage model keeps historical revisions until compaction runs. If compaction is misconfigured or falling behind, your etcd database grows, and range queries slow down.
Leader elections under load. etcd leader elections triggered by network hiccups or slow followers can cause brief but cascading stalls in API server responsiveness. These are often logged but rarely monitored with the urgency they deserve.
Reading the Symptoms Right
Before you can fix anything, you need to confirm that the API server or etcd is actually your problem. Here are the signals worth watching:
API server request latency metrics. The apiserver_request_duration_seconds histogram is your first stop. Specifically, look at the 99th percentile latency broken down by verb and resource. LIST operations on large resources like pods or events are often the first to show elevated latency. A p99 above 1 second on GET or WATCH operations is a red flag.
Throttled requests. The apiserver_flowcontrol_rejected_requests_total metric (or apiserver_dropped_requests_total on older versions) tells you when requests are being actively shed. If this counter is incrementing, your API server is already overwhelmed.
etcd commit latency. etcd_disk_wal_fsync_duration_seconds and etcd_disk_backend_commit_duration_seconds are the etcd-side metrics to watch. Sustained p99 above 25ms on WAL fsync is a serious warning sign.
Watch event backlog. The apiserver_watch_events_total and related metrics can reveal whether watch streams are backing up. Controllers that rely on watches—including every operator you're running—will start behaving erratically when watch delivery lags.
Tools like kubectl top, standard Prometheus/Grafana setups, and purpose-built tools like kube-state-metrics and etcdctl endpoint status can give you a real picture here. If you're on a managed Kubernetes service, your cloud provider's control plane metrics (GKE's control plane observability, EKS's CloudWatch control plane logs, AKS's diagnostic settings) are worth enabling if you haven't already.
Practical Fixes That Don't Require Blowing Up Your Architecture
The good news is that most API server bottlenecks are addressable without a full cluster redesign. Here's where to start:
Tune API Priority and Fairness (APF). Kubernetes has had API Priority and Fairness built in since 1.20, and it's graduated to stable. APF lets you define flow schemas and priority levels that control how requests from different sources are queued and served. If your CI system is hammering the API server with LIST operations and starving your controllers, APF is the mechanism to fix that. Spend time understanding the default priority levels and adjust them to reflect your actual workload patterns.
Fix your etcd disk situation. If etcd fsync latency is your problem, the fix is usually straightforward: move etcd to faster storage. On AWS, switching from gp2 to gp3 or io1 with provisioned IOPS is often all it takes. Dedicated SSD volumes for etcd, separate from your general workload storage, are best practice for any cluster running more than a few hundred nodes.
Tune etcd compaction and defragmentation. Make sure --auto-compaction-retention is set to a reasonable value (1 hour is a common starting point). Run etcdctl defrag periodically—ideally as a scheduled job—to reclaim fragmented space. This is especially important on clusters with high object churn.
Reduce unnecessary watch consumers. Audit how many controllers and operators are running in your cluster, and what they're watching. A poorly written operator that opens a broad watch on all pods cluster-wide is a real tax on the API server. Scope watches to specific namespaces or label selectors wherever possible.
Limit expensive LIST operations. Operators and tooling that perform full LIST operations on high-cardinality resources (especially without pagination) can spike API server load significantly. Enforce pagination with --chunk-size flags in client code, and consider caching layers like controller-runtime's informer cache to avoid redundant API calls.
The Monitoring Gap You Need to Close
The real reason API server bottlenecks go undetected so long is that most teams monitor their workloads well and their control plane poorly. Node CPU, pod memory, network throughput—these get dashboards and alerts on day one. API server request latency and etcd disk performance often don't get the same treatment until something has already gone sideways.
If you take one thing from this article, let it be this: add control plane metrics to your standard monitoring stack now, before you have a problem. The Kubernetes community maintains solid Grafana dashboard templates for both the API server and etcd. Import them, set meaningful alert thresholds, and you'll catch these issues while they're still slow-and-annoying rather than cluster-down-and-urgent.
The API server is the nervous system of your cluster. Treat it like one.