|
2 | 2 |
|
3 | 3 | You are helping a user deploy EKS observability using this Terraform repository. |
4 | 4 | Your job is to guide them through deployment conversationally — gather the info |
5 | | -you need, pick the right example, run Terraform, and hand them working dashboard URLs. |
| 5 | +you need, provision prerequisites, run Terraform, and hand them working dashboard URLs. |
6 | 6 |
|
7 | 7 | ## Repository Structure |
8 | 8 |
|
9 | 9 | ``` |
10 | 10 | modules/eks-monitoring/ # Core module — all profiles |
11 | 11 | examples/ |
12 | | - eks-cloudwatch-otlp/ # CloudWatch OTLP (recommended, self-contained) |
| 12 | + eks-cluster-with-vpc/ # Prereq: create an EKS cluster + VPC |
| 13 | + managed-grafana-workspace/ # Prereq: create a Grafana workspace + API token |
| 14 | + eks-cloudwatch-otlp/ # CloudWatch OTLP via OTel Collector (public-ready) |
13 | 15 | eks-amp-managed/ # AMP with managed collector (agentless) |
14 | 16 | eks-amp-otel/ # AMP with self-managed OTel Collector |
15 | | - eks-cluster-with-vpc/ # Helper: create an EKS cluster |
16 | | - managed-grafana-workspace/ # Helper: create a Grafana workspace |
17 | 17 | dashboards/ |
18 | | - original/ # Standard Prometheus/AMP dashboards |
19 | | - zeus/ # Zeus (CloudWatch OTLP) dashboards |
| 18 | + original/ # Standard Prometheus dashboards (AMP + OTel→CW OTLP) |
| 19 | + zeus/ # Container Insights dashboards (CW Agent, not public yet) |
20 | 20 | scripts/ |
21 | | - zeus-dashboard-transform.py # Converts original → Zeus dashboards |
| 21 | + zeus-dashboard-transform.py # Converts original → zeus dashboards |
22 | 22 | ``` |
23 | 23 |
|
24 | 24 | ## Collector Profiles |
25 | 25 |
|
26 | | -The `eks-monitoring` module supports three profiles via `collector_profile`: |
| 26 | +| Profile | Collector | Backend | Example | Status | |
| 27 | +|---------|-----------|---------|---------|--------| |
| 28 | +| `cloudwatch-otlp` | OTel Collector (Helm) | CloudWatch OTLP endpoint | `eks-cloudwatch-otlp/` | Public-ready (dashboards need work) | |
| 29 | +| `managed-metrics` | AMP Managed Scraper (agentless) | AMP | `eks-amp-managed/` | Public-ready | |
| 30 | +| `self-managed-amp` | OTel Collector (Helm) | AMP | `eks-amp-otel/` | Public-ready | |
| 31 | +| `cloudwatch-container-insights` | CW Agent / EKS add-on | CloudWatch | — | **Parked** — waiting for public chart/add-on GA | |
27 | 32 |
|
28 | | -| Profile | Backend | Collector | Best for | |
29 | | -|---------|---------|-----------|----------| |
30 | | -| `cloudwatch-otlp` | CloudWatch (Zeus) | CloudWatch Agent (Helm) | New deployments, no AMP needed | |
31 | | -| `managed-metrics` | AMP | AWS Managed Collector (agentless) | Zero collector management | |
32 | | -| `self-managed-amp` | AMP | OTel Collector (Helm) | Full control over collector config | |
| 33 | +### Profile details |
33 | 34 |
|
34 | | -**Recommendation: `cloudwatch-otlp`** — simplest path, no AMP workspace needed, |
35 | | -metrics queryable via CloudWatch PromQL endpoint in Grafana. Deploys the Amazon |
36 | | -CloudWatch Observability Helm chart which bundles the CW Agent DaemonSet, |
37 | | -Fluent Bit, kube-state-metrics, node-exporter, and a cluster scraper. |
| 35 | +**`cloudwatch-otlp`** (recommended for CloudWatch users) |
| 36 | +- Deploys OTel Collector scraping kube-state-metrics, node-exporter, kubelet |
| 37 | +- Exports to CloudWatch OTLP metrics endpoint via SigV4 auth |
| 38 | +- Endpoint is configurable: defaults to `https://monitoring.<region>.amazonaws.com/v1/metrics` |
| 39 | + but can be overridden via `cloudwatch_metrics_endpoint` for internal/pre-release testing |
| 40 | +- Uses `original/` dashboards with a CloudWatch PromQL datasource |
| 41 | +- IRSA role needs `cloudwatch:PutMetricData` |
38 | 42 |
|
39 | | -## Deployment Workflow |
| 43 | +**`managed-metrics`** (recommended for AMP users wanting zero management) |
| 44 | +- AMP managed scraper — no in-cluster collector to manage |
| 45 | +- Requires at least 2 subnets in 2 AZs |
| 46 | +- Uses `original/` dashboards with an AMP datasource |
40 | 47 |
|
41 | | -### Step 1: Gather Information |
| 48 | +**`self-managed-amp`** (full control) |
| 49 | +- OTel Collector with AMP remote write, optional X-Ray traces + CW Logs |
| 50 | +- IRSA role with AMP, X-Ray, and CW Logs policies |
| 51 | +- Uses `original/` dashboards with an AMP datasource |
42 | 52 |
|
43 | | -Ask the user for (or look up via AWS CLI): |
| 53 | +**`cloudwatch-container-insights`** (NOT YET PUBLIC) |
| 54 | +- Amazon CloudWatch Observability Helm chart (CW Agent DaemonSet, Fluent Bit, |
| 55 | + kube-state-metrics, node-exporter, cluster scraper) |
| 56 | +- Chart `amazon-cloudwatch-observability` is not yet in a public Helm repo |
| 57 | +- Will eventually become an EKS add-on (`aws_eks_addon` resource) |
| 58 | +- Uses `zeus/` dashboards |
| 59 | +- **Do not use for public examples** — dependencies are pending |
44 | 60 |
|
45 | | -1. **AWS Region** — where to deploy (default: `us-west-2`) |
46 | | -2. **EKS Cluster Name** — must already exist with at least one managed node group |
47 | | - - Check: `aws eks list-clusters --region <region>` |
48 | | -3. **Profile choice** — recommend `cloudwatch-otlp` unless they specifically need AMP |
49 | | -4. **Existing Grafana workspace?** — the `eks-cloudwatch-otlp` example creates one automatically |
| 61 | +--- |
50 | 62 |
|
51 | | -If the user doesn't have an EKS cluster, point them to `examples/eks-cluster-with-vpc/`. |
| 63 | +## Deployment Playbook |
52 | 64 |
|
53 | | -### Step 2: Deploy (CloudWatch OTLP — recommended) |
| 65 | +Follow these steps in order. Each step checks whether the resource exists |
| 66 | +before creating it. |
54 | 67 |
|
55 | | -```bash |
56 | | -cd examples/eks-cloudwatch-otlp |
| 68 | +### Step 0: Gather Information |
57 | 69 |
|
58 | | -# Option A: One-command install (recommended) |
59 | | -./install.sh -var="eks_cluster_id=<CLUSTER>" -var="aws_region=<REGION>" |
| 70 | +Ask the user for: |
60 | 71 |
|
61 | | -# Option B: Manual two-step |
62 | | -terraform init |
63 | | -terraform apply -var="eks_cluster_id=<CLUSTER>" -var="aws_region=<REGION>" |
| 72 | +1. **AWS Region** (default: `us-east-1`) |
| 73 | +2. **Profile choice** — recommend `cloudwatch-otlp` for CloudWatch, `managed-metrics` for AMP |
64 | 74 |
|
65 | | -# Then provision dashboards: |
66 | | -terraform apply \ |
67 | | - -var="eks_cluster_id=<CLUSTER>" \ |
68 | | - -var="aws_region=<REGION>" \ |
69 | | - -var="grafana_endpoint=$(terraform output -raw grafana_workspace_endpoint)" \ |
70 | | - -var="grafana_api_key=$(terraform output -raw grafana_api_key)" |
| 75 | +Then check what already exists: |
| 76 | + |
| 77 | +```bash |
| 78 | +# Existing EKS clusters |
| 79 | +aws eks list-clusters --region <REGION> |
| 80 | + |
| 81 | +# Existing Grafana workspaces |
| 82 | +aws grafana list-workspaces --region <REGION> \ |
| 83 | + --query 'workspaces[*].{name:name,id:id,endpoint:endpoint,status:status}' |
71 | 84 | ``` |
72 | 85 |
|
73 | | -For pre-release testing with a local chart build: |
| 86 | +Ask the user: |
| 87 | +- Do you have an EKS cluster to use, or should I create one? |
| 88 | +- Do you have a Grafana workspace, or should I create one? (optional — dashboards can be skipped) |
| 89 | + |
| 90 | +### Step 1: EKS Cluster (if needed) |
| 91 | + |
| 92 | +If the user has no cluster, provision one: |
| 93 | + |
74 | 94 | ```bash |
75 | | -./install.sh \ |
76 | | - -var="eks_cluster_id=<CLUSTER>" \ |
77 | | - -var="aws_region=<REGION>" \ |
78 | | - -var="cw_agent_chart_path=/path/to/cloudwatch-agent/helm/amazon-cloudwatch-observability" |
| 95 | +cd examples/eks-cluster-with-vpc |
| 96 | +terraform init |
| 97 | +terraform apply -var="cluster_name=<NAME>" -var="aws_region=<REGION>" |
79 | 98 | ``` |
80 | 99 |
|
81 | | -### Step 3: Hand Over Results |
| 100 | +This creates: |
| 101 | +- VPC with private/public subnets and NAT gateway |
| 102 | +- EKS cluster with `t3.medium` managed node group |
| 103 | +- Node IAM roles with `CloudWatchAgentServerPolicy` + `AmazonEC2ContainerRegistryReadOnly` |
82 | 104 |
|
83 | | -After successful apply, give the user: |
| 105 | +After completion: |
84 | 106 |
|
85 | | -1. **Grafana URL**: `terraform output grafana_workspace_endpoint` |
86 | | -2. **Dashboards available**: |
87 | | - - Cluster overview |
88 | | - - Kubelet metrics |
89 | | - - Node metrics |
90 | | - - Node Exporter metrics |
91 | | - - Namespace Workloads |
92 | | - - Workloads |
93 | | -3. **Note**: User must log in via AWS IAM Identity Center (SSO) to access Grafana |
| 107 | +```bash |
| 108 | +aws eks update-kubeconfig --name $(terraform output -raw eks_cluster_id) --region <REGION> |
| 109 | +``` |
94 | 110 |
|
95 | | -### Step 4: Verify Data Flow |
| 111 | +### Step 2: Grafana Workspace (if needed, optional) |
| 112 | + |
| 113 | +If the user wants dashboards and has no workspace: |
96 | 114 |
|
97 | 115 | ```bash |
98 | | -# Check CloudWatch Agent pods are running |
99 | | -kubectl get pods -n amazon-cloudwatch |
| 116 | +cd examples/managed-grafana-workspace |
| 117 | +terraform init |
| 118 | +terraform apply -var="aws_region=<REGION>" |
| 119 | +``` |
100 | 120 |
|
101 | | -# Verify the DaemonSet is healthy |
102 | | -kubectl get daemonset -n amazon-cloudwatch |
| 121 | +**Requires**: AWS IAM Identity Center (SSO) configured in the account. |
103 | 122 |
|
104 | | -# Check Fluent Bit pods |
105 | | -kubectl get pods -n amazon-cloudwatch -l app.kubernetes.io/name=fluent-bit |
| 123 | +Record the outputs: |
| 124 | +```bash |
| 125 | +GRAFANA_ENDPOINT=$(terraform output -raw grafana_workspace_endpoint) |
| 126 | +GRAFANA_API_KEY=$(terraform output -raw grafana_api_key) |
106 | 127 | ``` |
107 | 128 |
|
108 | | -If metrics aren't showing in dashboards after 5 minutes, check CW Agent logs: |
| 129 | +If the user has an existing workspace but no API token: |
| 130 | + |
109 | 131 | ```bash |
110 | | -kubectl logs -n amazon-cloudwatch -l app.kubernetes.io/name=cloudwatch-agent --tail=50 |
| 132 | +SA_ID=$(aws grafana create-workspace-service-account \ |
| 133 | + --workspace-id <ID> --name terraform --grafana-role ADMIN \ |
| 134 | + --region <REGION> --query 'id' --output text) |
| 135 | + |
| 136 | +aws grafana create-workspace-service-account-token \ |
| 137 | + --workspace-id <ID> --service-account-id $SA_ID \ |
| 138 | + --name terraform-token --seconds-to-live 2592000 \ |
| 139 | + --region <REGION> |
111 | 140 | ``` |
112 | 141 |
|
113 | | -## Deploy with AMP (managed-metrics profile) |
| 142 | +### Step 3: Deploy Monitoring |
| 143 | + |
| 144 | +Write `terraform.tfvars` in the chosen example directory: |
114 | 145 |
|
115 | | -If the user wants AMP instead: |
| 146 | +```hcl |
| 147 | +eks_cluster_id = "<CLUSTER_NAME>" |
| 148 | +aws_region = "<REGION>" |
| 149 | +``` |
| 150 | + |
| 151 | +#### CloudWatch OTLP |
| 152 | + |
| 153 | +```bash |
| 154 | +cd examples/eks-cloudwatch-otlp |
| 155 | + |
| 156 | +# Without dashboards |
| 157 | +./install.sh |
| 158 | + |
| 159 | +# With dashboards |
| 160 | +./install.sh \ |
| 161 | + -var="grafana_endpoint=<ENDPOINT>" \ |
| 162 | + -var="grafana_api_key=<KEY>" |
| 163 | + |
| 164 | +# With custom OTLP endpoint (for internal testing) |
| 165 | +./install.sh \ |
| 166 | + -var="cloudwatch_metrics_endpoint=https://custom-endpoint.example.com/v1/metrics" |
| 167 | +``` |
| 168 | + |
| 169 | +#### AMP Managed Scraper |
116 | 170 |
|
117 | 171 | ```bash |
118 | 172 | cd examples/eks-amp-managed |
119 | 173 | terraform init |
| 174 | +terraform apply |
| 175 | +``` |
| 176 | + |
| 177 | +#### AMP Self-Managed OTel |
| 178 | + |
| 179 | +```bash |
| 180 | +cd examples/eks-amp-otel |
| 181 | +terraform init |
120 | 182 | terraform apply \ |
121 | | - -var="eks_cluster_id=<CLUSTER>" \ |
122 | | - -var="aws_region=<REGION>" |
| 183 | + -var="grafana_endpoint=<ENDPOINT>" \ |
| 184 | + -var="grafana_api_key=<KEY>" |
123 | 185 | ``` |
124 | 186 |
|
125 | | -This creates an AMP workspace + managed collector (agentless). Requires: |
126 | | -- At least 2 subnets in 2 AZs for the scraper |
127 | | -- Security groups allowing scraper → EKS API access |
| 187 | +### Step 4: Verify |
128 | 188 |
|
129 | | -## Configuration Reference |
| 189 | +```bash |
| 190 | +# For cloudwatch-otlp or self-managed-amp (OTel Collector) |
| 191 | +kubectl get pods -n otel-collector |
130 | 192 |
|
131 | | -### Key Variables (eks-monitoring module) |
| 193 | +# For managed-metrics (no in-cluster pods — check AMP scraper) |
| 194 | +aws amp list-scrapers --region <REGION> |
132 | 195 |
|
133 | | -| Variable | Default | Description | |
134 | | -|----------|---------|-------------| |
135 | | -| `collector_profile` | (required) | `cloudwatch-otlp`, `managed-metrics`, or `self-managed-amp` | |
136 | | -| `eks_cluster_id` | (required) | EKS cluster name | |
137 | | -| `cw_agent_chart_path` | `"amazon-cloudwatch-observability"` | Helm chart path/URL (cloudwatch-otlp) | |
138 | | -| `cw_agent_chart_version` | `"4.8.0"` | CW Agent chart version | |
139 | | -| `cw_agent_enable_container_logs` | `true` | Enable Fluent Bit logs | |
140 | | -| `cw_agent_enable_application_signals` | `false` | Enable auto-instrumentation | |
141 | | -| `cloudwatch_metrics_endpoint` | regional default | Override CloudWatch OTLP endpoint | |
142 | | -| `create_amp_workspace` | `true` | Create new AMP workspace (AMP profiles) | |
143 | | -| `enable_dashboards` | `true` | Provision Grafana dashboards | |
144 | | -| `enable_tracing` | `true` | Enable X-Ray traces pipeline (self-managed-amp) | |
145 | | -| `enable_logs` | `true` | Enable CloudWatch Logs pipeline (self-managed-amp) | |
| 196 | +# Check kube-state-metrics and node-exporter |
| 197 | +kubectl get pods -n kube-system -l app.kubernetes.io/name=kube-state-metrics |
| 198 | +kubectl get pods -n prometheus-node-exporter |
| 199 | +``` |
146 | 200 |
|
147 | | -### Key Outputs |
| 201 | +### Step 5: Hand Over Results |
148 | 202 |
|
149 | | -| Output | Description | |
150 | | -|--------|-------------| |
151 | | -| `grafana_workspace_endpoint` | Grafana URL (eks-cloudwatch-otlp example) | |
152 | | -| `cw_agent_namespace` | CW Agent Kubernetes namespace | |
153 | | -| `cloudwatch_promql_datasource_config` | Grafana datasource connection details | |
154 | | -| `collector_irsa_arn` | OTel Collector IAM role ARN (self-managed-amp) | |
155 | | -| `managed_prometheus_workspace_endpoint` | AMP endpoint (AMP profiles) | |
| 203 | +Give the user: |
156 | 204 |
|
157 | | -## IAM Notes |
| 205 | +1. **Grafana URL** (if provisioned) — log in via AWS IAM Identity Center (SSO) |
| 206 | +2. **Dashboards**: Cluster, Kubelet, Nodes, Node Exporter, Namespace Workloads, Workloads |
| 207 | +3. **Collector namespace**: `otel-collector` (OTel profiles) or check AMP scraper (managed) |
158 | 208 |
|
159 | | -- **cloudwatch-otlp**: The CW Agent gets permissions from the EKS node IAM role |
160 | | - (`CloudWatchAgentServerPolicy`). The example attaches this automatically. |
161 | | - Future: switch to Pod Identity when the upstream EKS add-on supports Zeus. |
162 | | -- **self-managed-amp**: Uses IRSA (IAM Roles for Service Accounts) for the |
163 | | - OTel Collector with AMP remote write, X-Ray, and CloudWatch Logs policies. |
164 | | -- **managed-metrics**: No in-cluster IAM needed — the managed scraper uses |
165 | | - its own service-linked role. |
| 209 | +--- |
166 | 210 |
|
167 | 211 | ## Cleanup |
168 | 212 |
|
| 213 | +Destroy in reverse order: |
| 214 | + |
169 | 215 | ```bash |
170 | | -terraform destroy -var="eks_cluster_id=<CLUSTER>" -var="aws_region=<REGION>" |
| 216 | +# Monitoring |
| 217 | +cd examples/eks-cloudwatch-otlp # or eks-amp-managed, eks-amp-otel |
| 218 | +./destroy.sh # or terraform destroy |
| 219 | + |
| 220 | +# Grafana (if created) |
| 221 | +cd ../managed-grafana-workspace |
| 222 | +terraform destroy -var="aws_region=<REGION>" |
| 223 | + |
| 224 | +# Cluster (if created) |
| 225 | +cd ../eks-cluster-with-vpc |
| 226 | +terraform destroy -var="aws_region=<REGION>" |
171 | 227 | ``` |
172 | 228 |
|
| 229 | +--- |
| 230 | + |
| 231 | +## Key Variables (eks-monitoring module) |
| 232 | + |
| 233 | +| Variable | Default | Description | |
| 234 | +|----------|---------|-------------| |
| 235 | +| `collector_profile` | (required) | `cloudwatch-otlp`, `managed-metrics`, or `self-managed-amp` | |
| 236 | +| `eks_cluster_id` | (required) | EKS cluster name | |
| 237 | +| `cloudwatch_metrics_endpoint` | regional default | Override CloudWatch OTLP endpoint URL | |
| 238 | +| `create_amp_workspace` | `true` | Create new AMP workspace (AMP profiles) | |
| 239 | +| `enable_dashboards` | `true` | Provision Grafana dashboards | |
| 240 | +| `enable_tracing` | `true` | Enable X-Ray traces (self-managed-amp) | |
| 241 | +| `enable_logs` | `true` | Enable CloudWatch Logs (self-managed-amp) | |
| 242 | + |
| 243 | +## IAM Notes |
| 244 | + |
| 245 | +- **cloudwatch-otlp**: IRSA role with `cloudwatch:PutMetricData` for the OTel Collector |
| 246 | +- **self-managed-amp**: IRSA role with AMP remote write, X-Ray, and CW Logs policies |
| 247 | +- **managed-metrics**: No in-cluster IAM — managed scraper uses its own service-linked role |
| 248 | + |
173 | 249 | ## Troubleshooting |
174 | 250 |
|
175 | 251 | | Symptom | Cause | Fix | |
176 | 252 | |---------|-------|-----| |
177 | | -| No metrics in Grafana | CW Agent not running | `kubectl get pods -n amazon-cloudwatch` | |
178 | | -| 504 timeout on Grafana datasource | SigV4 auth misconfigured | Check Grafana workspace IAM role has CloudWatch read permissions | |
179 | | -| Dashboards show "No data" | Metrics not yet ingested | Wait 5 min, check CW Agent logs | |
180 | | -| CW Agent CrashLoopBackOff | Missing IAM permissions | Verify `CloudWatchAgentServerPolicy` is on the node role | |
181 | | -| Helm install fails | Chart not found | Check `cw_agent_chart_path` points to a valid chart | |
| 253 | +| No metrics in Grafana | Collector not running | Check pods in collector namespace | |
| 254 | +| 504 on Grafana datasource | SigV4 auth misconfigured | Check Grafana workspace IAM role | |
| 255 | +| Dashboards show "No data" | Metrics not yet ingested | Wait 5 min, check collector logs | |
| 256 | +| OTel Collector CrashLoopBackOff | Missing IRSA permissions | Check IAM role trust policy and policies | |
| 257 | +| ECR image pull errors | Missing ECR policy | Verify `AmazonEC2ContainerRegistryReadOnly` on node role | |
| 258 | +| AMP scraper not collecting | Network access | Check security groups allow scraper → EKS API | |
0 commit comments