RookeryOS — Deployment Pipeline
From code to running agent pod in minutes
Overview
RookeryOS deploys to Google Kubernetes Engine (GKE) Standard cluster in us-central1. The pipeline uses Cloud Build for Docker images, Artifact Registry for storage, Gateway API for routing, and KEDA for auto-scaling.
Infrastructure
GKE Cluster
| Setting | Value |
|---|---|
| Name | aw2-standard-cluster |
| Type | Standard (not Autopilot) |
| Location | us-central1 |
| Node Type | e2-standard-2 (Spot instances) |
| Gateway IP | 34.102.157.95 |
| Gateway API | v1 (HTTPRoute, Gateway, HTTPScaledObject) |
| KEDA | HTTP add-on for auto-scaling |
GCP Project
| Setting | Value |
|---|---|
| Project ID | ai-agent-workforce-hq |
| Project Number | 668121802941 |
| Billing Account | 01A3DA-B3618E-5EE29F |
| Artifact Registry | us-central1-docker.pkg.dev/ai-agent-workforce-hq/aw2-images/ |
Build Pipeline
Cloud Build: Multi-Image Build
gcloud builds submit --config=cloudbuild-pod.yaml
Builds three images in sequence:
cloudbuild-pod.yaml
│
├── Step 1: Build rookery-os-base
│ FROM debian:bookworm-slim
│ Harden, strip packages, create agent user
│ → us-central1-docker.pkg.dev/.../rookery-os-base:latest
│
├── Step 2: Build rookery-kernel
│ FROM rookery-os-base
│ Install Node.js 22, Hudson Gateway, nginx, s6-overlay
│ → us-central1-docker.pkg.dev/.../rookery-kernel:latest
│
└── Step 3: Build rookery-sidecar
FROM rookery-os-base
Install Chromium, Xvfb, noVNC, Browser-Use, Python
→ us-central1-docker.pkg.dev/.../rookery-sidecar:latest
Individual Service Builds
# Console
docker build -t aw2-console apps/console/
# API Server
docker build -t aw2-api apps/api/
# STT/TTS Service
docker build -t aw2-stt-tts apps/stt-tts-service/
Gateway API Routing
HTTPRoute Configuration
Internet (34.102.157.95)
│
├── HTTPS termination (Google-managed cert)
│
├── agentworksstudio.com → Marketing (Next.js)
├── www.agentworksstudio.com → Marketing (Next.js)
│
├── app.agentworksstudio.com → Console (React SPA)
│ └── platform/aw2-console HTTPRoute
│
├── api.agentworksstudio.com → API Server (Hono)
│ ├── platform/aw2-api HTTPRoute
│ └── voice/sonar-webrtc-route (WebRTC upgrade)
│
├── gateway.agentworksstudio.com → Hudson Gateway
│ └── platform/aw2-gateway HTTPRoute
│
└── *.pods.agentworksstudio.com → Agent Pods
└── {agent-namespace}/agent HTTPRoute (per-pod)
HTTP-to-HTTPS Redirect
All hostnames have HTTP→HTTPS redirect in aw2-system namespace:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-to-https-redirect
namespace: aw2-system
spec:
hostnames:
- agentworksstudio.com
- www.agentworksstudio.com
- app.agentworksstudio.com
- api.agentworksstudio.com
- gateway.agentworksstudio.com
Agent Pod Deployment
Provisioning Flow
1. API receives agent create request
2. Agent Provisioner generates K8s manifest
├── From template: agent-pod-v2.yaml (dual-container)
└── Or: navigator-pod.yaml (single-container, restricted)
3. Creates namespace (production) or uses shared (navigator)
4. Applies RBAC, NetworkPolicy
5. Creates PVC (production only)
6. Submits pod spec to K8s API
7. KEDA HTTPScaledObject enables auto-scaling
8. HTTPRoute registers pod subdomain
9. Pod boots → chelper validates → Hudson ready
10. Health checks pass → traffic routed
Agent Pod Template (Production)
# infrastructure/k8s/templates/agent-pod-v2.yaml
apiVersion: v1
kind: Pod
metadata:
name: agent
namespace: agent-{tenant}-{agent-id}
spec:
containers:
- name: kernel
image: rookery-kernel:latest
ports: ["8080"]
env:
- ENABLE_SIDECAR: "true"
- ENABLE_COOKIE_VAULT: "true"
- ENABLE_HITL: "true"
volumeMounts:
- name: cdp-socket, mountPath: /tmp/cdp
- name: workspace, mountPath: /data
- name: sidecar
image: rookery-sidecar:latest
ports: ["9222", "6080", "9223"]
volumeMounts:
- name: cdp-socket, mountPath: /tmp/cdp
volumes:
- name: cdp-socket, emptyDir: {}
- name: workspace, persistentVolumeClaim: { claimName: agent-workspace }
Navigator Pod Template (Free Tier)
# infrastructure/k8s/navigator/navigator-pod.yaml
spec:
containers:
- name: kernel-only
image: rookery-kernel:latest
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: 500m, memory: 512Mi }
env:
- NAVIGATOR_MODE: "true"
- ENABLE_SIDECAR: "false"
# No sidecar, no PVC, no Workload Identity
# Auto-delete after 24 hours via TTL controller
Auto-Scaling (KEDA)
KEDA HTTPScaledObject
│
├── Monitors HTTP traffic per agent pod
│
├── Scale to zero when idle (save costs)
│
├── Scale up on incoming requests
│
└── Per-agent scaling (not platform-wide)
Benefit: Agent pods that aren't actively chatting cost nothing. They spin up in ~45s when a message arrives.
Platform Services Deployment
Console (aw2-console)
Namespace: platform
Replicas: 1
Image: aw2-console
Service: ClusterIP :8080
Resources: 100m/128Mi → 500m/256Mi
Health: GET / (startup 10s)
Route: app.agentworksstudio.com → /
API Server (aw2-api)
Namespace: platform
Replicas: 2
Image: aw2-api
Service: ClusterIP :3001
Resources: 250m/512Mi → 1000m/1Gi
Health: GET /health
Route: api.agentworksstudio.com → /
Gateway (aw2-gateway)
Namespace: platform
Replicas: 1
Image: aw2-gateway
Service: ClusterIP :8080
Resources: 250m/256Mi → 500m/512Mi
Health: GET /health
Route: gateway.agentworksstudio.com → /
Voice Service (aw2-stt-tts)
Namespace: voice
Replicas: 1
Image: aw2-stt-tts
Service: ClusterIP :8000
Resources: 500m/1Gi → 2000m/4Gi
Health: GET /health
Route: api.agentworksstudio.com/voice/* → :8000
Deployment Commands
# Deploy all platform services
kubectl apply -f infrastructure/k8s/platform/
# Rolling restart (zero downtime)
kubectl rollout restart deployment/aw2-console -n platform
kubectl rollout restart deployment/aw2-api -n platform
kubectl rollout restart deployment/aw2-gateway -n platform
# Deploy agent provisioner
kubectl rollout restart deployment/aw2-provisioner -n platform
# Check status
kubectl get pods -n platform
kubectl get httproute -A
kubectl describe gateway aw2-gateway -n aw2-system
# View logs
kubectl logs -f deployment/aw2-api -n platform
kubectl logs -f deployment/aw2-console -n platform
Cost Optimization
| Strategy | Implementation |
|---|---|
| Spot instances | e2-standard-2 spot (70% cheaper than on-demand) |
| Scale to zero | KEDA HTTPScaledObject for agent pods |
| Single replica | Console, Gateway run 1 pod each |
| Navigator isolation | Strict resource quotas prevent abuse |
| No GPU | All inference via Z.ai API (no GPU instances) |
| Minimal images | Alpine/slim base images, multi-stage builds |
Estimated Monthly Cost: $50–92/mo (down from $258/mo pre-optimization)
Monitoring
| Check | Method |
|---|---|
| Pod health | kubectl get pods -A |
| Route status | kubectl get httproute -A |
| Gateway status | kubectl describe gateway aw2-gateway -n aw2-system |
| API logs | kubectl logs -f deployment/aw2-api -n platform |
| Console logs | kubectl logs -f deployment/aw2-console -n platform |
| Agent pod logs | kubectl logs -f agent-pod -n agent-{ns} |
| Build history | gcloud builds list --limit=10 |
File Locations
infrastructure/
├── k8s/
│ ├── platform/
│ │ ├── namespace.yaml # Platform namespace + tier label
│ │ ├── console.yaml # Console deployment + service
│ │ ├── api.yaml # API deployment + service
│ │ ├── gateway.yaml # Gateway deployment + service
│ │ └── provisioner.yaml # Provisioner deployment
│ ├── templates/
│ │ └── agent-pod-v2.yaml # Dual-container pod template
│ └── navigator/
│ ├── namespace.yaml # Navigator namespace
│ ├── network-policy.yaml # Network isolation
│ ├── resource-quota.yaml # Resource limits
│ ├── rbac.yaml # RBAC for navigator
│ └── navigator-pod.yaml # Single-container template
├── docker/
│ ├── rookery-os-base/Dockerfile
│ ├── rookery-kernel/Dockerfile
│ └── rookery-sidecar/Dockerfile
└── cloudbuild-pod.yaml # Multi-image build pipeline
apps/agent-provisioner/src/
├── provisioner.ts # Production pod provisioning
└── navigator-provisioner.ts # Navigator pod provisioning
