div18 commited on
Commit
8cd4141
·
1 Parent(s): 0d2b52f

docs(deploy): add detailed architecture guide and update k8s workloads

Browse files

- Add AntiAtropos Architecture Guide explaining system design and Kubernetes concepts
- Document SRE agent operation loop and action effects on AWS EKS
- Explain telemetry flow from real cluster to agent via AMP and Prometheus
- Clarify three-layer scaling caps for cost control and safety limits
- Provide mapping of simulator nodes to real Kubernetes deployments
- Include comprehensive component listings for Hugging Face Spaces, AWS EKS, and managed services
- Describe simulator modes and cost implications of scaling actions
- Add ResourceQuota to prod-sre namespace limiting pods and resource usage
- Restructure and clean Kubernetes manifest for microservice deployments and services
- Enhance manifest comments for better understanding of workloads and scraping setup

deploy/aws/ARCHITECTURE.md ADDED
@@ -0,0 +1,361 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AntiAtropos Architecture Guide
2
+
3
+ A complete explanation of how AntiAtropos works across Hugging Face Spaces and AWS, written for someone who is technically strong but new to Kubernetes.
4
+
5
+ ---
6
+
7
+ ## The Big Picture
8
+
9
+ AntiAtropos trains AI agents to be Site Reliability Engineers (SREs). An SRE agent watches a simulated microservice cluster and decides when to scale services, reroute traffic, or shed load to keep things running smoothly.
10
+
11
+ The system is split across two platforms:
12
+
13
+ ```
14
+ Hugging Face Spaces AWS
15
+ ===================== ======================
16
+ The "brain" The "muscle"
17
+
18
+ AntiAtropos FastAPI server EKS (Kubernetes cluster)
19
+ - Runs the simulator - Runs the actual microservice pods
20
+ - Runs the SRE agent logic - The agent scales these pods
21
+ - Queries Prometheus for metrics - Prometheus Agent scrapes metrics
22
+ - Sends scale commands to K8s - Metrics flow to AMP
23
+ - Grafana (AMG) visualizes it all
24
+ ```
25
+
26
+ Why split? HF Spaces is free/cheap for running the Python server. AWS EKS is where the real infrastructure lives that the agent practices on.
27
+
28
+ ---
29
+
30
+ ## Kubernetes Concepts You Need
31
+
32
+ ### Pod
33
+
34
+ The smallest unit in Kubernetes. A pod is one or more containers that run together. In our case, each pod runs a single nginx container that simulates a microservice (like "payments" or "checkout").
35
+
36
+ Think of it as: one running instance of a service.
37
+
38
+ ### Deployment
39
+
40
+ A Deployment is a recipe that tells Kubernetes "keep N copies of this pod running at all times." If a pod dies, the Deployment automatically replaces it.
41
+
42
+ The key field is `spec.replicas` — this is the number the SRE agent changes when it scales a service up or down.
43
+
44
+ ```
45
+ Deployment: payments
46
+ replicas: 3 <-- the agent changes this number
47
+ |
48
+ +-- Pod: payments-abc123 (running)
49
+ +-- Pod: payments-def456 (running)
50
+ +-- Pod: payments-ghi789 (running)
51
+ ```
52
+
53
+ **The agent scales replicas, not pods.** When it sets `replicas: 5`, Kubernetes creates 5 pods. When it sets `replicas: 2`, Kubernetes kills 3 pods.
54
+
55
+ ### Service
56
+
57
+ A Service gives pods a stable network name. Instead of connecting to `payments-abc123` directly (which changes when the pod is recreated), you connect to `payments` (the Service), which routes to whichever pods are healthy.
58
+
59
+ ### Namespace
60
+
61
+ A namespace is a folder for organizing resources. We use:
62
+ - `prod-sre` — where the 5 microservice Deployments live
63
+ - `monitoring` — where the Prometheus Agent pod lives
64
+ - `kube-system` — where AWS/EKS system pods live
65
+
66
+ ### Node
67
+
68
+ A node is one EC2 virtual machine in the EKS cluster. Our cluster has 2-4 nodes. Each node runs multiple pods. When all nodes are full and the agent wants to scale up, Kubernetes adds more nodes (up to `maxSize: 4` in our config).
69
+
70
+ ```
71
+ EKS Cluster
72
+ Node 1 (t3.medium - 4 vCPU, 8GB RAM)
73
+ Pod: payments-abc123
74
+ Pod: checkout-def456
75
+ Pod: catalog-ghi789
76
+ Pod: prometheus-agent-xyz
77
+ Node 2 (t3.medium - 4 vCPU, 8GB RAM)
78
+ Pod: payments-jkl012 <-- agent scaled payments from 1 to 2
79
+ Pod: cart-mno345
80
+ Pod: auth-pqr678
81
+ ```
82
+
83
+ ### ResourceQuota
84
+
85
+ A hard limit on how many resources a namespace can use. We set one on `prod-sre` that caps total pods at 30. This is a safety net — even if the Python code cap fails, Kubernetes itself will refuse to create more than 30 pods.
86
+
87
+ ---
88
+
89
+ ## How the SRE Agent Works
90
+
91
+ ### The Loop
92
+
93
+ Every "tick" (one step of the simulation), the agent goes through this cycle:
94
+
95
+ ```
96
+ 1. OBSERVE -- Read telemetry (CPU, latency, queue depth) from Prometheus
97
+ 2. DECIDE -- Choose an action (SCALE_UP, SCALE_DOWN, REROUTE_TRAFFIC, SHED_LOAD, NO_OP)
98
+ 3. ACT -- Send the action to KubernetesExecutor
99
+ 4. REWARD -- Compute Lyapunov stability reward (was the cluster more or less stable?)
100
+ 5. REPEAT
101
+ ```
102
+
103
+ ### How Each Action Works
104
+
105
+ | Action | What the Agent Decides | What Happens on EKS |
106
+ |---|---|---|
107
+ | `SCALE_UP` | "node-0 needs more capacity" | `KubernetesExecutor` patches `payments` Deployment: `replicas: 2 -> 5` |
108
+ | `SCALE_DOWN` | "node-3 is over-provisioned" | `KubernetesExecutor` patches `cart` Deployment: `replicas: 4 -> 1` |
109
+ | `REROUTE_TRAFFIC` | "Move traffic away from node-2" | Currently simulation-only (no live K8s ingress patching) |
110
+ | `SHED_LOAD` | "Drop 50% of traffic to node-3" | Currently simulation-only (no live K8s traffic shaping) |
111
+ | `NO_OP` | "Do nothing this tick" | Nothing changes on EKS |
112
+
113
+ ### The SCALE_UP Flow in Detail
114
+
115
+ Here is exactly what happens when the agent decides to scale up `node-0` (the payments service):
116
+
117
+ ```
118
+ HF Spaces AWS EKS
119
+ ---------- --------
120
+
121
+ Agent: "SCALE_UP, node-0, parameter=0.5"
122
+ |
123
+ v
124
+ AntiAtroposEnvironment.step()
125
+ |
126
+ v
127
+ KubernetesExecutor.execute_with_metadata()
128
+ |
129
+ v
130
+ _load_node_workload_map()
131
+ reads: node-0 -> {"deployment": "payments", "namespace": "prod-sre"}
132
+ |
133
+ v
134
+ _scale_deployment("SCALE_UP", "node-0", 0.5)
135
+ |
136
+ +-- 1. Read current replicas: apps_v1.read_namespaced_deployment_scale("payments", "prod-sre")
137
+ | Current replicas = 2
138
+ |
139
+ +-- 2. Calculate delta: max(1, int(0.5 * 3)) = 1
140
+ | Desired = min(6, 2 + 1) = 3 <-- max_replicas cap from env var
141
+ |
142
+ +-- 3. Patch: apps_v1.patch_namespaced_deployment_scale("payments", "prod-sre",
143
+ | body={"spec": {"replicas": 3}})
144
+ |
145
+ v +---------------------------+
146
+ Returns: "Ack: SCALE_UP for node-0 - | K8s creates 1 new pod: |
147
+ deployment payments in namespace | payments-newpod-xyz |
148
+ prod-sre scaled 2->3" +---------------------------+
149
+ ```
150
+
151
+ ### The Telemetry Flow in Detail
152
+
153
+ How the agent reads metrics from the real cluster:
154
+
155
+ ```
156
+ EKS Cluster AMP HF Spaces
157
+ ----------- --- ----------
158
+
159
+ Workload pods AMP Workspace AntiAtropos
160
+ (payments, checkout...) stores all metrics PrometheusClient
161
+ | ^ |
162
+ | /metrics (scraped every 15s) | |
163
+ v | |
164
+ Prometheus Agent | |
165
+ | | |
166
+ | remote-write (SigV4 auth) | |
167
+ +-------------------------------------------> |
168
+ | |
169
+ | HTTPS query |
170
+ +------------------------>
171
+ (PROMETHEUS_URL env var)
172
+ |
173
+ v
174
+ _fetch_real_metrics()
175
+ runs PromQL like:
176
+ sum(rate(http_requests_total[1m])) by (pod)
177
+ returns: TelemetryRecord for each node
178
+ ```
179
+
180
+ ---
181
+
182
+ ## The Three Layers of Scaling Caps
183
+
184
+ This is the most important thing to understand for cost control. There are **three** independent limits:
185
+
186
+ ### Layer 1: Python Code Cap (Soft)
187
+
188
+ **Where:** `ANTIATROPOS_MAX_REPLICAS` env var on HF Spaces, read by `kubernetes_executor.py` line 18.
189
+
190
+ **How it works:** The `_scale_deployment()` method calculates `desired = min(self.max_replicas, current + delta)`. If the agent tries to scale above 6, it gets:
191
+
192
+ ```
193
+ Ack: SCALE_UP for node-0 - replicas unchanged at 6 (bounds 1-6)
194
+ ```
195
+
196
+ **Can it be bypassed?** Yes. A bug in the code, or someone running `kubectl scale deployment payments --replicas=50` directly.
197
+
198
+ **Set to:** `6` on HF Spaces.
199
+
200
+ ### Layer 2: Kubernetes ResourceQuota (Hard)
201
+
202
+ **Where:** `k8s-workloads.yaml` — ResourceQuota on the `prod-sre` namespace.
203
+
204
+ **How it works:** Kubernetes itself refuses to schedule pods that would exceed the quota. If the namespace already has 30 pods and something tries to create a 31st:
205
+
206
+ ```
207
+ Error from server (Forbidden): pods "payments-new" is forbidden:
208
+ exceeded quota: prod-sre-quota, requested: pods=1, used: pods=30, limited: pods=30
209
+ ```
210
+
211
+ **Can it be bypassed?** Only by someone with cluster-admin access who deletes or edits the ResourceQuota.
212
+
213
+ **Set to:** 30 pods total, 8 CPU, 8GB RAM.
214
+
215
+ ### Layer 3: EKS Node Group Max Size (Hard)
216
+
217
+ **Where:** `eksctl-cluster.yaml` — `managedNodeGroups[0].maxSize: 4`.
218
+
219
+ **How it works:** The Cluster Autoscaler will never add more than 4 nodes. Even if there are 100 pending pods, it stops at 4 nodes. Pending pods just wait.
220
+
221
+ **Can it be bypassed?** Only by someone editing the node group in the AWS console.
222
+
223
+ **Set to:** 4 nodes (4 x t3.medium = 8 vCPU, 16GB RAM max).
224
+
225
+ ### How the Three Layers Work Together
226
+
227
+ ```
228
+ Agent wants to scale all 5 deployments to 20 replicas each:
229
+
230
+ Layer 1 (Python cap): 6 replicas max per deployment -> agent gets "unchanged at 6"
231
+ 5 x 6 = 30 pods maximum
232
+
233
+ Layer 2 (ResourceQuota): 30 pods max in namespace -> 31st pod is Forbidden
234
+
235
+ Layer 3 (Node group): 4 nodes max -> if 30 pods don't fit on 4 nodes,
236
+ some stay Pending (no cost)
237
+
238
+ Worst case with all caps: 30 pods on 4 nodes = ~$160/month
239
+ Without any caps: 100 pods on 25 nodes = ~$1,800/month
240
+ ```
241
+
242
+ ---
243
+
244
+ ## The Mapping: Simulator Nodes to Real Deployments
245
+
246
+ The simulator has 5 abstract nodes (node-0 through node-4). The `ANTIATROPOS_WORKLOAD_MAP` env var tells the system which K8s Deployment each simulator node maps to:
247
+
248
+ ```
249
+ Simulator Node K8s Deployment Namespace Notes
250
+ ------------- --------------- --------- -----
251
+ node-0 payments prod-sre VIP (4x importance weight)
252
+ node-1 checkout prod-sre Critical (no SHED_LOAD)
253
+ node-2 catalog prod-sre Critical (no SHED_LOAD)
254
+ node-3 cart prod-sre Non-critical (sheddable)
255
+ node-4 auth prod-sre Non-critical (sheddable)
256
+ ```
257
+
258
+ When the simulator says "SCALE_UP node-0 by 0.5", the system:
259
+ 1. Looks up node-0 in the workload map -> `payments` in `prod-sre`
260
+ 2. Calls `patch_namespaced_deployment_scale("payments", "prod-sre", ...)`
261
+ 3. Kubernetes creates/destroys pods to match the new replica count
262
+
263
+ ---
264
+
265
+ ## What Runs Where (Complete List)
266
+
267
+ ### On Hugging Face Spaces
268
+
269
+ | Component | What It Does | Port |
270
+ |---|---|---|
271
+ | FastAPI server (`server/app.py`) | HTTP API for the agent | 7860 (via NGINX) |
272
+ | Simulator (`simulator.py`) | 5-node microservice cluster simulation | Internal |
273
+ | PrometheusClient (`telemetry/prometheus_client.py`) | Queries AMP for real metrics | Outbound HTTPS |
274
+ | KubernetesExecutor (`control/kubernetes_executor.py`) | Sends scale commands to EKS | Outbound HTTPS |
275
+ | Prometheus metrics exporter | Serves `/metrics` for HF's monitoring | 8000 |
276
+ | Grafana + local Prometheus | Local dashboards (from the Dockerfile) | 3000, 9090 |
277
+
278
+ ### On AWS EKS
279
+
280
+ | Component | Namespace | What It Does |
281
+ |---|---|---|
282
+ | payments Deployment | prod-sre | 2 nginx pods (scales with agent) |
283
+ | checkout Deployment | prod-sre | 1 nginx pod (scales with agent) |
284
+ | catalog Deployment | prod-sre | 1 nginx pod (scales with agent) |
285
+ | cart Deployment | prod-sre | 1 nginx pod (scales with agent) |
286
+ | auth Deployment | prod-sre | 1 nginx pod (scales with agent) |
287
+ | Prometheus Agent | monitoring | Scrapes workload pods, remote-writes to AMP |
288
+ | Cluster Autoscaler | kube-system | Adds/removes EC2 nodes based on demand |
289
+
290
+ ### On AWS Managed Services
291
+
292
+ | Service | What It Does |
293
+ |---|---|
294
+ | AMP (Amazon Managed Prometheus) | Stores all metrics. Queried by HF Spaces. |
295
+ | AMG (Amazon Managed Grafana) | Visualizes metrics in dashboards. Accessed via browser. |
296
+
297
+ ---
298
+
299
+ ## The Simulator vs Real Cluster
300
+
301
+ AntiAtropos has three modes controlled by `ANTIATROPOS_ENV_MODE`:
302
+
303
+ ### Simulated Mode (`simulated`)
304
+
305
+ Everything is fake. The simulator generates synthetic metrics (random CPU, latency, etc.). No K8s, no Prometheus. The agent practices in a safe sandbox.
306
+
307
+ This is the default on HF Spaces without AWS configured.
308
+
309
+ ### Hybrid Mode (`hybrid`)
310
+
311
+ The simulator runs, but it pulls real metrics from AMP to calibrate itself. If AMP says `payments` pods have 80% CPU, the simulator adjusts its internal model to match. The agent can read real data but actions only affect the simulator, not real pods.
312
+
313
+ ### Live Mode (`live`)
314
+
315
+ The real deal. The agent reads real metrics from AMP and sends real scale commands to EKS. When it says `SCALE_UP`, actual pods get created on actual EC2 instances that cost actual money.
316
+
317
+ **Set `ANTIATROPOS_ENV_MODE=live` on HF Spaces to enable this.**
318
+
319
+ ---
320
+
321
+ ## Cost Flow
322
+
323
+ Every pod on EKS costs money. Here is how costs flow based on the agent's actions:
324
+
325
+ ```
326
+ Agent action: SCALE_UP node-0
327
+ -> payments Deployment: replicas 2 -> 5
328
+ -> 3 new pods created
329
+ -> If existing nodes are full, Cluster Autoscaler adds a node
330
+ -> New node = another t3.medium EC2 instance = ~$0.04/hr
331
+ -> 3 pods running = 3 x (0.1 CPU + 64MB RAM) from the quota
332
+
333
+ Agent action: SCALE_DOWN node-3
334
+ -> cart Deployment: replicas 4 -> 1
335
+ -> 3 pods terminated
336
+ -> If nodes are now underutilized, Cluster Autoscaler removes a node (after 10 min)
337
+ -> One fewer EC2 instance = saves ~$0.04/hr
338
+ ```
339
+
340
+ The Lyapunov reward function penalizes the agent for both instability AND cost, so a well-trained agent should learn to scale efficiently:
341
+
342
+ ```
343
+ R_t = -(alpha * delta_V + beta * cost + gamma * SLA_violation)
344
+ ^^^^
345
+ beta=0.01 penalizes over-provisioning
346
+ ```
347
+
348
+ ---
349
+
350
+ ## Quick Reference: Key Files
351
+
352
+ | File | Purpose |
353
+ |---|---|
354
+ | `kubernetes_executor.py` | Translates agent actions to K8s API calls |
355
+ | `prometheus_client.py` | Queries AMP for real metrics |
356
+ | `simulator.py` | 5-node fluid-queue simulation |
357
+ | `stability.py` | Lyapunov reward computation |
358
+ | `deploy/aws/k8s-workloads.yaml` | The 5 Deployments + ResourceQuota on EKS |
359
+ | `deploy/aws/eksctl-cluster.yaml` | EKS cluster definition (nodes, caps) |
360
+ | `deploy/aws/prometheus-agent-values.yaml` | Helm config for Prometheus Agent |
361
+ | `deploy/aws/generate-kubeconfig.sh` | Creates kubeconfig for HF Spaces |
deploy/aws/k8s-workloads.yaml CHANGED
@@ -17,6 +17,26 @@ metadata:
17
  labels:
18
  app.kubernetes.io/part-of: antiatropos
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  ---
21
  # payments — node-0 (VIP)
22
  # Business-critical payment service. Always has 2 replicas for redundancy.
 
17
  labels:
18
  app.kubernetes.io/part-of: antiatropos
19
 
20
+ ---
21
+ # ResourceQuota: Hard cap on pods in prod-sre namespace.
22
+ # This is a Kubernetes-level safety net. Even if the agent's Python cap fails,
23
+ # Kubernetes will refuse to create pods beyond this limit.
24
+ #
25
+ # Max 30 pods = 6 replicas x 5 deployments (our worst-case budget)
26
+ # Max 8 CPU / 8GB RAM = enough for 30 small nginx pods
27
+ apiVersion: v1
28
+ kind: ResourceQuota
29
+ metadata:
30
+ name: prod-sre-quota
31
+ namespace: prod-sre
32
+ spec:
33
+ hard:
34
+ pods: "30"
35
+ requests.cpu: "8"
36
+ requests.memory: 8Gi
37
+ limits.cpu: "15"
38
+ limits.memory: 15Gi
39
+
40
  ---
41
  # payments — node-0 (VIP)
42
  # Business-critical payment service. Always has 2 replicas for redundancy.