
Series of blog posts show progress of updating/adding to EKS Cluster, this post covers adding Terraform bootstrap for enhanced automation, start-up sh script, & connecting Grafana w/Prometheus, Loki, Tempo, & Thanos to S3 for further telemetry. See below for past posts:
Bootstrappin TF w/thuh Ferrrrr’:
- Small TF bootstrap layer instead of pullin my whole Gitops Repo into TF. We will be like Hashicorp & be all “declarative”… so once TF gets Argo installed, everything flows down-hill.
- TF = where is gitops entry point?
- Argo = whats deployed?
- Documentiontion Referencing:
Terraform Apply
│
├── VPC
├── EKS
├── EBS CSI
├── IAM / IRSA
├── S3
├── Argo CD
│
└── bootstrap-root
│
▼
GitHub
│
▼
monitoring-root
│
├── kube-prometheus-stack
├── Loki
├── Tempo
├── Thanos
└── metrics-server
Providers.tf:
terraform-aws-modules/eks = module.eks_east.cluster_name
↓
creates EKS cluster & aws_eks_cluster_auth data source
↓
exports cluster_certificate_authority_data & temporary authentication token
↓
kubectl provider uses it
Bootstrap.tf
EKS
↓
Argo Helm installation
↓
bootstrap-root
Lil Scripty Script to make this Reproducible:
- Oh & did a simple post-build verification script too, basically runs some commands to ensure i can get my pods & stuff.
- Before Makeover
- Terraform Apply
- aws eks update-kubeconfig….
- kubectl apply -f bootstrap-root.yaml
- …wait…
- Verify
- After Makeover
- Terraform Apply
- awks eks update-kubeconfig..
- ./scripts/verify-cluster.sh
Verify-cluster.sh:
Prometheus, Sidecar Named Thanos & AWS IRSA S3:
- Wanted some long-term metrics from the Prometheus Thanos Sidecar that uploads TSDB Blocks into S3.
- Leveraging documentation
Prometheus
│
├── local 24h metrics
│
└── Thanos sidecar
↓
S3
↓
Thanos Store Gateway
↓
Thanos Query
Objstore.yaml:
- Added annotation for sync-wave “-1” cuz Argo can apply the secret before Prometheus & now it can reference it.
Thanos-IAM.tf:
- Need Prometheus ID to write to S3, IRSA saves the day. Oh yah, & a trust policy too – duhh
- Sub = authorizes k8s service accounts to assume IAM role
- Trust policy allows Thanos Store Gateway & Prometheus Thanos Sidecar assume the role
- Permission Policy says what the role can do
- Leveraged AWS Docx
Values.tf:
- Argo deploys Helm Charts plus my values, so also had to deploy that secret too.
- Referenced Thanos-iam.tf serviceaccount annotation & objstore.yaml
Application-bootstrap.yaml:
- Added a third source, manifest
- Leveraged documentation
annotations:
argocd.argoproj.io/sync-wave: "-1"
Visualzz of what had happen was:
TF Commandzz:

- terraform init -upgrade
- terraform fmt
- terraform validate
- terraform plan
- terraform apply


Thanos Storage Gateway Issue:
- Oddly ran on an AZ that was not available
kubectl delete pvc data-thanos-storegateway-0 -n monitoring
Prometheus Application OutOfSync/Missing:
- Argo was stuck on kube-prometheus-stack-admission & are no admissions jobs hard refresh, so Argo syncs kept getting stuck on the admission hook
# ============================# PROMETHEUS OPERATOR (CHEAP MODE)# ============================prometheusOperator: resources: requests: cpu: 20m memory: 50Mi limits: cpu: 100m memory: 100Mi prometheusOperator: admissionWebhooks: patch: enabled: false
- Pod-count capacity on the nodes, not CPU/memory. Daemon-set wants 1 node-exporter pod per node, have 3 ready nodes, but only one exporter is running & other two are pending. Aka —- too many pods.
- AWS Docx Reference
- Cuz i have spot, i have different sizes & smaller instance support fewer pods network interfaces/IPs & EKS pod allocatable limit.
node_instance_types = [ "t4g.small", "t4g.medium", "t4g.large"]t4g.medium → 10 podst4g.small → 9 podst4g.small → 8 pods
- For your lab, the cleanest fix is to enable VPC CNI prefix delegation, which increases the number of pod IPs available per node and therefore increases pod density. AWS specifically recommends prefix delegation when you need more pods per node.
- AWS Docx Reference
- Check CNI version/config
- Enable prefix delegation
- Replace/update nodes
- Verify MAXPODS increases
- Let node-exporter schedule
- Verify Argo → Synced / Healthy
- The root cause was i did not enable prefix delegation, so the nodes were capped at MAXPODS=11 & exporter DaemonSet can NOT schedule on 2 nodes.
- Enabled to true, makes VPC CNI allocate /28 prefixes to ENIs & increase pod IP capacity.
- AWS Docx Reference:
ebs-csi.tf:
resource "aws_eks_addon" "vpc_cni_east" { cluster_name = module.eks_east.cluster_name addon_name = "vpc-cni" most_recent = true configuration_values = jsonencode({ env = { ENABLE_PREFIX_DELEGATION = "true" WARM_PREFIX_TARGET = "1" } })}
vpc-cni.tf
EKS is giving you the CNI as part of the cluster/node setup, but Terraform has no dedicated block you can configure yet.
- EKS gave me an CNI, but Terraform had no dedicated block yet..
aws eks list-nodegroups \ --cluster-name say-when-east \ --region us-east-1 aws eks update-nodegroup-version \ --cluster-name say-when-east \ --nodegroup-name <NODEGROUP_NAME> \ --region us-east-1 aws eks update-nodegroup-version \ --cluster-name say-when-east \ --nodegroup-name default-20260817193826579400000012 \ --region us-east-1
Temporary Nodegroup added, cuz did not want to terraform destroy.. cuz it takes too long:
kubectl get nodes \
-L eks.amazonaws.com/nodegroup \
-o custom-columns='NAME:.metadata.name,NODEGROUP:.metadata.labels.eks\.amazonaws\.com/nodegroup,TYPE:.metadata.labels.node\.kubernetes\.io/instance-type,MAXPODS:.status.allocatable.pods'
NAME NODEGROUP TYPE MAXPODS
ip-10-0-1-110.ec2.internal default-20260817193826579400000012 t4g.small 11
ip-10-0-1-164.ec2.internal default-20260817193826579400000012 t4g.small 11
ip-10-0-1-209.ec2.internal prefix-20260817212214558700000007 t4g.small 110
ip-10-0-1-217.ec2.internal default-20260817193826579400000012 t4g.small 11
ip-10-0-1-231.ec2.internal prefix-20260817212214558700000007 t4g.small 110
ip-10-0-1-242.ec2.internal prefix-20260817212214558700000007 t4g.small 110
ip-10-0-2-133.ec2.internal prefix-20260817212214558700000007 t4g.small 110
ip-10-0-2-81.ec2.internal default-20260817193826579400000012 t4g.small 11
Prometheus Still OutOfSync:
- Admission webhook validates & mutates Prometheus Operator custom resource’s, helpful but not required.

prometheusOperator: admissionWebhooks: enabled: false patch: enabled: false
kubectl annotate application kube-prometheus-stack -n argocd \ argocd.argoproj.io/refresh=hard --overwriteapplication.argoproj.io/kube-prometheus-stack annotated

- Then change the https://github.com/earpjennings37/say_when_infra/blob/main/eks.tf to what it was & go back to 3 nodes.
