Lean: update Semantics modules, add new numerics/physics data files Hardware: update FPGA bitstreams (tangnano9k_uart_loopback) Infra: k3s-flake tests, netcup-vps configuration, VCN compute substrate Docs: ARCHITECTURE, specs, citation updates
13 KiB
Plan: Ray Deployment on Research Stack k3s
Date: 2026-05-29 Status: Draft Estimated effort: 2-3 days
Goal
Deploy Ray on the Research Stack k3s cluster with:
- Distributed compute across 5 nodes (2 Ready, 3 flaky)
- H.264 transport via Ray Object Store
- GPU acceleration on qfox (RTX 4070)
- Thundering herd mitigations for node reconnection
- Graceful degradation when nodes go offline
Current State
| Node | Status | Role | Hardware |
|---|---|---|---|
| nixos | Ready | control-plane | NixOS, 6.18.32 kernel |
| qfox-1 | Ready | worker | CachyOS, RTX 4070 |
| 361395-1 | NotReady | worker | Debian, edge VPS |
| racknerd | NotReady | worker | Debian, VPS |
| steamdeck | NotReady | worker | NixOS |
Namespaces: ai-models (empty), services, media, mail, monitoring, research, edge
Existing workloads:
- VCN pipeline:
braid_vcn_encoder.py(Delta+RLE + RS ECC + ChaCha20 + H.264) - Fractal dimension:
fractal_dimension.py(DBC algorithm, 29x vectorized) - GPU node:
vcn_lupine_gpu_node.py(MKV decode + GPU compute) - AlphaProof:
alphaproof_loop.py(Ollama → lake build → feedback) - Lean: 3572 jobs, 0 errors
- Python: 68/68 tests pass
Architecture
Ray Topology
Neon-64GB (Ray Head + Worker)
├── GCS (Global Control Store) — PVC-backed
├── Dashboard (:8265) — via Traefik ingress
├── Object Store — 32GB allocated
├── Raylet — 18 ARM64 cores
└── VCN Encoder — Delta+RLE + RS ECC + ChaCha20
qfox-1 (Ray GPU Worker)
├── Raylet — RTX 4070
├── NVDEC — H.264 hardware decode (0.1ms)
├── CUDA — GPU compute (fractal dimension, Q16 LUT)
└── Object Store — 8GB allocated
nixos (Ray CPU Worker)
├── Raylet — CPU cores
├── Software decode — H.264 fallback
├── Lean builds — lake build via Ray tasks
└── Object Store — 4GB allocated
racknerd (Ray Edge Worker — standby)
├── Raylet — 2 vCPU EPYC
├── Edge relay — forward to external clients
└── Object Store — 2GB allocated
steamdeck (Ray Idle Worker — standby)
├── Raylet — idle until needed
└── Object Store — 2GB allocated
Network Flow
Braid data (Python)
→ Delta+RLE (vectorized copy-if, 3.3x)
→ RS ECC
→ ChaCha20
→ H.264 frame (YUV420)
→ MKV container
→ ray.put() → ObjectRef
→ Ray Object Store (shared memory)
→ GPU hardware decode (NVDEC) or CPU fallback
→ GPU compute or CPU compute
→ Result → ray.put() → ObjectRef
→ Downstream consumer
Port Map
| Port | Service | Access |
|---|---|---|
| 6379 | Ray GCS | Internal (Tailscale only) |
| 8265 | Ray Dashboard | Via Traefik ingress |
| 10001 | Ray Client | Tailscale only |
| 8000 | Ray Serve | Via Traefik ingress |
Implementation Steps
Phase 1: Ray Head Deployment (Day 1)
Step 1.1: Create Ray namespace and RBAC
- File:
4-Infrastructure/k3s/ray/namespace.yaml - Create
ainamespace (already exists, use it) - ServiceAccount, ClusterRole, ClusterRoleBinding for Ray
Step 1.2: Deploy Ray Head on Neon-64GB
- File:
4-Infrastructure/k3s/ray/head-deployment.yaml - Image:
rayproject/ray:2.43.0-py311-cu124 - Command:
ray start --head --dashboard-host=0.0.0.0 --object-store-memory=34359738368 - PVC: 10Gi for GCS persistence
- Resources: 4 CPU request, 16 CPU limit, 8Gi RAM request, 32Gi RAM limit
- NodeSelector:
kubernetes.io/hostname: neon-64gb - Liveness probe:
ray health-check - Readiness probe:
ray status
Step 1.3: Deploy Ray Dashboard Service
- File:
4-Infrastructure/k3s/ray/dashboard-service.yaml - ClusterIP service on port 8265
- Traefik IngressRoute at
/ray/dashboard
Step 1.4: Verify Head is running
kubectl get pods -n aicurl http://localhost:8265(port-forward)ray statusinside head pod
Phase 2: Worker Deployment (Day 1)
Step 2.1: Deploy Ray GPU Worker on qfox-1
- File:
4-Infrastructure/k3s/ray/gpu-worker-deployment.yaml - Image:
rayproject/ray:2.43.0-py311-cu124 - Command:
ray start --address=ray-head.ai.svc.cluster.local:6379 - Resources: 2 CPU, 8Gi RAM, 1 nvidia.com/gpu
- NodeSelector:
kubernetes.io/hostname: qfox-1 - Toleration:
nvidia.com/gpu:NoSchedule - Environment:
NVIDIA_VISIBLE_DEVICES=all
Step 2.2: Deploy Ray CPU Worker on nixos
- File:
4-Infrastructure/k3s/ray/cpu-worker-deployment.yaml - Image:
rayproject/ray:2.43.0-py311-cu124 - Command:
ray start --address=ray-head.ai.svc.cluster.local:6379 - Resources: 4 CPU, 8Gi RAM
- No GPU resources
Step 2.3: Deploy Standby Workers (racknerd, steamdeck)
- File:
4-Infrastructure/k3s/ray/standby-worker-deployment.yaml - Same as CPU worker but with lower resources
- Toleration:
node.kubernetes.io/unreachable:NoSchedule - Priority: low (evicted first when nodes are under pressure)
Step 2.4: Verify all workers connected
ray statusinside head pod- Check: 4 workers connected (Neon, qfox, nixos, racknerd/steamdeck if online)
Phase 3: Thundering Herd Mitigations (Day 2)
Step 3.1: Staggered reconnection
- File:
4-Infrastructure/k3s/ray/worker-entrypoint.sh - Script: compute jitter from Tailscale IP hash, sleep before connecting
delay = hash(tailscale_ip) % 30- Mount as ConfigMap, use as worker command
Step 3.2: Token bucket on Head
- File:
4-Infrastructure/k3s/ray/head-entrypoint.sh - Configure Ray with
--max-worker-startup-concurrency=1 - One worker connects per second, burst of 3
- Workers get 429 + Retry-After on rejection
Step 3.3: Object Store watermarks
- File:
4-Infrastructure/k3s/ray/object-store-config.yaml - Configure Ray with memory thresholds:
- 60%: throttle incoming syncs to 1/s
- 80%: reject new connections
- 95%: emergency GC
- Spill cold objects to PVC at 60%
Step 3.4: Circuit breaker per worker
- File:
4-Infrastructure/shim/ray_circuit_breaker.py - Python class wrapping Ray client calls
- States: CLOSED (normal), OPEN (head overwhelmed), HALF-OPEN (testing)
- Failure threshold: 5 failures in 30s → OPEN
- Recovery: 60s wait → HALF-OPEN → probe → CLOSED
Step 3.5: Graduated task migration
- File:
4-Infrastructure/shim/ray_task_migrator.py - When GPU node returns, migrate tasks in batches:
- t=0s: 10% of tasks
- t=30s: 20% more
- t=60s: remaining 70%
- Abort if any batch fails
Step 3.6: Witness deduplication
- Ray ObjectRefs are already content-addressed
- Verify:
ray.put(data)returns same ObjectRef for same data - No custom code needed — document the behavior
Phase 4: VCN Pipeline Integration (Day 2)
Step 4.1: Wire VCN encoder to Ray Object Store
- File:
4-Infrastructure/shim/vcn_ray_transport.py encode_and_store(braid_data) → ObjectRefdecode_on_gpu(ObjectRef) → np.ndarraydecode_on_cpu(ObjectRef) → np.ndarray(fallback)
Step 4.2: Wire fractal dimension to Ray
- File:
4-Infrastructure/shim/fractal_ray_task.py @ray.remote(num_gpus=1) def compute_fd_gpu(data)@ray.remote(num_cpus=4) def compute_fd_cpu(data)- Auto-select based on GPU availability
Step 4.3: Wire AlphaProof to Ray
- File:
4-Infrastructure/shim/alphaproof_ray.py @ray.remote def prove_theorem(problem)- Parallel proof search across workers
- Pre-filter: skip trivial theorems (copy-if pattern)
Step 4.4: Test end-to-end
- Encode 100 braid strands → Object Store → GPU decode → compute → verify
- Measure: encode time, transfer time, decode time, compute time
- Verify: 3.3x speedup on Delta+RLE, 100x on H.264 decode
Phase 5: k3s Migration (Day 3)
Step 5.1: Migrate control plane
- Stop k3s-server on Neon-64GB
- Install k3s-server on cupfox
- Update kubeconfig to point to cupfox
- Update Tailscale Funnel target
Step 5.2: Re-point workers
- Update k3s-agent on all workers to point to cupfox
- Verify: all nodes join new control plane
Step 5.3: Update DNS and ingress
- Update researchstack.info A record → cupfox IP
- Update Caddy upstream on racknerd
- Verify: Traefik ingress works
Step 5.4: Verify Ray survives migration
- Ray Head should reschedule on Neon (worker node now)
- GCS persists on PVC (survives restart)
- Workers reconnect to new Head
Phase 6: Monitoring and Observability (Day 3)
Step 6.1: Ray Dashboard ingress
- File:
4-Infrastructure/k3s/ray/dashboard-ingress.yaml - Traefik IngressRoute at
researchstack.info/ray/ - SSO-gated via Authentik
Step 6.2: Prometheus metrics
- Ray exports Prometheus metrics at
:8080/metrics - Scrape config in monitoring namespace
- Grafana dashboard for Ray cluster health
Step 6.3: Alerting
- Alert on: worker disconnect, Object Store pressure, task failures
- Route to: Telegram/Discord via Alertmanager
Files to Create
| File | Purpose |
|---|---|
4-Infrastructure/k3s/ray/namespace.yaml |
Namespace + RBAC |
4-Infrastructure/k3s/ray/head-deployment.yaml |
Ray Head on Neon |
4-Infrastructure/k3s/ray/head-service.yaml |
ClusterIP + IngressRoute |
4-Infrastructure/k3s/ray/gpu-worker-deployment.yaml |
GPU worker on qfox |
4-Infrastructure/k3s/ray/cpu-worker-deployment.yaml |
CPU worker on nixos |
4-Infrastructure/k3s/ray/standby-worker-deployment.yaml |
Standby on racknerd/steamdeck |
4-Infrastructure/k3s/ray/worker-entrypoint.sh |
Staggered reconnection script |
4-Infrastructure/k3s/ray/head-entrypoint.sh |
Token bucket config |
4-Infrastructure/k3s/ray/object-store-config.yaml |
Watermark thresholds |
4-Infrastructure/k3s/ray/dashboard-ingress.yaml |
Dashboard Traefik route |
4-Infrastructure/shim/ray_circuit_breaker.py |
Circuit breaker per node |
4-Infrastructure/shim/ray_task_migrator.py |
Graduated migration |
4-Infrastructure/shim/vcn_ray_transport.py |
VCN → Ray Object Store |
4-Infrastructure/shim/fractal_ray_task.py |
Fractal dimension on Ray |
4-Infrastructure/shim/alphaproof_ray.py |
AlphaProof on Ray |
Files to Modify
| File | Change |
|---|---|
4-Infrastructure/k3s-flake/k3s-edge.nix |
Update Traefik for Ray ingress |
6-Documentation/INFRASTRUCTURE.md |
Add Ray section |
6-Documentation/RUNBOOK.md |
Add Ray troubleshooting |
AGENTS.md |
Add Ray deployment rules |
Validation
Phase 1 Validation
- Ray Head pod Running on Neon
- Dashboard accessible at localhost:8265 (port-forward)
ray statusshows 1 node (Head)
Phase 2 Validation
- GPU worker connected (qfox)
- CPU worker connected (nixos)
- Standby workers connected (racknerd, steamdeck if online)
ray statusshows 4+ nodes
Phase 3 Validation
- Simulate node disconnect: kill qfox pod
- Verify: GPU tasks queued, not failed
- Restart qfox pod
- Verify: staggered reconnection (watch logs)
- Verify: graduated migration (5→15→35→50 tasks)
- Verify: Object Store watermark triggers at 60%
Phase 4 Validation
ray.put(braid_data)returns ObjectRefray.get(ObjectRef)returns original data- GPU decode works on qfox
- CPU decode fallback works on nixos
- 100 braid strands: end-to-end < 10s
Phase 5 Validation
- Control plane migrated to cupfox
- All workers join new control plane
- Ray Head reschedules on Neon
- GCS persists across restart
Phase 6 Validation
- Dashboard accessible via Traefik
- Prometheus scraping Ray metrics
- Grafana dashboard shows cluster health
Risks and Mitigations
| Risk | Impact | Mitigation |
|---|---|---|
| Neon ARM64 image compatibility | Some services won't run | Test images before deploying |
| Ray Head on 4GB cupfox | OOM | Keep Head on Neon (64GB), cupfox is control-plane only |
| Tailscale DERP latency | Slow Ray RPC | Use direct connections when possible |
| Object Store memory pressure | OOM on workers | Watermarks + PVC spill |
| GPU driver mismatch | NVDEC fails | Fall back to CPU software decode |
| etcd on cupfox 128GB disk | Disk full | Monitor disk usage, set alerts |
Open Questions
- ARM64 Ray image: Does
rayproject/ray:2.43.0-py311-cu124have ARM64 builds? If not, need to build custom image. - NVDEC on qfox: Is the NVIDIA driver new enough for NVDEC? Need to verify with
nvidia-smi. - PVC access from workers: Can Ray workers on different nodes mount the same PVC? Need ReadWriteMany or NFS.
- Ray version: 2.43.0 is latest stable. Check compatibility with k3s 1.35.4.
- Cost: Ray Head on Neon uses 8-32GB RAM. Is that acceptable alongside other workloads?
Success Criteria
- Ray cluster operational with 4+ nodes
- VCN pipeline runs on Ray (encode → transfer → decode → compute)
- GPU acceleration working (NVDEC + CUDA)
- Thundering herd mitigations tested (node disconnect/reconnect)
- Dashboard accessible via Traefik
- AlphaProof runs on Ray (parallel proof search)
- All existing workloads still functional (k3s services, Lean, Python)