Production EKS Platform cheat sheet
114 commands from every lesson of Production EKS Platform — From Zero to Production, on one page.
Look around an account
aws sts get-caller-identity | Which account and role am I using? |
aws ec2 describe-availability-zones --query 'AvailabilityZones[].ZoneName' | AZs in the current region |
aws ec2 describe-vpcs --query 'Vpcs[].[VpcId,CidrBlock]' --output table | VPCs and their CIDRs |
aws eks list-clusters | EKS clusters in this region |
aws eks describe-cluster --name prod --query 'cluster.[version,status,endpoint]' | Version, status and API endpoint |
aws eks list-addons --cluster-name prod | Managed add-ons installed |
aws service-quotas list-service-quotas --service-code eks | EKS service quotas |
Inspect a cluster
aws eks list-clusters | Clusters in the region |
aws eks describe-cluster --name prod --query 'cluster.[version,status,endpoint,resourcesVpcConfig.endpointPublicAccess,resourcesVpcConfig.endpointPrivateAccess]' | Version, status, endpoint access |
aws eks update-kubeconfig --name prod --region eu-west-1 | Add the cluster to your kubeconfig |
aws eks list-addons --cluster-name prod | Installed EKS add-ons |
aws eks list-nodegroups --cluster-name prod | Managed node groups |
Inspect the network
aws ec2 describe-subnets --filters Name=vpc-id,Values=<vpc> --query 'Subnets[].[SubnetId,AvailabilityZone,CidrBlock,AvailableIpAddressCount]' --output table | Subnets, AZs and free IPs |
aws ec2 describe-route-tables --filters Name=vpc-id,Values=<vpc> | Routes (IGW for public, NAT for private) |
aws ec2 describe-nat-gateways --filter Name=vpc-id,Values=<vpc> | NAT gateways per AZ |
aws ec2 describe-vpc-endpoints --filters Name=vpc-id,Values=<vpc> | Private endpoints to AWS services |
aws ec2 describe-subnets --filters Name=tag:kubernetes.io/role/internal-elb,Values=1 | Subnets marked for internal load balancers |
Inspect
kubectl -n kube-system get ds aws-node -o jsonpath='{.spec.template.spec.containers[0].env}' | jq | VPC CNI settings (env vars) |
kubectl get nodes -o custom-columns=NAME:.metadata.name,PODS:.status.allocatable.pods | Max pods per node |
aws ec2 describe-subnets --subnet-ids <id> --query 'Subnets[].AvailableIpAddressCount' | Free IPs left in a subnet |
Key settings
ENABLE_PREFIX_DELEGATION=true | Assign /28 prefixes to ENIs (more pods per node) |
AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true | Pods use subnets from ENIConfig (e.g. a secondary CIDR) |
WARM_IP_TARGET / WARM_PREFIX_TARGET | How many spare IPs/prefixes each node keeps ready |
Cluster
eksctl create cluster -f cluster.yaml | Create a cluster from a config file (quick labs) |
aws eks update-kubeconfig --name prod --region eu-west-1 | Write a kubeconfig entry for the cluster |
aws eks describe-cluster --name prod --query 'cluster.resourcesVpcConfig' | Endpoint access, subnets, security groups |
aws eks update-cluster-config --name prod --resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true | Make the API endpoint private |
Compute
aws eks list-nodegroups --cluster-name prod | Managed node groups |
kubectl get nodes -L eks.amazonaws.com/nodegroup,node.kubernetes.io/instance-type,topology.kubernetes.io/zone | Nodes with group, type and AZ |
aws eks list-fargate-profiles --cluster-name prod | Fargate profiles |
Add-ons
aws eks describe-addon-versions --addon-name vpc-cni --kubernetes-version 1.33 | Compatible add-on versions for a Kubernetes version |
aws eks create-addon --cluster-name prod --addon-name eks-pod-identity-agent | Install a managed add-on |
aws eks describe-addon --cluster-name prod --addon-name coredns --query 'addon.[addonVersion,status]' | Installed version and health |
Cluster access (access entries)
aws eks describe-cluster --name prod --query cluster.accessConfig | Authentication mode |
aws eks list-access-entries --cluster-name prod | Who has access |
aws eks create-access-entry --cluster-name prod --principal-arn <role-arn> | Grant an IAM role access |
aws eks associate-access-policy --cluster-name prod --principal-arn <role-arn> --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy --access-scope type=namespace,namespaces=shop | View access to one namespace |
aws eks list-associated-access-policies --cluster-name prod --principal-arn <role-arn> | What a principal can do |
kubectl auth can-i --list -n shop | Your own effective Kubernetes permissions |
Pod permissions
aws eks create-pod-identity-association --cluster-name prod --namespace shop --service-account orders --role-arn <role-arn> | Give a ServiceAccount an IAM role (Pod Identity) |
aws eks list-pod-identity-associations --cluster-name prod | All Pod Identity associations |
aws eks describe-cluster --name prod --query cluster.identity.oidc.issuer | OIDC issuer (for IRSA) |
kubectl annotate sa orders -n shop eks.amazonaws.com/role-arn=<role-arn> | IRSA: link a ServiceAccount to a role |
kubectl run awscli -n shop --rm -it --image=amazon/aws-cli --overrides='{"spec":{"serviceAccountName":"orders"}}' -- sts get-caller-identity | Which role does a pod really get? |
Guard-rails
kubectl get resourcequota,limitrange -n shop | Quotas and default limits in a namespace |
kubectl label ns shop pod-security.kubernetes.io/enforce=restricted | Enforce the restricted Pod Security Standard |
aws service-quotas get-service-quota --service-code ec2 --quota-code L-1216C47A | Running On-Demand standard instance vCPU quota |
Controller
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=prod | Install (after creating its IAM role; eks = https://aws.github.io/eks-charts) |
kubectl -n kube-system logs deploy/aws-load-balancer-controller | Why an LB wasn't created |
kubectl get ingress,svc -A -o wide | LB DNS names on Ingresses and Services |
Subnet tags (required for discovery)
kubernetes.io/role/elb = 1 | Public subnets for internet-facing LBs |
kubernetes.io/role/internal-elb = 1 | Private subnets for internal LBs |
ECR
aws ecr create-repository --repository-name shop/api --image-tag-mutability IMMUTABLE --image-scanning-configuration scanOnPush=true | Repository with immutable tags and scan on push |
aws ecr get-login-password | docker login --username AWS --password-stdin <acct>.dkr.ecr.<region>.amazonaws.com | Log Docker in to ECR (12-hour token) |
docker push <acct>.dkr.ecr.<region>.amazonaws.com/shop/api:1.4.0 | Push an image |
aws ecr describe-image-scan-findings --repository-name shop/api --image-id imageTag=1.4.0 | Vulnerability findings |
aws ecr put-lifecycle-policy --repository-name shop/api --lifecycle-policy-text file://lifecycle.json | Expire old images automatically |
Roll out
kubectl set image deploy/api api=<acct>.dkr.ecr.<region>.amazonaws.com/shop/api:1.4.1 -n shop | Start a rolling update |
kubectl rollout status deploy/api -n shop | Watch it complete |
kubectl rollout undo deploy/api -n shop | Roll back to the previous ReplicaSet |
kubectl get pods -n shop -o wide -L topology.kubernetes.io/zone | Are replicas spread across AZs? |
Drivers
aws eks create-addon --cluster-name prod --addon-name aws-ebs-csi-driver | EBS CSI driver (give it a role via Pod Identity) |
aws eks create-addon --cluster-name prod --addon-name aws-efs-csi-driver | EFS CSI driver |
kubectl get csidrivers | ebs.csi.aws.com, efs.csi.aws.com, … |
Tiers
gp3 (WaitForFirstConsumer) | Hot: databases, general RWO volumes |
io2 | Hot and demanding: consistent high IOPS |
EFS (access points) | Shared RWX files across AZs |
S3 (+ Mountpoint CSI) | Cold, large, read-heavy data; backups |
Inspect
kubectl get nodepools,ec2nodeclasses | Karpenter configuration |
kubectl get nodeclaims -o wide | Nodes Karpenter launched (type, zone, capacity type) |
kubectl -n kube-system logs deploy/karpenter -f | Why it launched or removed a node (namespace depends on install) |
kubectl get nodes -L karpenter.sh/capacity-type,node.kubernetes.io/instance-type,topology.kubernetes.io/zone | Capacity type, instance type and zone per node |
Protect a workload
karpenter.sh/do-not-disrupt: "true" | Pod annotation: don't voluntarily disrupt this pod's node |
PodDisruptionBudget | Karpenter respects PDBs when draining |
Control plane
aws eks update-cluster-config --name prod --logging '{"clusterLogging":[{"types":["api","audit","authenticator"],"enabled":true}]}' | Send control-plane logs to CloudWatch Logs |
aws logs tail /aws/eks/prod/cluster --follow --filter-pattern authenticator | Follow control-plane logs |
kubectl get --raw /metrics | grep apiserver_request_total | head | API server metrics (Prometheus format) |
In the cluster
aws eks create-addon --cluster-name prod --addon-name amazon-cloudwatch-observability | Container Insights + Fluent Bit via managed add-on |
helm install kps prometheus-community/kube-prometheus-stack -n monitoring --create-namespace | Self-run Prometheus, Alertmanager, Grafana |
kubectl top pods -A --sort-by=memory | head | Quick resource view (metrics-server) |
Check the posture
aws eks describe-cluster --name prod --query 'cluster.[resourcesVpcConfig.endpointPublicAccess,resourcesVpcConfig.publicAccessCidrs,encryptionConfig]' | Public endpoint, allowed CIDRs, secrets encryption |
aws ec2 describe-launch-templates --query 'LaunchTemplates[].LaunchTemplateName' | Find node launch templates to check IMDS settings |
kubectl get ns -L pod-security.kubernetes.io/enforce | Pod Security level per namespace |
kubectl get networkpolicy -A | Which namespaces restrict traffic |
aws guardduty list-findings --detector-id <id> --finding-criteria '{"Criterion":{"resource.resourceType":{"Eq":["EKSCluster"]}}}' | GuardDuty findings for EKS |
Harden
kubectl label ns shop pod-security.kubernetes.io/enforce=restricted --overwrite | Enforce restricted pods |
aws eks update-addon --cluster-name prod --addon-name vpc-cni --configuration-values '{"enableNetworkPolicy":"true"}' | Enable network policy in the VPC CNI |
trivy image <acct>.dkr.ecr.<region>.amazonaws.com/shop/api:1.4.0 | Scan an image before deploying |
Before
aws eks list-insights --cluster-name prod | Upgrade insights: deprecated APIs, add-on compatibility and more |
aws eks describe-addon-versions --addon-name vpc-cni --kubernetes-version 1.33 --query 'addons[].addonVersions[0].addonVersion' | Latest add-on version for the target Kubernetes version |
kubectl get pdb -A | Budgets that could block node replacement |
Do
aws eks update-cluster-version --name prod --kubernetes-version 1.33 | Upgrade the control plane (or change the version in Terraform) |
aws eks update-addon --cluster-name prod --addon-name coredns --addon-version <v> | Upgrade an add-on |
aws eks update-nodegroup-version --cluster-name prod --nodegroup-name system | Roll a managed node group to the new version |
State recovery
aws s3api list-object-versions --bucket acme-tfstate-prod --prefix eks/prod/cluster/ | Previous versions of a state file |
aws s3api get-object --bucket … --key … --version-id <id> old.tfstate | Download an older version |
terraform state pull > backup.tfstate | Back up current state before any repair |
import { to = aws_s3_bucket.logs id = "acme-logs" } | Re-adopt an existing resource (in code, Terraform 1.5+) |
Prevention
lifecycle { prevent_destroy = true } | Refuse to plan destruction of critical resources |
deletion_protection / termination protection | Provider-level protection where available |
IAM deny on eks:DeleteCluster for CI roles (except break-glass) | Stop destructive calls at the API |
Laptop
aws sso login --profile prod-readonly | Get short-lived credentials |
aws eks update-kubeconfig --name prod --region eu-west-1 --alias prod --profile prod-readonly | Write the kubeconfig entry |
kubectl config view --minify | See the exec plugin (aws eks get-token) |
kubectl auth whoami | Who does the cluster think I am? |
Pipelines
infra: OIDC role → terraform plan (PR) / apply (main, approved) | Infrastructure changes |
app: OIDC role → docker build → push to ECR (by digest) | Images |
GitOps repo commit → Argo CD sync | Deployments |
Evidence to bring to a review
aws eks describe-cluster --name prod | Version, endpoint access, auth mode, logging, encryption |
aws eks list-addons --cluster-name prod | Managed add-ons and versions |
aws eks list-access-entries --cluster-name prod | Who has access |
kubectl get nodepools,nodeclaims | Karpenter capacity |
kubectl get pdb,hpa -A | Disruption budgets and autoscalers |
kubectl get ns -L pod-security.kubernetes.io/enforce,team | Tenancy and pod security per namespace |