Disclosure: This article may contain affiliate links. We may earn a commission if you purchase through these links, at no extra cost to you. We only recommend products we believe in.

Master Amazon EKS best practices for production. Learn Kubernetes on AWS optimization, performance tuning, and cost management strategies.


Running Kubernetes in production on AWS sounds straightforward until you're debugging a pod eviction at 2 AM while your cluster decides to scale to 200 nodes because your Horizontal Pod Autoscaler is misconfigured. I've been there. After deploying and managing dozens of EKS clusters for enterprises ranging from fintech startups to Fortune 500 healthcare companies, I've learned that production-grade EKS optimization isn't about any single silver bullet—it's about getting multiple fundamentals right simultaneously.

Why Amazon EKS Production Optimization Matters More Than Ever

Amazon EKS handles over 2.3 million active clusters globally, according to AWS re:Invent 2023 announcements, and the platform's managed control plane has improved dramatically. However, the managed control plane is only half the battle. Your worker nodes, networking configuration, and operational practices determine whether you hit 99.99% uptime or spend your Q4 firefighting unexpected scaling events.

The difference between a well-tuned EKS cluster and a struggling one often comes down to three factors: how efficiently you're using compute resources (and how much you're paying), how gracefully your cluster handles traffic spikes, and how quickly you can diagnose issues when something goes wrong. This guide covers all three dimensions with actionable recommendations you can implement today.

Node Group Architecture: Foundation First

Managed Node Groups vs. Self-Managed: The Decision That Shapes Your Operations

For production workloads, I strongly recommend managed node groups (MNGs) over self-managed nodes. The operational overhead savings are substantial—AWS handles node provisioning, lifecycle management, and Kubernetes version updates without requiring you to maintain custom AMIs or launch configurations.

When configuring managed node groups, avoid the common mistake of using a single instance type across your cluster. I learned this the hard way during a 2021 incident when an AWS capacity constraint in us-east-1a caused pod evictions across multiple deployments simultaneously. Instead, implement instance diversification within your node groups:

  • Create separate node groups for different workload types (compute-optimized for ML inference, memory-optimized for databases, general-purpose for application workloads)
  • Spread instances across multiple Availability Zones within a region
  • Use capacity-optimized allocation strategy for predictable workloads, and spot instances with diversified instance families for fault-tolerant batch processing

Scaling Configuration That Actually Works

Cluster Autoscaler configuration makes or breaks your production experience. The default settings will leave you with either under-provisioned clusters during traffic spikes or bloated clusters burning budget during off-peak hours.

For most production workloads, configure Cluster Autoscaler with these parameters:

--balance-similar-node-groups=true
--expander=price
--skip-nodes-with-local-storage=false
--scale-down-unneeded-time=10m
--scale-down-utilization-threshold=0.5

The balance-similar-node-groups setting is critical if you're following my recommendation to diversify instance types—it ensures Cluster Autoscaler distributes pods evenly across your instance families rather than filling one type before scaling others.

Set your scale-down-utilization-threshold to 0.5 (50% CPU or memory utilization) for most workloads. If you're running highly stateful applications with expensive restarts, consider 0.65 to reduce unnecessary terminations. Lower thresholds like 0.3 are appropriate only for cost-sensitive batch workloads that can tolerate frequent scaling.

Networking: VPC CNI Deep Dive

Security Groups and Pod Networking

