@intentius/chant-lexicon-k8s 0.0.22 → 0.1.0

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.
Files changed (54) hide show
  1. package/dist/integrity.json +9 -4
  2. package/dist/manifest.json +1 -1
  3. package/dist/skills/chant-k8s-aks.md +146 -0
  4. package/{src/skills/kubernetes-patterns.md → dist/skills/chant-k8s-deployment-strategies.md} +1 -1
  5. package/dist/skills/chant-k8s-eks.md +156 -0
  6. package/dist/skills/chant-k8s-gke.md +246 -0
  7. package/{src/skills/kubernetes-security.md → dist/skills/chant-k8s-security.md} +1 -1
  8. package/dist/skills/chant-k8s.md +65 -2
  9. package/package.json +5 -4
  10. package/src/composites/adot-collector.ts +34 -22
  11. package/src/composites/agic-ingress.ts +14 -6
  12. package/src/composites/aks-external-dns-agent.ts +29 -18
  13. package/src/composites/alb-ingress.ts +14 -6
  14. package/src/composites/autoscaled-service.ts +25 -20
  15. package/src/composites/azure-disk-storage-class.ts +14 -6
  16. package/src/composites/azure-file-storage-class.ts +14 -6
  17. package/src/composites/azure-monitor-collector.ts +34 -22
  18. package/src/composites/batch-job.ts +25 -17
  19. package/src/composites/cockroachdb-cluster.ts +164 -58
  20. package/src/composites/composites.test.ts +371 -365
  21. package/src/composites/config-connector-context.ts +18 -11
  22. package/src/composites/configured-app.ts +21 -15
  23. package/src/composites/cron-workload.ts +25 -20
  24. package/src/composites/ebs-storage-class.ts +14 -6
  25. package/src/composites/efs-storage-class.ts +14 -6
  26. package/src/composites/external-dns-agent.ts +26 -20
  27. package/src/composites/filestore-storage-class.ts +14 -6
  28. package/src/composites/fluent-bit-agent.ts +30 -24
  29. package/src/composites/gce-ingress.ts +14 -6
  30. package/src/composites/gce-pd-storage-class.ts +14 -6
  31. package/src/composites/gke-external-dns-agent.ts +34 -21
  32. package/src/composites/gke-fluent-bit-agent.ts +34 -22
  33. package/src/composites/gke-gateway.ts +19 -12
  34. package/src/composites/gke-otel-collector.ts +34 -22
  35. package/src/composites/irsa-service-account.ts +22 -14
  36. package/src/composites/metrics-server.ts +41 -26
  37. package/src/composites/monitored-service.ts +26 -19
  38. package/src/composites/namespace-env.ts +26 -17
  39. package/src/composites/network-isolated-app.ts +21 -16
  40. package/src/composites/node-agent.ts +33 -22
  41. package/src/composites/secure-ingress.ts +19 -11
  42. package/src/composites/sidecar-app.ts +17 -12
  43. package/src/composites/stateful-app.ts +21 -12
  44. package/src/composites/web-app.ts +25 -21
  45. package/src/composites/worker-pool.ts +40 -26
  46. package/src/composites/workload-identity-sa.ts +22 -14
  47. package/src/composites/workload-identity-service-account.ts +22 -16
  48. package/src/plugin.ts +40 -614
  49. package/src/serializer.ts +7 -0
  50. package/src/skills/chant-k8s-deployment-strategies.md +183 -0
  51. package/src/skills/chant-k8s-gke.md +56 -1
  52. package/src/skills/chant-k8s-patterns.md +245 -0
  53. package/src/skills/chant-k8s-security.md +237 -0
  54. package/src/skills/chant-k8s.md +305 -0
package/src/serializer.ts CHANGED
@@ -88,6 +88,13 @@ const API_GROUP_VERSIONS: Record<string, string> = {
88
88
  Storage: "storage.k8s.io/v1",
89
89
  Autoscaling: "autoscaling/v2",
90
90
  Admissionregistration: "admissionregistration.k8s.io/v1",
91
+ GKE: "cloud.google.com/v1",
92
+ NetworkingGKE: "networking.gke.io/v1",
93
+ NetworkingGKEBeta: "networking.gke.io/v1beta1",
94
+ // Common Kubernetes operator CRDs
95
+ CertManager: "cert-manager.io/v1",
96
+ ExternalSecrets: "external-secrets.io/v1",
97
+ Monitoring: "monitoring.coreos.com/v1",
91
98
  };
