@intentius/chant-lexicon-k8s 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/integrity.json +17 -15
- package/dist/manifest.json +1 -1
- package/dist/skills/chant-k8s-eks.md +156 -0
- package/dist/skills/chant-k8s-patterns.md +245 -0
- package/dist/skills/chant-k8s.md +36 -227
- package/package.json +2 -2
- package/src/codegen/docs.ts +4 -4
- package/src/composites/adot-collector.ts +239 -0
- package/src/composites/alb-ingress.ts +151 -0
- package/src/composites/autoscaled-service.ts +33 -0
- package/src/composites/batch-job.ts +188 -0
- package/src/composites/composites.test.ts +883 -0
- package/src/composites/configured-app.ts +218 -0
- package/src/composites/ebs-storage-class.ts +96 -0
- package/src/composites/efs-storage-class.ts +77 -0
- package/src/composites/external-dns-agent.ts +168 -0
- package/src/composites/fluent-bit-agent.ts +215 -0
- package/src/composites/index.ts +28 -0
- package/src/composites/irsa-service-account.ts +114 -0
- package/src/composites/metrics-server.ts +224 -0
- package/src/composites/monitored-service.ts +215 -0
- package/src/composites/network-isolated-app.ts +196 -0
- package/src/composites/secure-ingress.ts +149 -0
- package/src/composites/sidecar-app.ts +201 -0
- package/src/composites/stateful-app.ts +70 -15
- package/src/composites/web-app.ts +107 -35
- package/src/composites/worker-pool.ts +41 -4
- package/src/index.ts +19 -2
- package/src/plugin.ts +552 -241
package/dist/skills/chant-k8s.md
CHANGED
|
@@ -126,20 +126,6 @@ kubectl port-forward pod/<pod-name> 8080:8080
|
|
|
126
126
|
| CreateContainerError | Container config issue | `kubectl describe pod` → Events | Check volume mounts, configmap/secret refs, security context |
|
|
127
127
|
| Init:CrashLoopBackOff | Init container failing | `kubectl logs -c <init-container>` | Fix init container command, check dependencies |
|
|
128
128
|
|
|
129
|
-
### Resource inspection
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
# Get all resources in namespace
|
|
133
|
-
kubectl get all -n <namespace>
|
|
134
|
-
|
|
135
|
-
# YAML output for debugging
|
|
136
|
-
kubectl get deployment/my-app -o yaml
|
|
137
|
-
|
|
138
|
-
# Check resource usage
|
|
139
|
-
kubectl top pods -l app.kubernetes.io/name=my-app
|
|
140
|
-
kubectl top nodes
|
|
141
|
-
```
|
|
142
|
-
|
|
143
129
|
## Production safety
|
|
144
130
|
|
|
145
131
|
### Pre-apply validation
|
|
@@ -155,22 +141,6 @@ kubectl apply -f manifests.yaml --dry-run=server
|
|
|
155
141
|
kubectl apply -f manifests.yaml --dry-run=client
|
|
156
142
|
```
|
|
157
143
|
|
|
158
|
-
### Rollback
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
# Check rollout history
|
|
162
|
-
kubectl rollout history deployment/my-app
|
|
163
|
-
|
|
164
|
-
# Undo last rollout
|
|
165
|
-
kubectl rollout undo deployment/my-app
|
|
166
|
-
|
|
167
|
-
# Roll back to a specific revision
|
|
168
|
-
kubectl rollout undo deployment/my-app --to-revision=2
|
|
169
|
-
|
|
170
|
-
# Watch rollout progress
|
|
171
|
-
kubectl rollout status deployment/my-app --timeout=300s
|
|
172
|
-
```
|
|
173
|
-
|
|
174
144
|
### Deployment strategies
|
|
175
145
|
|
|
176
146
|
- **RollingUpdate** (default): Gradually replaces pods. Set `maxSurge` and `maxUnavailable`.
|
|
@@ -178,157 +148,42 @@ kubectl rollout status deployment/my-app --timeout=300s
|
|
|
178
148
|
- **Canary**: Deploy a second Deployment with 1 replica + same selector labels. Route percentage via Ingress annotations or service mesh.
|
|
179
149
|
- **Blue/Green**: Two full Deployments (blue/green), switch Service selector between them.
|
|
180
150
|
|
|
181
|
-
##
|
|
182
|
-
|
|
183
|
-
Composites are higher-level functions that produce multiple coordinated K8s resources from a single call. They return plain prop objects — not class instances
|
|
184
|
-
|
|
185
|
-
###
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
const { cronJob, serviceAccount, role, roleBinding } = CronWorkload({
|
|
219
|
-
name: "db-backup",
|
|
220
|
-
image: "postgres:16",
|
|
221
|
-
schedule: "0 2 * * *",
|
|
222
|
-
command: ["pg_dump", "-h", "postgres", "mydb"],
|
|
223
|
-
rbacRules: [{ apiGroups: [""], resources: ["secrets"], verbs: ["get"] }],
|
|
224
|
-
});
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### AutoscaledService — Deployment + Service + HPA + PDB
|
|
228
|
-
|
|
229
|
-
Production HTTP service with autoscaling, health probes, and optional topology spreading.
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
import { AutoscaledService } from "@intentius/chant-lexicon-k8s";
|
|
233
|
-
|
|
234
|
-
const { deployment, service, hpa, pdb } = AutoscaledService({
|
|
235
|
-
name: "api",
|
|
236
|
-
image: "api:2.0",
|
|
237
|
-
port: 8080,
|
|
238
|
-
maxReplicas: 10,
|
|
239
|
-
minReplicas: 3,
|
|
240
|
-
cpuRequest: "200m",
|
|
241
|
-
memoryRequest: "256Mi",
|
|
242
|
-
cpuLimit: "1",
|
|
243
|
-
memoryLimit: "1Gi",
|
|
244
|
-
// Probe paths — defaults: /healthz and /readyz
|
|
245
|
-
livenessPath: "/healthz",
|
|
246
|
-
readinessPath: "/readyz",
|
|
247
|
-
// Zone-aware topology spreading (default: false)
|
|
248
|
-
topologySpread: true,
|
|
249
|
-
// Custom: topologySpread: { maxSkew: 2, topologyKey: "kubernetes.io/hostname" }
|
|
250
|
-
});
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
Key features:
|
|
254
|
-
- **Probe paths**: `livenessPath` (default `/healthz`) and `readinessPath` (default `/readyz`) — override for apps that don't serve those routes
|
|
255
|
-
- **Topology spread**: `topologySpread: true` adds zone-aware spreading (maxSkew=1, DoNotSchedule); pass an object for custom key/skew
|
|
256
|
-
- **PDB minAvailable**: accepts number or string percentage (e.g., `"50%"`)
|
|
257
|
-
|
|
258
|
-
### WorkerPool — Deployment + RBAC + optional ConfigMap + optional HPA
|
|
259
|
-
|
|
260
|
-
Background queue workers with optional RBAC and autoscaling.
|
|
261
|
-
|
|
262
|
-
```typescript
|
|
263
|
-
import { WorkerPool } from "@intentius/chant-lexicon-k8s";
|
|
264
|
-
|
|
265
|
-
const { deployment, serviceAccount, role, roleBinding, configMap, hpa } = WorkerPool({
|
|
266
|
-
name: "email-worker",
|
|
267
|
-
image: "worker:1.0",
|
|
268
|
-
command: ["bundle", "exec", "sidekiq"],
|
|
269
|
-
config: { REDIS_URL: "redis://redis:6379", QUEUE: "emails" },
|
|
270
|
-
autoscaling: { minReplicas: 2, maxReplicas: 20, targetCPUPercent: 60 },
|
|
271
|
-
});
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
Key features:
|
|
275
|
-
- **RBAC opt-out**: Pass `rbacRules: []` to skip ServiceAccount/Role/RoleBinding creation entirely. Omitting `rbacRules` (undefined) creates default rules for secrets/configmaps.
|
|
276
|
-
- `serviceAccount`, `role`, `roleBinding` are optional in the result — check before use
|
|
277
|
-
|
|
278
|
-
### NamespaceEnv — Namespace + ResourceQuota + LimitRange + NetworkPolicy
|
|
279
|
-
|
|
280
|
-
Multi-tenant namespace provisioning with resource guardrails and network isolation.
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
import { NamespaceEnv } from "@intentius/chant-lexicon-k8s";
|
|
284
|
-
|
|
285
|
-
const { namespace, resourceQuota, limitRange, networkPolicy } = NamespaceEnv({
|
|
286
|
-
name: "team-alpha",
|
|
287
|
-
cpuQuota: "8",
|
|
288
|
-
memoryQuota: "16Gi",
|
|
289
|
-
maxPods: 50,
|
|
290
|
-
defaultCpuRequest: "100m",
|
|
291
|
-
defaultMemoryRequest: "128Mi",
|
|
292
|
-
defaultCpuLimit: "500m",
|
|
293
|
-
defaultMemoryLimit: "512Mi",
|
|
294
|
-
defaultDenyIngress: true,
|
|
295
|
-
defaultDenyEgress: true,
|
|
296
|
-
});
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
Key features:
|
|
300
|
-
- **Quota-without-limits warning**: Setting ResourceQuota without LimitRange defaults emits a warning — pods without explicit resource requests will fail to schedule
|
|
301
|
-
- **Network policies**: `defaultDenyIngress` (default true), `defaultDenyEgress` (default false) — can be combined or used individually
|
|
302
|
-
|
|
303
|
-
### NodeAgent — DaemonSet + ServiceAccount + ClusterRole + ClusterRoleBinding + optional ConfigMap
|
|
304
|
-
|
|
305
|
-
Per-node agents (log collectors, security scanners, monitoring exporters).
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
import { NodeAgent } from "@intentius/chant-lexicon-k8s";
|
|
309
|
-
|
|
310
|
-
const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = NodeAgent({
|
|
311
|
-
name: "log-collector",
|
|
312
|
-
image: "fluentd:v1.16",
|
|
313
|
-
port: 24224,
|
|
314
|
-
hostPaths: [
|
|
315
|
-
{ name: "varlog", hostPath: "/var/log", mountPath: "/var/log" },
|
|
316
|
-
],
|
|
317
|
-
config: { "fluent.conf": "..." },
|
|
318
|
-
rbacRules: [{ apiGroups: [""], resources: ["pods", "namespaces"], verbs: ["get", "list", "watch"] }],
|
|
319
|
-
cpuRequest: "50m", // default: 50m
|
|
320
|
-
memoryRequest: "64Mi", // default: 64Mi
|
|
321
|
-
cpuLimit: "200m", // default: 200m
|
|
322
|
-
memoryLimit: "128Mi", // default: 128Mi
|
|
323
|
-
namespace: "monitoring",
|
|
324
|
-
});
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
Key features:
|
|
328
|
-
- **Container resources**: Always set with sensible defaults (50m/64Mi requests, 200m/128Mi limits) — override per-agent
|
|
329
|
-
- **Host paths**: Mounted read-only by default; set `readOnly: false` to enable writes
|
|
330
|
-
- **Tolerations**: `tolerateAllTaints: true` (default) ensures agent runs on every node
|
|
331
|
-
- Uses **ClusterRole/ClusterRoleBinding** (cluster-scoped) for node-level access
|
|
151
|
+
## Choosing the Right Composite
|
|
152
|
+
|
|
153
|
+
Composites are higher-level functions that produce multiple coordinated K8s resources from a single call. They return plain prop objects — not class instances.
|
|
154
|
+
|
|
155
|
+
### Decision Tree
|
|
156
|
+
|
|
157
|
+
| Need | Composite | Resources |
|
|
158
|
+
|------|-----------|-----------|
|
|
159
|
+
| Stateless web app | **WebApp** | Deployment + Service + optional Ingress + optional PDB |
|
|
160
|
+
| Stateful database/cache | **StatefulApp** | StatefulSet + headless Service + PVC + optional PDB |
|
|
161
|
+
| Production HTTP service with autoscaling | **AutoscaledService** | Deployment + Service + HPA + PDB |
|
|
162
|
+
| Background queue workers | **WorkerPool** | Deployment + RBAC + optional ConfigMap + optional HPA + optional PDB |
|
|
163
|
+
| Scheduled jobs | **CronWorkload** | CronJob + RBAC |
|
|
164
|
+
| One-shot batch jobs | **BatchJob** | Job + optional RBAC |
|
|
165
|
+
| App with ConfigMap/Secret mounts | **ConfiguredApp** | Deployment + Service + optional ConfigMap |
|
|
166
|
+
| Multi-container sidecar patterns | **SidecarApp** | Deployment + Service |
|
|
167
|
+
| App with Prometheus monitoring | **MonitoredService** | Deployment + Service + ServiceMonitor + optional PrometheusRule |
|
|
168
|
+
| App with fine-grained network policies | **NetworkIsolatedApp** | Deployment + Service + NetworkPolicy |
|
|
169
|
+
| Namespace with quotas and isolation | **NamespaceEnv** | Namespace + ResourceQuota + LimitRange + NetworkPolicy |
|
|
170
|
+
| Per-node agent (custom) | **NodeAgent** | DaemonSet + RBAC + optional ConfigMap |
|
|
171
|
+
| Multi-host TLS Ingress (cert-manager) | **SecureIngress** | Ingress + optional Certificate |
|
|
172
|
+
| EKS IRSA ServiceAccount | **IrsaServiceAccount** | ServiceAccount + optional RBAC |
|
|
173
|
+
| AWS ALB Ingress | **AlbIngress** | Ingress with ALB annotations |
|
|
174
|
+
| EBS StorageClass | **EbsStorageClass** | StorageClass (ebs.csi.aws.com) |
|
|
175
|
+
| EFS StorageClass | **EfsStorageClass** | StorageClass (efs.csi.aws.com) |
|
|
176
|
+
| Fluent Bit for CloudWatch | **FluentBitAgent** | DaemonSet + RBAC + ConfigMap |
|
|
177
|
+
| ExternalDNS for Route53 | **ExternalDnsAgent** | Deployment + IRSA SA + ClusterRole |
|
|
178
|
+
| ADOT for CloudWatch/X-Ray | **AdotCollector** | DaemonSet + RBAC + ConfigMap |
|
|
179
|
+
|
|
180
|
+
### Hardening options (available on Deployment-based composites)
|
|
181
|
+
|
|
182
|
+
- `minAvailable` — creates a PodDisruptionBudget (WebApp, StatefulApp, WorkerPool; AutoscaledService always has one)
|
|
183
|
+
- `initContainers` — run before main containers (WebApp, StatefulApp, AutoscaledService, ConfiguredApp, SidecarApp)
|
|
184
|
+
- `securityContext` — container security settings (WebApp, StatefulApp, AutoscaledService, WorkerPool)
|
|
185
|
+
- `terminationGracePeriodSeconds` — graceful shutdown (WebApp, StatefulApp, AutoscaledService, WorkerPool)
|
|
186
|
+
- `priorityClassName` — pod scheduling priority (WebApp, StatefulApp, AutoscaledService, WorkerPool)
|
|
332
187
|
|
|
333
188
|
### Common patterns across all composites
|
|
334
189
|
|
|
@@ -337,49 +192,6 @@ Key features:
|
|
|
337
192
|
- Pass `namespace: "prod"` to set namespace on all namespaced resources
|
|
338
193
|
- Pass `env: [{ name: "KEY", value: "val" }]` for container environment variables
|
|
339
194
|
|
|
340
|
-
## Namespace management
|
|
341
|
-
|
|
342
|
-
Use the **NamespaceEnv** composite (above) to manage namespaces declaratively. For manual kubectl management:
|
|
343
|
-
|
|
344
|
-
```bash
|
|
345
|
-
# Create namespace
|
|
346
|
-
kubectl create namespace my-project
|
|
347
|
-
|
|
348
|
-
# Set default resource quotas
|
|
349
|
-
kubectl apply -f - <<EOF
|
|
350
|
-
apiVersion: v1
|
|
351
|
-
kind: ResourceQuota
|
|
352
|
-
metadata:
|
|
353
|
-
name: default-quota
|
|
354
|
-
namespace: my-project
|
|
355
|
-
spec:
|
|
356
|
-
hard:
|
|
357
|
-
requests.cpu: "4"
|
|
358
|
-
requests.memory: 8Gi
|
|
359
|
-
limits.cpu: "8"
|
|
360
|
-
limits.memory: 16Gi
|
|
361
|
-
pods: "20"
|
|
362
|
-
EOF
|
|
363
|
-
|
|
364
|
-
# Set default container limits via LimitRange
|
|
365
|
-
kubectl apply -f - <<EOF
|
|
366
|
-
apiVersion: v1
|
|
367
|
-
kind: LimitRange
|
|
368
|
-
metadata:
|
|
369
|
-
name: default-limits
|
|
370
|
-
namespace: my-project
|
|
371
|
-
spec:
|
|
372
|
-
limits:
|
|
373
|
-
- default:
|
|
374
|
-
cpu: 500m
|
|
375
|
-
memory: 256Mi
|
|
376
|
-
defaultRequest:
|
|
377
|
-
cpu: 100m
|
|
378
|
-
memory: 128Mi
|
|
379
|
-
type: Container
|
|
380
|
-
EOF
|
|
381
|
-
```
|
|
382
|
-
|
|
383
195
|
## Troubleshooting reference table
|
|
384
196
|
|
|
385
197
|
| Symptom | Likely cause | Resolution |
|
|
@@ -388,11 +200,8 @@ EOF
|
|
|
388
200
|
| Pod stuck in Pending | PVC not bound | Check StorageClass exists, PV available |
|
|
389
201
|
| Pod stuck in Pending | Node selector/affinity mismatch | Verify node labels match selectors |
|
|
390
202
|
| Pod stuck in ContainerCreating | ConfigMap/Secret not found | Ensure referenced ConfigMaps/Secrets exist |
|
|
391
|
-
| Pod stuck in ContainerCreating | Volume mount failure | Check PVC status, CSI driver health |
|
|
392
203
|
| Service returns 503 | No ready endpoints | Check pod readiness probes, selector match |
|
|
393
|
-
| Service returns 503 | Wrong port configuration | Verify targetPort matches containerPort |
|
|
394
204
|
| Ingress returns 404 | Backend service not found | Check Ingress rules, service name/port |
|
|
395
|
-
| Ingress returns 404 | Wrong path matching | Check pathType (Prefix vs Exact) |
|
|
396
205
|
| HPA not scaling | Metrics server not installed | Install metrics-server |
|
|
397
206
|
| HPA not scaling | Resource requests not set | Add CPU/memory requests to containers |
|
|
398
207
|
| CronJob not running | Invalid cron expression | Validate cron syntax (5-field format) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": ["src/", "dist/"],
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"prepack": "bun run generate && bun run bundle && bun run validate"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@intentius/chant": "0.0.
|
|
25
|
+
"@intentius/chant": "0.0.13"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.9.3"
|
package/src/codegen/docs.ts
CHANGED
|
@@ -18,7 +18,7 @@ function serviceFromType(resourceType: string): string {
|
|
|
18
18
|
|
|
19
19
|
const overview = `The **Kubernetes** lexicon provides typed constructors for Kubernetes resource
|
|
20
20
|
manifests. It covers Deployments, Services, ConfigMaps, StatefulSets, Jobs,
|
|
21
|
-
Ingress, RBAC, and
|
|
21
|
+
Ingress, RBAC, and 147 resources and 50 property types.
|
|
22
22
|
|
|
23
23
|
New? Start with the [Getting Started](/chant/lexicons/k8s/getting-started/) guide.
|
|
24
24
|
|
|
@@ -64,7 +64,7 @@ export const service = new Service({
|
|
|
64
64
|
});
|
|
65
65
|
\`\`\`
|
|
66
66
|
|
|
67
|
-
The lexicon provides **
|
|
67
|
+
The lexicon provides **147 resource types** (Deployment, Service, ConfigMap, StatefulSet, and more), **50 property types** (Container, Probe, Volume, SecurityContext, etc.), and composites (WebApp, StatefulApp, CronWorkload, AutoscaledService, WorkerPool, NamespaceEnv, NodeAgent) for common patterns.
|
|
68
68
|
`;
|
|
69
69
|
|
|
70
70
|
const outputFormat = `The Kubernetes lexicon serializes resources into **multi-document YAML** with
|
|
@@ -76,7 +76,7 @@ structure: \`apiVersion\`, \`kind\`, \`metadata\`, and \`spec\`.
|
|
|
76
76
|
Run \`chant build\` to produce Kubernetes manifests from your declarations:
|
|
77
77
|
|
|
78
78
|
\`\`\`bash
|
|
79
|
-
chant build
|
|
79
|
+
chant build src/ --output dist/manifests.yaml
|
|
80
80
|
# Writes dist/manifests.yaml
|
|
81
81
|
\`\`\`
|
|
82
82
|
|
|
@@ -134,7 +134,7 @@ export async function generateDocs(opts?: { verbose?: boolean }): Promise<void>
|
|
|
134
134
|
overview,
|
|
135
135
|
outputFormat,
|
|
136
136
|
serviceFromType,
|
|
137
|
-
suppressPages: ["pseudo-parameters"],
|
|
137
|
+
suppressPages: ["pseudo-parameters", "rules"],
|
|
138
138
|
extraPages: [
|
|
139
139
|
{
|
|
140
140
|
slug: "getting-started",
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdotCollector composite — DaemonSet + RBAC + ConfigMap for AWS Distro for OpenTelemetry.
|
|
3
|
+
*
|
|
4
|
+
* @eks ADOT collector for CloudWatch and X-Ray. NodeAgent specialization
|
|
5
|
+
* with pre-configured pipelines for AWS observability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export interface AdotCollectorProps {
|
|
9
|
+
/** AWS region. */
|
|
10
|
+
region: string;
|
|
11
|
+
/** EKS cluster name. */
|
|
12
|
+
clusterName: string;
|
|
13
|
+
/** Exporters to enable (default: ["cloudwatch", "xray"]). */
|
|
14
|
+
exporters?: ("cloudwatch" | "xray" | "prometheus")[];
|
|
15
|
+
/** Agent name (default: "adot-collector"). */
|
|
16
|
+
name?: string;
|
|
17
|
+
/** ADOT image (default: "public.ecr.aws/aws-observability/aws-otel-collector:latest"). */
|
|
18
|
+
image?: string;
|
|
19
|
+
/** Namespace (default: "amazon-metrics"). */
|
|
20
|
+
namespace?: string;
|
|
21
|
+
/** Additional labels. */
|
|
22
|
+
labels?: Record<string, string>;
|
|
23
|
+
/** CPU request (default: "100m"). */
|
|
24
|
+
cpuRequest?: string;
|
|
25
|
+
/** Memory request (default: "256Mi"). */
|
|
26
|
+
memoryRequest?: string;
|
|
27
|
+
/** CPU limit (default: "500m"). */
|
|
28
|
+
cpuLimit?: string;
|
|
29
|
+
/** Memory limit (default: "512Mi"). */
|
|
30
|
+
memoryLimit?: string;
|
|
31
|
+
/** IAM Role ARN for IRSA (adds eks.amazonaws.com/role-arn annotation to ServiceAccount). */
|
|
32
|
+
iamRoleArn?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AdotCollectorResult {
|
|
36
|
+
daemonSet: Record<string, unknown>;
|
|
37
|
+
serviceAccount: Record<string, unknown>;
|
|
38
|
+
clusterRole: Record<string, unknown>;
|
|
39
|
+
clusterRoleBinding: Record<string, unknown>;
|
|
40
|
+
configMap: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create an AdotCollector composite — returns prop objects for
|
|
45
|
+
* a DaemonSet, ServiceAccount, ClusterRole, ClusterRoleBinding, and ConfigMap.
|
|
46
|
+
*
|
|
47
|
+
* @eks
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { AdotCollector } from "@intentius/chant-lexicon-k8s";
|
|
51
|
+
*
|
|
52
|
+
* const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding, configMap } = AdotCollector({
|
|
53
|
+
* region: "us-east-1",
|
|
54
|
+
* clusterName: "my-cluster",
|
|
55
|
+
* exporters: ["cloudwatch", "xray"],
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function AdotCollector(props: AdotCollectorProps): AdotCollectorResult {
|
|
60
|
+
const {
|
|
61
|
+
region,
|
|
62
|
+
clusterName,
|
|
63
|
+
exporters = ["cloudwatch", "xray"],
|
|
64
|
+
name = "adot-collector",
|
|
65
|
+
image = "public.ecr.aws/aws-observability/aws-otel-collector:latest",
|
|
66
|
+
namespace = "amazon-metrics",
|
|
67
|
+
labels: extraLabels = {},
|
|
68
|
+
cpuRequest = "100m",
|
|
69
|
+
memoryRequest = "256Mi",
|
|
70
|
+
cpuLimit = "500m",
|
|
71
|
+
memoryLimit = "512Mi",
|
|
72
|
+
iamRoleArn,
|
|
73
|
+
} = props;
|
|
74
|
+
|
|
75
|
+
const saName = `${name}-sa`;
|
|
76
|
+
const clusterRoleName = `${name}-role`;
|
|
77
|
+
const bindingName = `${name}-binding`;
|
|
78
|
+
const configMapName = `${name}-config`;
|
|
79
|
+
|
|
80
|
+
const commonLabels: Record<string, string> = {
|
|
81
|
+
"app.kubernetes.io/name": name,
|
|
82
|
+
"app.kubernetes.io/managed-by": "chant",
|
|
83
|
+
...extraLabels,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Build ADOT config YAML
|
|
87
|
+
const exporterConfigs: string[] = [];
|
|
88
|
+
const exporterNames: string[] = [];
|
|
89
|
+
|
|
90
|
+
if (exporters.includes("cloudwatch")) {
|
|
91
|
+
exporterConfigs.push(` awsemf:
|
|
92
|
+
region: ${region}
|
|
93
|
+
namespace: ContainerInsights
|
|
94
|
+
log_group_name: '/aws/containerinsights/${clusterName}/performance'
|
|
95
|
+
dimension_rollup_option: NoDimensionRollup`);
|
|
96
|
+
exporterNames.push("awsemf");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (exporters.includes("xray")) {
|
|
100
|
+
exporterConfigs.push(` awsxray:
|
|
101
|
+
region: ${region}`);
|
|
102
|
+
exporterNames.push("awsxray");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (exporters.includes("prometheus")) {
|
|
106
|
+
exporterConfigs.push(` prometheusremotewrite:
|
|
107
|
+
endpoint: http://prometheus:9090/api/v1/write`);
|
|
108
|
+
exporterNames.push("prometheusremotewrite");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const adotConfig = `receivers:
|
|
112
|
+
otlp:
|
|
113
|
+
protocols:
|
|
114
|
+
grpc:
|
|
115
|
+
endpoint: 0.0.0.0:4317
|
|
116
|
+
http:
|
|
117
|
+
endpoint: 0.0.0.0:4318
|
|
118
|
+
|
|
119
|
+
processors:
|
|
120
|
+
batch:
|
|
121
|
+
timeout: 30s
|
|
122
|
+
send_batch_size: 8192
|
|
123
|
+
|
|
124
|
+
exporters:
|
|
125
|
+
${exporterConfigs.join("\n")}
|
|
126
|
+
|
|
127
|
+
service:
|
|
128
|
+
pipelines:
|
|
129
|
+
metrics:
|
|
130
|
+
receivers: [otlp]
|
|
131
|
+
processors: [batch]
|
|
132
|
+
exporters: [${exporterNames.join(", ")}]
|
|
133
|
+
traces:
|
|
134
|
+
receivers: [otlp]
|
|
135
|
+
processors: [batch]
|
|
136
|
+
exporters: [${exporterNames.filter((e) => e !== "awsemf").join(", ") || "awsxray"}]
|
|
137
|
+
`;
|
|
138
|
+
|
|
139
|
+
const container: Record<string, unknown> = {
|
|
140
|
+
name,
|
|
141
|
+
image,
|
|
142
|
+
command: ["--config=/etc/adot/config.yaml"],
|
|
143
|
+
ports: [
|
|
144
|
+
{ containerPort: 4317, name: "otlp-grpc" },
|
|
145
|
+
{ containerPort: 4318, name: "otlp-http" },
|
|
146
|
+
],
|
|
147
|
+
resources: {
|
|
148
|
+
requests: { cpu: cpuRequest, memory: memoryRequest },
|
|
149
|
+
limits: { cpu: cpuLimit, memory: memoryLimit },
|
|
150
|
+
},
|
|
151
|
+
volumeMounts: [
|
|
152
|
+
{ name: "config", mountPath: "/etc/adot", readOnly: true },
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const daemonSetProps: Record<string, unknown> = {
|
|
157
|
+
metadata: {
|
|
158
|
+
name,
|
|
159
|
+
namespace,
|
|
160
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
|
|
161
|
+
},
|
|
162
|
+
spec: {
|
|
163
|
+
selector: { matchLabels: { "app.kubernetes.io/name": name } },
|
|
164
|
+
template: {
|
|
165
|
+
metadata: { labels: { "app.kubernetes.io/name": name, ...extraLabels } },
|
|
166
|
+
spec: {
|
|
167
|
+
serviceAccountName: saName,
|
|
168
|
+
containers: [container],
|
|
169
|
+
volumes: [
|
|
170
|
+
{ name: "config", configMap: { name: configMapName } },
|
|
171
|
+
],
|
|
172
|
+
tolerations: [{ operator: "Exists" }],
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const serviceAccountProps: Record<string, unknown> = {
|
|
179
|
+
metadata: {
|
|
180
|
+
name: saName,
|
|
181
|
+
namespace,
|
|
182
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "agent" },
|
|
183
|
+
...(iamRoleArn ? { annotations: { "eks.amazonaws.com/role-arn": iamRoleArn } } : {}),
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const clusterRoleProps: Record<string, unknown> = {
|
|
188
|
+
metadata: {
|
|
189
|
+
name: clusterRoleName,
|
|
190
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
191
|
+
},
|
|
192
|
+
rules: [
|
|
193
|
+
{ apiGroups: [""], resources: ["pods", "nodes", "endpoints"], verbs: ["get", "list", "watch"] },
|
|
194
|
+
{ apiGroups: ["apps"], resources: ["replicasets"], verbs: ["get", "list", "watch"] },
|
|
195
|
+
{ apiGroups: ["batch"], resources: ["jobs"], verbs: ["get", "list", "watch"] },
|
|
196
|
+
{ apiGroups: [""], resources: ["nodes/proxy"], verbs: ["get"] },
|
|
197
|
+
{ apiGroups: [""], resources: ["nodes/stats", "configmaps", "events"], verbs: ["create", "get"] },
|
|
198
|
+
{ apiGroups: [""], resources: ["configmaps"], verbs: ["get", "update", "create"], resourceNames: ["otel-container-insight-clusterleader"] },
|
|
199
|
+
],
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const clusterRoleBindingProps: Record<string, unknown> = {
|
|
203
|
+
metadata: {
|
|
204
|
+
name: bindingName,
|
|
205
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "rbac" },
|
|
206
|
+
},
|
|
207
|
+
roleRef: {
|
|
208
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
209
|
+
kind: "ClusterRole",
|
|
210
|
+
name: clusterRoleName,
|
|
211
|
+
},
|
|
212
|
+
subjects: [
|
|
213
|
+
{
|
|
214
|
+
kind: "ServiceAccount",
|
|
215
|
+
name: saName,
|
|
216
|
+
namespace,
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const configMapProps: Record<string, unknown> = {
|
|
222
|
+
metadata: {
|
|
223
|
+
name: configMapName,
|
|
224
|
+
namespace,
|
|
225
|
+
labels: { ...commonLabels, "app.kubernetes.io/component": "config" },
|
|
226
|
+
},
|
|
227
|
+
data: {
|
|
228
|
+
"config.yaml": adotConfig,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
daemonSet: daemonSetProps,
|
|
234
|
+
serviceAccount: serviceAccountProps,
|
|
235
|
+
clusterRole: clusterRoleProps,
|
|
236
|
+
clusterRoleBinding: clusterRoleBindingProps,
|
|
237
|
+
configMap: configMapProps,
|
|
238
|
+
};
|
|
239
|
+
}
|