The Amazon VPC CNI plugin assigns each pod a primary ENI IP address from your VPC subnet. This provides excellent network performance but creates a challenge: each node has a limited number of IPs based on its instance type (a c5.xlarge has a max of 4 ENIs and 15 IP addresses per ENI, though you typically won't use all of them for pods).

For production clusters, enable the VPC CNI's prefix delegation feature, introduced in CNI version 1.9.0. Prefix delegation allows each ENI to allocate /28 prefixes (16 IP addresses per prefix) instead of individual IPs, dramatically increasing pod density per node. A c5.4xlarge can support over 200 pods with prefix delegation versus under 60 without it.

Configure your VPC CNI with these recommended settings:

AWS_VPC_K8S_CNI_CUSTOM_NETWORKING=true
AWS_VCP_K8S_CNI_EXTERNAL_SNAT=false
WARM_PREFIX_TARGET=1
MINIMUM_IP_TARGET=10

Network Policies: Don't Skip This

By default, all pods in your EKS cluster can communicate with each other. For production environments handling sensitive data, implement network policies immediately. AWS VPC CNI supports Kubernetes Network Policies natively, but you must explicitly create them—there's no default-deny policy.

I recommend starting with a default-deny policy for all namespaces except kube-system, then explicitly allowing only required communication paths. This follows the principle of least privilege and dramatically reduces your blast radius if a container gets compromised.

Resource Management: Avoiding the OOMKiller's Wrath

Setting Pod Resource Requests and Limits Correctly

One of the most common production EKS issues I encounter is misconfigured resource requests and limits. When requests are too low, the Kubernetes scheduler places pods on nodes that can't actually support them, leading to immediate OOMKilled events. When limits are too high, you're wasting money and creating resource fragmentation across your cluster.

For production workloads, establish a resource request/limit framework:

Memory limits should typically be set to 1.5-2x the observed working set during normal operation. If your application consistently uses 512Mi working set, set limits to 768Mi-1Gi. The extra headroom accommodates traffic spikes, garbage collection overhead, and logging bursts.

CPU limits require more nuance. For most application workloads, I recommend setting requests equal to limits (Guaranteed QoS class) for predictable latency-sensitive services, but leaving limits unset for batch workloads that should burst freely. Avoid setting CPU limits too conservatively—throttled CPU causes latency spikes that are harder to diagnose than OOM events.

Implementing Vertical Pod Autoscaler

VPA (Vertical Pod Autoscaler) in recommendation mode is an excellent starting point. It analyzes historical resource usage and suggests appropriate requests without modifying your running pods. After 1-2 weeks of data collection, review VPA recommendations and update your deployments accordingly.

Once you're comfortable with the recommendation patterns, switch VPA to Auto mode for development namespaces—though I'd caution against Auto mode in production initially. The pod disruption caused by VPA modifications can impact availability if not coordinated with your deployment strategy.

Monitoring and Observability: Seeing What Matters

Essential Metrics You Must Track

A production EKS environment without proper observability is flying blind. Beyond basic cluster metrics, focus on these high-signal indicators:

  1. Pod startup latency: If average pod startup exceeds 60 seconds, investigate image pull times, init container configuration, and readiness probe settings
  2. Container restart frequency: Multiple restarts within an hour typically indicate resource constraints, liveness probe misconfiguration, or application bugs
  3. HPA effectiveness: Track the gap between desired and actual replica counts—if HPA consistently can't scale fast enough, adjust scale-up velocity or reduce minimum replica counts
  4. Node memory pressure: Monitor node_memory_Active_bytes and node_memory_Cached_bytes to predict upcoming evictions before they occur

Recommended Monitoring Stack

For most production EKS environments, deploy the following stack:

  • Amazon CloudWatch Container Insights as your baseline observability layer—it's included with EKS at no additional cost and provides dashboards, alarms, and log aggregation out of the box
  • Prometheus Operator for detailed application metrics and custom alerting rules—deploy via EKS Blueprints for consistent configuration
  • AWS Distro for OpenTelemetry (ADOT) for distributed tracing and unified data collection

CloudWatch Container Insights has limitations for cost optimization: it can become expensive at scale. For clusters exceeding 500 nodes or 5000 pods, consider a self-managed Prometheus with Amazon Managed Service for Prometheus (AMP) to reduce per-metric costs while gaining more flexibility.

Cost Optimization: The Pillar Everyone Wants But Few Achieve

Compute Savings Without Compromising Reliability

AWS provides several mechanisms to reduce EKS compute costs, but each comes with trade-offs you must understand:

Savings Plans for Compute offer up to 66% savings compared to On-Demand pricing in exchange for 1 or 3-year commitments. For production workloads with predictable baseline capacity, this is a no-brainer. I typically recommend committing to 60-70% of your baseline utilization and letting Cluster Autoscaler handle the variable portion with On-Demand or Spot instances.

Spot Instances provide up to 90% discount but come with interruption risk. For stateless, fault-tolerant workloads, Spot is excellent. Use multiple instance families in a single node group and configure graceful termination handling with the aws-node DaemonSet draining pods before spot interruption notices arrive.

Graviton-based instances (M7g, C7g, R7g) provide 20% better price-performance than comparable Intel-based instances for most workloads. If your application supports ARM64 (most modern containerized applications do), migrate to Graviton for straightforward cost reduction. We migrated a client's API gateway cluster from c6i.xlarge to c7g.xlarge and achieved 15% cost reduction with 10% latency improvement.

EKS Cluster Cost Attribution

For enterprise environments, EKS charges $0.10 per hour per cluster ($73/month). This is often negligible compared to compute costs, but you should track it for chargeback purposes. Use AWS Resource Access Manager (RAM) to share clusters across accounts if you're running multiple environments—consolidating from 4 development clusters to 2 shared clusters reduced one client's EKS costs by 50% while improving resource utilization.

High Availability: Designing for Failure

Control Plane Resilience

EKS provides a highly available control plane with three masters across multiple AZs by default. However, you must configure your data plane to handle control plane API latency during rare availability events.

Implement retry logic with exponential backoff in your application deployment code. Configure your Kubernetes client (kubectl, client-go libraries) with appropriate timeout settings—5-10 seconds for most operations is reasonable, though watch operations may need longer.

Workload High Availability Patterns

For production deployments requiring high availability, enforce these deployment practices:

  • Minimum 2 replicas for all production workloads: a single-replica deployment will experience downtime during node updates, pod disruptions, or routine maintenance
  • PodDisruptionBudgets (PDBs) with maxUnavailable=1 for stateless applications: this prevents the cluster from evicting too many pods simultaneously during voluntary disruptions like node drains
  • Pod anti-affinity rules for stateful applications: spread database pods across availability zones to survive AZ failures
  • Topology spread constraints: ensure pods distribute evenly across regions, zones, or node groups for improved fault tolerance

Operational Excellence: Practices That Scale

GitOps with ArgoCD or Flux

Configuration drift is the enemy of reliable production systems. Implement GitOps workflows using ArgoCD or Flux to ensure your cluster state matches your desired state defined in Git. This provides audit trails, rollback capabilities, and prevents manual configuration that can't be reproduced.

Upgrade Strategy: Never Skip Patch Versions

Kubernetes version upgrades on EKS happen quarterly with approximately 4 months of support per minor version. For production clusters:

  1. Always test upgrades in non-production environments first—allow 2-4 weeks for validation
  2. Review Kubernetes release notes for breaking changes and deprecations affecting your workloads
  3. Never skip more than one minor version when upgrading
  4. Schedule upgrades during low-traffic windows and have rollback procedures ready

AWS EKS supports extended support for older versions at additional cost ($0.60 per cluster per hour for EKS Extended Support), which can be valuable during complex upgrade periods but should not become a long-term strategy.

Conclusion: The Optimization Journey Is Continuous

Amazon EKS production optimization isn't a one-time project—it's an operational discipline that compounds over time. Start with the fundamentals: diversified node groups, proper resource configuration, and baseline observability. Then layer in cost optimization, advanced networking policies, and GitOps workflows as your team matures.

The organizations that run EKS most successfully treat their cluster as a product with a roadmap, not infrastructure that should just work. Invest in automation, document your patterns, and build runbooks before you need them. Your future on-call self will thank you.

If you're operating EKS at scale and encountering specific challenges—cost overruns, scaling bottlenecks, or observability gaps—Ciro Cloud's architecture team has helped dozens of enterprises address these exact pain points. Reach out for a complimentary cluster review.

Weekly cloud insights — free

Practical guides on cloud costs, security and strategy. No spam, ever.

Comments

Leave a comment