Skip to content

Commit c252f47

Browse files
committed
refactor: Split cloudwatch-otlp to use OTel Collector, park CW Agent for future
- cloudwatch-otlp profile now deploys OTel Collector exporting to CloudWatch OTLP endpoint via SigV4 prometheusremotewrite, with configurable endpoint for internal testing - Park CW Agent helm release behind is_container_insights flag (future cloudwatch-container-insights profile, pending public chart/EKS add-on GA) - IRSA role for cloudwatch-otlp uses CloudWatchAgentServerPolicy - Modernize eks-cluster-with-vpc example (EKS module v21, K8s 1.35, t3.medium, ECR + CloudWatch IAM policies on node roles) - Extend managed-grafana-workspace with service account + API token output for downstream examples - Refactor eks-cloudwatch-otlp example to take Grafana endpoint/key as inputs (prereqs) instead of creating workspace inline - Add destroy.sh, simplify install.sh to single-phase apply - Update AGENT.md with 4-profile architecture and deployment playbook
1 parent c7aee17 commit c252f47

22 files changed

Lines changed: 553 additions & 653 deletions

File tree

AGENT.md

Lines changed: 186 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -2,180 +2,257 @@
22

33
You are helping a user deploy EKS observability using this Terraform repository.
44
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.
66

77
## Repository Structure
88

99
```
1010
modules/eks-monitoring/ # Core module — all profiles
1111
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)
1315
eks-amp-managed/ # AMP with managed collector (agentless)
1416
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
1717
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)
2020
scripts/
21-
zeus-dashboard-transform.py # Converts original → Zeus dashboards
21+
zeus-dashboard-transform.py # Converts original → zeus dashboards
2222
```
2323

2424
## Collector Profiles
2525

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 |
2732

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
3334

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`
3842

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
4047

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
4252

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
4460

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+
---
5062

51-
If the user doesn't have an EKS cluster, point them to `examples/eks-cluster-with-vpc/`.
63+
## Deployment Playbook
5264

53-
### Step 2: Deploy (CloudWatch OTLP — recommended)
65+
Follow these steps in order. Each step checks whether the resource exists
66+
before creating it.
5467

55-
```bash
56-
cd examples/eks-cloudwatch-otlp
68+
### Step 0: Gather Information
5769

58-
# Option A: One-command install (recommended)
59-
./install.sh -var="eks_cluster_id=<CLUSTER>" -var="aws_region=<REGION>"
70+
Ask the user for:
6071

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
6474

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}'
7184
```
7285

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+
7494
```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>"
7998
```
8099

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`
82104

83-
After successful apply, give the user:
105+
After completion:
84106

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+
```
94110

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:
96114

97115
```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+
```
100120

101-
# Verify the DaemonSet is healthy
102-
kubectl get daemonset -n amazon-cloudwatch
121+
**Requires**: AWS IAM Identity Center (SSO) configured in the account.
103122

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)
106127
```
107128

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+
109131
```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>
111140
```
112141

113-
## Deploy with AMP (managed-metrics profile)
142+
### Step 3: Deploy Monitoring
143+
144+
Write `terraform.tfvars` in the chosen example directory:
114145

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
116170

117171
```bash
118172
cd examples/eks-amp-managed
119173
terraform init
174+
terraform apply
175+
```
176+
177+
#### AMP Self-Managed OTel
178+
179+
```bash
180+
cd examples/eks-amp-otel
181+
terraform init
120182
terraform apply \
121-
-var="eks_cluster_id=<CLUSTER>" \
122-
-var="aws_region=<REGION>"
183+
-var="grafana_endpoint=<ENDPOINT>" \
184+
-var="grafana_api_key=<KEY>"
123185
```
124186

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
128188

129-
## Configuration Reference
189+
```bash
190+
# For cloudwatch-otlp or self-managed-amp (OTel Collector)
191+
kubectl get pods -n otel-collector
130192

131-
### Key Variables (eks-monitoring module)
193+
# For managed-metrics (no in-cluster pods — check AMP scraper)
194+
aws amp list-scrapers --region <REGION>
132195

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+
```
146200

147-
### Key Outputs
201+
### Step 5: Hand Over Results
148202

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:
156204

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)
158208

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+
---
166210

167211
## Cleanup
168212

213+
Destroy in reverse order:
214+
169215
```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>"
171227
```
172228

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+
173249
## Troubleshooting
174250

175251
| Symptom | Cause | Fix |
176252
|---------|-------|-----|
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

Comments
 (0)