92
99
 
93
100
  function deriveGVKFromType(entityType: string): { apiVersion: string; kind: string } | null {
@@ -0,0 +1,183 @@
1
+ ---
2
+ skill: chant-k8s-deployment-strategies
3
+ description: Kubernetes deployment strategies, stateful workloads, RBAC, and networking patterns
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Kubernetes Infrastructure Patterns
8
+
9
+ ## Deployment Strategies
10
+
11
+ ### Rolling Update (default)
12
+
13
+ Gradually replaces pods with zero downtime. Configure surge and unavailability:
14
+
15
+ ```typescript
16
+ import { WebApp } from "@intentius/chant-lexicon-k8s";
17
+
18
+ const { deployment, service } = WebApp({
19
+ name: "api",
20
+ image: "api:2.0",
21
+ replicas: 4,
22
+ strategy: {
23
+ type: "RollingUpdate",
24
+ rollingUpdate: { maxSurge: "25%", maxUnavailable: "25%" },
25
+ },
26
+ });
27
+ ```
28
+
29
+ ### Blue/Green Deployment
30
+
31
+ Run two full deployments and switch traffic by updating the Service selector:
32
+
33
+ ```typescript
34
+ import { WebApp } from "@intentius/chant-lexicon-k8s";
35
+
36
+ const blue = WebApp({ name: "app-blue", image: "app:1.0", replicas: 3 });
37
+ const green = WebApp({ name: "app-green", image: "app:2.0", replicas: 3 });
38
+
39
+ // Switch traffic: update the Service selector to point at green
40
+ // kubectl patch svc app -p '{"spec":{"selector":{"version":"green"}}}'
41
+ ```
42
+
43
+ ### Canary Deployment
44
+
45
+ Deploy a small replica set alongside the main deployment to test new versions:
46
+
47
+ ```typescript
48
+ import { AutoscaledService, WebApp } from "@intentius/chant-lexicon-k8s";
49
+
50
+ const main = AutoscaledService({
51
+ name: "app",
52
+ image: "app:1.0",
53
+ port: 8080,
54
+ minReplicas: 9,
55
+ maxReplicas: 20,
56
+ });
57
+
58
+ const canary = WebApp({
59
+ name: "app-canary",
60
+ image: "app:2.0",
61
+ replicas: 1,
62
+ labels: { track: "canary" },
63
+ });
64
+ ```
65
+
66
+ Both share the same `app.kubernetes.io/name` label so the Service routes traffic to both.
67
+
68
+ ## Stateful Workloads
69
+
70
+ ### StatefulSet with Persistent Storage
71
+
72
+ Use `StatefulApp` for databases, caches, and other stateful services:
73
+
74
+ ```typescript
75
+ import { StatefulApp } from "@intentius/chant-lexicon-k8s";
76
+
77
+ const { statefulSet, service } = StatefulApp({
78
+ name: "postgres",
79
+ image: "postgres:16",
80
+ port: 5432,
81
+ replicas: 3,
82
+ storageSize: "50Gi",
83
+ storageClass: "gp3-encrypted",
84
+ env: [
85
+ { name: "POSTGRES_DB", value: "app" },
86
+ { name: "POSTGRES_PASSWORD", valueFrom: { secretKeyRef: { name: "pg-creds", key: "password" } } },
87
+ ],
88
+ });
89
+ ```
90
+
91
+ ### Headless Service for StatefulSet Discovery
92
+
93
+ `StatefulApp` creates a headless Service (`clusterIP: None`) automatically. Pods are addressable as `postgres-0.postgres.namespace.svc.cluster.local`.
94
+
95
+ ### PersistentVolumeClaim Retention
96
+
97
+ StatefulSet PVCs persist after pod deletion by default. To clean up:
98
+
99
+ ```bash
100
+ kubectl delete pvc -l app.kubernetes.io/name=postgres
101
+ ```
102
+
103
+ ## RBAC Patterns
104
+
105
+ ### Least-Privilege ServiceAccount
106
+
107
+ Use `WorkerPool` or `BatchJob` composites which create scoped RBAC automatically:
108
+
109
+ ```typescript
110
+ import { WorkerPool } from "@intentius/chant-lexicon-k8s";
111
+
112
+ const { deployment, serviceAccount, role, roleBinding } = WorkerPool({
113
+ name: "queue-worker",
114
+ image: "worker:1.0",
115
+ replicas: 3,
116
+ rbacRules: [
117
+ { apiGroups: [""], resources: ["configmaps"], verbs: ["get", "list"] },
118
+ { apiGroups: ["batch"], resources: ["jobs"], verbs: ["create"] },
119
+ ],
120
+ });
121
+ ```
122
+
123
+ ### Namespace-Scoped vs Cluster-Scoped
124
+
125
+ - Use `Role` + `RoleBinding` for namespace-scoped permissions (default in composites)
126
+ - Use `ClusterRole` + `ClusterRoleBinding` for cross-namespace access (node agents, monitoring)
127
+
128
+ ```typescript
129
+ import { NodeAgent } from "@intentius/chant-lexicon-k8s";
130
+
131
+ const { daemonSet, serviceAccount, clusterRole, clusterRoleBinding } = NodeAgent({
132
+ name: "log-agent",
133
+ image: "fluent-bit:2.2",
134
+ rbacRules: [
135
+ { apiGroups: [""], resources: ["pods", "namespaces"], verbs: ["get", "list", "watch"] },
136
+ ],
137
+ });
138
+ ```
139
+
140
+ ## Networking Patterns
141
+
142
+ ### Default-Deny with Selective Allow
143
+
144
+ Use `NamespaceEnv` for namespace-level isolation, then `NetworkIsolatedApp` for per-app rules:
145
+
146
+ ```typescript
147
+ import { NamespaceEnv, NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
148
+
149
+ const ns = NamespaceEnv({
150
+ name: "prod",
151
+ defaultDenyIngress: true,
152
+ defaultDenyEgress: true,
153
+ cpuLimit: "8",
154
+ memoryLimit: "16Gi",
155
+ });
156
+
157
+ const app = NetworkIsolatedApp({
158
+ name: "api",
159
+ image: "api:1.0",
160
+ port: 8080,
161
+ namespace: "prod",
162
+ allowIngressFrom: [
163
+ { podSelector: { "app.kubernetes.io/name": "gateway" } },
164
+ ],
165
+ allowEgressTo: [
166
+ { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
167
+ ],
168
+ });
169
+ ```
170
+
171
+ ### Service Mesh (Istio/Linkerd)
172
+
173
+ For mTLS between services, use a sidecar-injected namespace:
174
+
175
+ ```bash
176
+ kubectl label namespace prod istio-injection=enabled
177
+ ```
178
+
179
+ Then deploy with standard composites. The mesh proxy is injected automatically.
180
+
181
+ ### DNS-Based Service Discovery
182
+
183
+ Services are discoverable at `<service>.<namespace>.svc.cluster.local`. For headless services (StatefulSets), individual pods are at `<pod>.<service>.<namespace>.svc.cluster.local`.
@@ -119,6 +119,12 @@ const result = GkeExternalDnsAgent({
119
119
  });
120
120
  ```
121
121
 
122
+ **Props:** `gcpServiceAccountEmail` (required), `gcpProjectId` (required), `domainFilters` (required), `txtOwnerId?`, `source?` (string or string[], default: `"service"`), `name?` (default: `"external-dns"`), `namespace?` (default: `"kube-system"`), `image?` (default: `"registry.k8s.io/external-dns/external-dns:v0.14.2"`), `labels?`, `defaults?`
123
+
124
+ **Returns:** `{ deployment, serviceAccount, clusterRole, clusterRoleBinding }`
125
+
126
+ To watch both Services and Ingresses, pass `source: ["service", "ingress"]`.
127
+
122
128
  ### GkeFluentBitAgent — DaemonSet for Cloud Logging
123
129
 
124
130
  ```typescript
@@ -143,6 +149,55 @@ const result = GkeOtelCollector({
143
149
  });
144
150
  ```
145
151
 
152
+ ### CockroachDbCluster — multi-node CockroachDB StatefulSet
153
+
154
+ ```typescript
155
+ import { CockroachDbCluster } from "@intentius/chant-lexicon-k8s";
156
+
157
+ const crdb = CockroachDbCluster({
158
+ name: "cockroachdb",
159
+ namespace: "crdb-east",
160
+ replicas: 3,
161
+ image: "cockroachdb/cockroach:v24.3.4",
162
+ storageSize: "100Gi",
163
+ storageClassName: "pd-ssd",
164
+ cpuLimit: "2",
165
+ memoryLimit: "8Gi",
166
+ locality: "region=us-east1,zone=us-east1-b",
167
+ joinAddresses: ["cockroachdb-0.east.crdb.example.com", "cockroachdb-0.west.crdb.example.com"],
168
+ secure: true,
169
+ skipInit: false, // true on non-bootstrapping regions
170
+ skipCertGen: true, // true when certs are provisioned externally
171
+ advertiseHostDomain: "east.crdb.example.com",
172
+ extraCertNodeAddresses: [
173
+ "cockroachdb-0.east.crdb.example.com",
174
+ "cockroachdb-1.east.crdb.example.com",
175
+ "cockroachdb-2.east.crdb.example.com",
176
+ ],
177
+ });
178
+
179
+ export const {
180
+ serviceAccount, role, roleBinding, clusterRole, clusterRoleBinding,
181
+ publicService, headlessService, pdb, statefulSet,
182
+ initJob, // only when skipInit: false
183
+ certGenJob, // only when skipCertGen: false
184
+ } = crdb;
185
+ ```
186
+
187
+ **Key props:**
188
+ - `secure` — enables TLS node-to-node and client comms (default: `false`)
189
+ - `skipInit` — skip `cockroach init`; set `true` on all regions except the one that bootstraps the cluster
190
+ - `skipCertGen` — skip cert generation Job; use when certs are managed externally (e.g. `generate-certs.sh`)
191
+ - `advertiseHostDomain` — hostname suffix CockroachDB advertises to peers; must resolve via ExternalDNS or similar
192
+ - `extraCertNodeAddresses` — SANs added to node certs for cross-region RPC; list all pod FQDNs that peers will dial
193
+ - `locality` — CockroachDB locality string (`region=...,zone=...`); used for data placement and rebalancing
194
+ - `joinAddresses` — seed peer addresses used at startup; include one node from each region
195
+
196
+ **`defaults`** allow deep-merging arbitrary fields onto any generated resource:
197
+ - `defaults.serviceAccount` — e.g. add `iam.gke.io/gcp-service-account` annotation for Workload Identity
198
+ - `defaults.publicService` — e.g. add `cloud.google.com/backend-config` + `cloud.google.com/app-protocols` annotations for GCE Ingress
199
+ - `defaults.headlessService` — e.g. add `external-dns.alpha.kubernetes.io/hostname` for ExternalDNS registration
200
+
146
201
  ### ConfigConnectorContext — Config Connector namespace bootstrap
147
202
 
148
203
  ```typescript
@@ -151,7 +206,7 @@ import { ConfigConnectorContext } from "@intentius/chant-lexicon-k8s";
151
206
  const { context } = ConfigConnectorContext({
152
207
  googleServiceAccountEmail: "cc-sa@my-project.iam.gserviceaccount.com",
153
208
  namespace: "config-connector",
154
- stateIntoSpec: "absent",
209
+ stateIntoSpec: "Absent",
155
210
  });
156
211
  ```
157
212
 
@@ -0,0 +1,245 @@
1
+ ---
2
+ skill: chant-k8s-patterns
3
+ description: Advanced Kubernetes deployment patterns and composites
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Advanced Kubernetes Patterns
8
+
9
+ ## Sidecar Patterns
10
+
11
+ ### SidecarApp — multi-container Deployment
12
+
13
+ ```typescript
14
+ import { SidecarApp } from "@intentius/chant-lexicon-k8s";
15
+
16
+ // Envoy sidecar proxy
17
+ const { deployment, service } = SidecarApp({
18
+ name: "api",
19
+ image: "api:1.0",
20
+ port: 8080,
21
+ sidecars: [
22
+ {
23
+ name: "envoy",
24
+ image: "envoyproxy/envoy:v1.28",
25
+ ports: [{ containerPort: 9901, name: "admin" }],
26
+ resources: { requests: { cpu: "100m", memory: "128Mi" }, limits: { cpu: "200m", memory: "256Mi" } },
27
+ },
28
+ ],
29
+ initContainers: [
30
+ { name: "migrate", image: "api:1.0", command: ["python", "manage.py", "migrate"] },
31
+ ],
32
+ sharedVolumes: [{ name: "tmp", emptyDir: {} }],
33
+ });
34
+ ```
35
+
36
+ Common sidecar use cases:
37
+ - **Envoy proxy** — service mesh, mTLS, traffic management
38
+ - **Log forwarder** — Fluent Bit sidecar for app-specific log routing
39
+ - **Auth proxy** — OAuth2 Proxy for authentication
40
+ - **Config watcher** — reload config on ConfigMap changes
41
+
42
+ ## Config and Secret Mounting
43
+
44
+ ### ConfiguredApp — automatic volume wiring
45
+
46
+ ```typescript
47
+ import { ConfiguredApp } from "@intentius/chant-lexicon-k8s";
48
+
49
+ const { deployment, service, configMap } = ConfiguredApp({
50
+ name: "api",
51
+ image: "api:1.0",
52
+ port: 8080,
53
+ // Mount ConfigMap as volume
54
+ configData: { "app.conf": "key=value\nother=setting" },
55
+ configMountPath: "/etc/api",
56
+ // Mount existing Secret as volume
57
+ secretName: "api-creds",
58
+ secretMountPath: "/secrets",
59
+ // Inject as environment variables
60
+ envFrom: { secretRef: "api-env-secret", configMapRef: "api-env-config" },
61
+ // Run migrations before the app starts
62
+ initContainers: [
63
+ { name: "migrate", image: "api:1.0", command: ["./migrate.sh"] },
64
+ ],
65
+ });
66
+ ```
67
+
68
+ ### Volume patterns
69
+
70
+ | Pattern | Use Case | ConfiguredApp Props |
71
+ |---------|----------|---------------------|
72
+ | ConfigMap as file | Config files, templates | `configData` + `configMountPath` |
73
+ | Secret as file | TLS certs, credentials | `secretName` + `secretMountPath` |
74
+ | ConfigMap as env | Simple key-value config | `envFrom.configMapRef` |
75
+ | Secret as env | Database URLs, API keys | `envFrom.secretRef` |
76
+
77
+ ## TLS / cert-manager
78
+
79
+ ### SecureIngress — multi-host TLS with cert-manager
80
+
81
+ ```typescript
82
+ import { SecureIngress } from "@intentius/chant-lexicon-k8s";
83
+
84
+ const { ingress, certificate } = SecureIngress({
85
+ name: "app-ingress",
86
+ hosts: [
87
+ {
88
+ hostname: "api.example.com",
89
+ paths: [
90
+ { path: "/v1", serviceName: "api-v1", servicePort: 80 },
91
+ { path: "/v2", serviceName: "api-v2", servicePort: 80 },
92
+ ],
93
+ },
94
+ {
95
+ hostname: "admin.example.com",
96
+ paths: [{ path: "/", serviceName: "admin", servicePort: 80 }],
97
+ },
98
+ ],
99
+ clusterIssuer: "letsencrypt-prod",
100
+ ingressClassName: "nginx",
101
+ });
102
+ ```
103
+
104
+ Features:
105
+ - Multiple hosts and paths per Ingress
106
+ - Automatic cert-manager Certificate when `clusterIssuer` set
107
+ - TLS secret auto-provisioned by cert-manager
108
+
109
+ ### cert-manager setup (prerequisite)
110
+
111
+ ```bash
112
+ # Install cert-manager
113
+ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
114
+
115
+ # Create ClusterIssuer for Let's Encrypt
116
+ kubectl apply -f - <<EOF
117
+ apiVersion: cert-manager.io/v1
118
+ kind: ClusterIssuer
119
+ metadata:
120
+ name: letsencrypt-prod
121
+ spec:
122
+ acme:
123
+ server: https://acme-v02.api.letsencrypt.org/directory
124
+ email: admin@example.com
125
+ privateKeySecretRef:
126
+ name: letsencrypt-prod-key
127
+ solvers:
128
+ - http01:
129
+ ingress:
130
+ class: nginx
131
+ EOF
132
+ ```
133
+
134
+ ## Observability
135
+
136
+ ### MonitoredService — Prometheus monitoring
137
+
138
+ ```typescript
139
+ import { MonitoredService } from "@intentius/chant-lexicon-k8s";
140
+
141
+ const { deployment, service, serviceMonitor, prometheusRule } = MonitoredService({
142
+ name: "api",
143
+ image: "api:1.0",
144
+ port: 8080,
145
+ metricsPort: 9090,
146
+ metricsPath: "/metrics",
147
+ scrapeInterval: "15s",
148
+ alertRules: [
149
+ {
150
+ name: "HighErrorRate",
151
+ expr: 'rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05',
152
+ for: "5m",
153
+ severity: "critical",
154
+ annotations: { summary: "High error rate on {{ $labels.instance }}" },
155
+ },
156
+ {
157
+ name: "HighLatency",
158
+ expr: 'histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) > 1',
159
+ for: "10m",
160
+ severity: "warning",
161
+ },
162
+ ],
163
+ });
164
+ ```
165
+
166
+ ### Prerequisites
167
+
168
+ - Prometheus Operator installed (for ServiceMonitor/PrometheusRule CRDs)
169
+ - Prometheus configured to discover ServiceMonitors
170
+
171
+ ## Network Isolation
172
+
173
+ ### NetworkIsolatedApp — per-app firewall rules
174
+
175
+ ```typescript
176
+ import { NetworkIsolatedApp } from "@intentius/chant-lexicon-k8s";
177
+
178
+ const { deployment, service, networkPolicy } = NetworkIsolatedApp({
179
+ name: "api",
180
+ image: "api:1.0",
181
+ port: 8080,
182
+ allowIngressFrom: [
183
+ { podSelector: { "app.kubernetes.io/name": "frontend" } },
184
+ { namespaceSelector: { "kubernetes.io/metadata.name": "monitoring" } },
185
+ ],
186
+ allowEgressTo: [
187
+ { podSelector: { "app.kubernetes.io/name": "postgres" }, ports: [{ port: 5432 }] },
188
+ { podSelector: { "app.kubernetes.io/name": "redis" }, ports: [{ port: 6379 }] },
189
+ ],
190
+ });
191
+ ```
192
+
193
+ ### Combining with NamespaceEnv
194
+
195
+ Use NamespaceEnv for namespace-level default-deny, then NetworkIsolatedApp for per-app allow rules:
196
+
197
+ ```typescript
198
+ // Namespace: deny all by default
199
+ const ns = NamespaceEnv({ name: "prod", defaultDenyIngress: true, defaultDenyEgress: true });
200
+
201
+ // App: allow specific traffic
202
+ const app = NetworkIsolatedApp({
203
+ name: "api",
204
+ image: "api:1.0",
205
+ namespace: "prod",
206
+ allowIngressFrom: [{ podSelector: { "app.kubernetes.io/name": "gateway" } }],
207
+ allowEgressTo: [{ podSelector: { "app.kubernetes.io/name": "db" }, ports: [{ port: 5432 }] }],
208
+ });
209
+ ```
210
+
211
+ ## Blue/Green and Canary
212
+
213
+ These patterns use standard K8s resources — no special composite needed.
214
+
215
+ ### Blue/Green
216
+
217
+ ```typescript
218
+ // Two Deployments with different versions
219
+ const blue = WebApp({ name: "app-blue", image: "app:1.0", labels: { version: "blue" } });
220
+ const green = WebApp({ name: "app-green", image: "app:2.0", labels: { version: "green" } });
221
+
222
+ // Service points to active version — switch by changing selector
223
+ // Active: blue → green (update the Service selector)
224
+ ```
225
+
226
+ ### Canary
227
+
228
+ ```typescript
229
+ // Main deployment (90% traffic)
230
+ const main = AutoscaledService({ name: "app", image: "app:1.0", minReplicas: 9, maxReplicas: 20, ... });
231
+
232
+ // Canary deployment (10% traffic) — same app label, fewer replicas
233
+ const canary = WebApp({ name: "app-canary", image: "app:2.0", replicas: 1, labels: { track: "canary" } });
234
+ // Both share the same Service selector ("app.kubernetes.io/name": "app") for traffic splitting
235
+ ```
236
+
237
+ ## Gateway API (future direction)
238
+
239
+ Gateway API is the successor to Ingress. Key differences:
240
+ - **HTTPRoute** replaces Ingress rules
241
+ - **Gateway** replaces IngressClass
242
+ - Built-in traffic splitting, header matching, URL rewriting
243
+ - Currently in beta — use Ingress/SecureIngress/AlbIngress for production today
244
+
245
+ When Gateway API reaches GA, new composites will be added. For now, use CRD import if you need Gateway API resources.