See it as a diagram
Everything below, as a diagram you can edit. Describe yours and see it in seconds.
No account needed · Editable canvas, not a picture
Two planes, drawn differently
The control plane is operated by AWS in an AWS-owned VPC. You do not run its API server, etcd, scheduler, or controller manager, so drawing boxes for them documents Kubernetes rather than your cluster. One node labelled with the cluster name, the Kubernetes version, and the API endpoint access mode (public, private, or both) carries everything a reader can act on.
The data plane is yours and deserves the detail: managed node groups with their instance types and scaling range, Fargate profiles with the selectors that route pods to them, and Karpenter-provisioned capacity if that is what you run. These sit in your subnets, in your availability zones, and they are what fails when a zone fails.
The API endpoint mode is worth stating explicitly because it is a recurring audit question and it is invisible in most diagrams. A private-only endpoint means kubectl requires network access into the VPC, which changes how the CI pipeline and the on-call laptop reach the cluster.
Show the network the cluster actually uses
Draw the cluster inside the VPC, with node groups in private subnets spread across the availability zones they are configured for. This is where EKS diagrams most often mislead: a cluster drawn as a floating box hides the fact that pods live on instances in your subnets and consume your address space.
That address consumption is worth annotating. The Amazon VPC CNI plugin, amazon-vpc-cni-k8s, gives every pod a real VPC IP address from the subnet its node sits in, so a subnet sized for a handful of instances can run out of addresses long before it runs out of instance capacity. Putting the subnet CIDR and the ENABLE_PREFIX_DELEGATION setting on the diagram saves a future incident.
The ingress path deserves the full chain because it crosses both worlds: Route 53 to an ALB created by the AWS Load Balancer Controller from an Ingress object, to a target group registering pod IPs directly in IP target mode, to the Service, to the pods. Drawing the ALB without noting that a controller inside the cluster created it leaves readers unable to work out where that load balancer configuration lives.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: checkout
namespace: payments
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/subnets: subnet-public-a, subnet-public-b
spec:
ingressClassName: alb
rules:
- host: checkout.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: checkout
port: { number: 8080 }Kubernetes objects at the right altitude
Namespaces make good zones inside the cluster because they usually match team or domain ownership. Inside them, draw Deployments and StatefulSets, not individual pods. Pods are ephemeral by design, and a diagram that shows three replicas is wrong the moment the autoscaler acts. Put the replica range on the workload node instead.
Cluster add-ons and controllers belong in a note: CoreDNS, kube-proxy, the VPC CNI, the EBS CSI driver, the AWS Load Balancer Controller, Karpenter, external-dns, cert-manager. They are infrastructure for the cluster rather than parts of any application path, and listing them with their versions in one block is more useful than scattering them across the canvas.
IAM shows up here as IRSA or EKS Pod Identity, and it works best as an edge label: an arrow from a workload to a DynamoDB table reading "via IRSA, CheckoutServiceRole". That keeps the identity attached to the call it authorises, which is the same rule as in showing IAM in an AWS diagram.
Generating it and keeping it true
Cluster topology changes faster than almost anything else in an AWS account: new namespaces, new workloads, new node groups, a version upgrade every few months. A hand-drawn EKS diagram has a short life expectancy.
Two sources keep it honest. The Terraform that provisions the cluster, VPC, node groups, and add-ons, parsed from source with no init and no state, covers the AWS half. The catalog treats aws_eks_cluster as a first-class node and picks version as the attribute displayed on it, so the Kubernetes version on the diagram is read out of the .tf file rather than remembered, and that is the single field that goes stale fastest on a hand-drawn EKS picture.
The Kubernetes manifests in the repository cover the workload half, which is the subject of living diagrams from Kubernetes manifests. Either way the sync regenerates the diagram daily, and nodes you moved by hand keep their positions across syncs, so the picture updates rather than reshuffles.
FAQ
Should the EKS control plane components be drawn individually?
How do I show pods without the diagram going stale?
Where should namespaces appear?
Why does the subnet CIDR matter on an EKS diagram?
How does the ALB get into an EKS diagram?