Amazon EKS in Production with Terraform›Playbooks, challenges & practice · Cheat sheet & self-check
Learning Hub / Cloud — OpenStack, AWS & EKS / Amazon EKS in Production with Terraform

Playbooks, challenges & practice · wrap-up

Cheat sheet & self-check

Every command from this section on one page.

13 · Playbook: creating the cluster

Pre-flight

aws sts get-caller-identityRight account and role?
aws service-quotas get-service-quota --service-code ec2 --quota-code L-1216C47AOn-Demand standard vCPU quota
terraform version / kubectl version --client / helm versionTool versions match the repo's pins

Per layer (network → cluster → platform)

terraform init -backend-config=backend-prod.hclPoint at this layer's state
terraform plan -var-file=prod.tfvars -out=prod.planReview: only expected creates
terraform apply prod.planApply exactly what was reviewed

Verification gates

aws eks describe-cluster --name prod --query 'cluster.status'ACTIVE
aws eks update-kubeconfig --name prod --region eu-west-1 --alias prodkubectl access
aws eks list-addons --cluster-name prod / describe-addon …Add-ons ACTIVE
kubectl get nodes -o wide / kubectl get pods -ANodes Ready, system pods Running

14 · Playbook: day-2 operations

Everyday changes (through Git + pipeline)

NodePool / node group change in the platform or cluster layerAdd or reshape capacity
aws_eks_access_entry + aws_eks_access_policy_associationGrant a team access
aws eks describe-addon-versions --addon-name vpc-cni --kubernetes-version 1.32Compatible add-on versions

Upgrade

pluto detect-helm -o wide / pluto detect-files -d manifests/Deprecated APIs before upgrading
kubernetes_version = "1.33" → plan/apply (cluster layer)Control plane first
kubectl get nodes -L karpenter.sh/nodepool -o wideWatch nodes roll to the new version

Teardown (reverse order)

kubectl delete ingress,svc -A -l <app selector> (LB-backed)Let controllers delete ALBs/NLBs
kubectl delete nodepools --allLet Karpenter terminate its nodes
terraform destroy (platform → cluster → network)Then Terraform

15 · The flow: laptop → cluster → kubeconfig → app

Laptop

aws sso login --profile prod-readonlyGet short-lived credentials
aws eks update-kubeconfig --name prod --region eu-west-1 --alias prod --profile prod-readonlyWrite the kubeconfig entry
kubectl config view --minifySee the exec plugin (aws eks get-token)
kubectl auth whoamiWho 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 syncDeployments

16 · Challenges on this stack

Quick checks

terraform plan | grep -E 'must be replaced|forces replacement'Dangerous replacements
terraform plan -detailed-exitcode (2 = changes)Scheduled drift detection
kubectl get nodeclaims / kubectl -n kube-system logs deploy/karpenterWhy no new nodes?
kubectl describe pvc <p> / kubectl get pv -o wideVolume AZ and binding
kubectl -n kube-system logs deploy/aws-load-balancer-controller | tailWhy no ALB?

Guard rails

lifecycle { prevent_destroy = true }On the cluster and state-critical resources
volumeBindingMode: WaitForFirstConsumerEBS volumes created in the pod's AZ
VPC endpoints: ecr.api, ecr.dkr, s3 (gateway), stsCut NAT traffic

17 · Recovery playbook

State

terraform force-unlock <LOCK_ID>Release a stale lock (after confirming nothing is running)
aws s3api list-object-versions --bucket <b> --prefix eks/prod/cluster/terraform.tfstateFind earlier state versions
terraform state pull > before-repair.tfstateBackup before any repair
import { to = … id = … } then plan/applyAdopt existing resources

Network & cluster

aws ec2 describe-network-interfaces --filters Name=vpc-id,Values=<vpc> --query 'NetworkInterfaces[].[NetworkInterfaceId,Description,Status]'Leftover ENIs blocking destroy
aws eks list-access-entries --cluster-name prodWho can get in
velero restore create --from-backup <name>Restore app data/objects to a rebuilt cluster

18 · Simulator: practise for $0

Terraform without AWS

terraform fmt -check && terraform validateSyntax and references
mock_provider "aws" {} in tests/*.tftest.hclFake provider for tests (Terraform 1.7+)
terraform testRun plan-based tests with assertions

Local stand-ins

docker run -d -p 4566:4566 localstack/localstackLocalStack (check feature coverage for your version)
backend "s3" { endpoints = { s3 = "http://localhost:4566" } use_path_style = true … }State backend on LocalStack
kind create cluster --name eks-simPractise the platform layer
AWS Budgets alert + destroy after each sessionWhen you do use real AWS