Skip to content
Rookery OS

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

SettingValue
Nameaw2-standard-cluster
TypeStandard (not Autopilot)
Locationus-central1
Node Typee2-standard-2 (Spot instances)
Gateway IP34.102.157.95
Gateway APIv1 (HTTPRoute, Gateway, HTTPScaledObject)
KEDAHTTP add-on for auto-scaling

GCP Project

SettingValue
Project IDai-agent-workforce-hq
Project Number668121802941
Billing Account01A3DA-B3618E-5EE29F
Artifact Registryus-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 }
# 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

StrategyImplementation
Spot instancese2-standard-2 spot (70% cheaper than on-demand)
Scale to zeroKEDA HTTPScaledObject for agent pods
Single replicaConsole, Gateway run 1 pod each
Navigator isolationStrict resource quotas prevent abuse
No GPUAll inference via Z.ai API (no GPU instances)
Minimal imagesAlpine/slim base images, multi-stage builds

Estimated Monthly Cost: $50–92/mo (down from $258/mo pre-optimization)


Monitoring

CheckMethod
Pod healthkubectl get pods -A
Route statuskubectl get httproute -A
Gateway statuskubectl describe gateway aw2-gateway -n aw2-system
API logskubectl logs -f deployment/aw2-api -n platform
Console logskubectl logs -f deployment/aw2-console -n platform
Agent pod logskubectl logs -f agent-pod -n agent-{ns}
Build historygcloud 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