Skip to Content
DeploymentKubernetes

Kubernetes Deployment

Deploy Pilot on Kubernetes with proper health checks, secrets management, and persistent storage.


Health Probes

Pilot exposes health endpoints for Kubernetes liveness and readiness probes:

EndpointPurposeSuccessFailure
/readyReadiness probe200 when all checks pass503 when any check fails
/liveLiveness probe200 when process is healthy503 when deadlocked
/healthBasic health checkAlways 200-

Readiness probe (/ready) checks:

  • Registered component readiness (e.g., GitHub client connected)
  • Returns JSON with individual check statuses

Liveness probe (/live) checks:

  • Goroutine count < 1000 (detects goroutine leaks)
  • No recent panics (5-minute window)
  • Main loop heartbeat freshness (< 60 seconds)

Example responses:

// GET /ready { "ready": true, "checks": { "github": true, "database": true } } // GET /live { "alive": true, "checks": { "goroutines": {"count": 42, "max": 1000, "ok": true}, "panics": {"count": 0, "recent": false, "ok": true}, "heartbeat": {"last_seconds_ago": 5, "ok": true} } }

Deployment Manifest

apiVersion: apps/v1 kind: Deployment metadata: name: pilot labels: app: pilot spec: replicas: 1 # Single replica recommended selector: matchLabels: app: pilot template: metadata: labels: app: pilot spec: containers: - name: pilot image: ghcr.io/anthropics/pilot:latest ports: - containerPort: 9090 name: http env: - name: GITHUB_TOKEN valueFrom: secretKeyRef: name: pilot-secrets key: github-token - name: ANTHROPIC_API_KEY valueFrom: secretKeyRef: name: pilot-secrets key: anthropic-api-key livenessProbe: httpGet: path: /live port: http initialDelaySeconds: 10 periodSeconds: 30 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "1Gi" cpu: "1000m" volumeMounts: - name: config mountPath: /home/pilot/.pilot - name: data mountPath: /home/pilot/.pilot/data volumes: - name: config configMap: name: pilot-config - name: data persistentVolumeClaim: claimName: pilot-data --- apiVersion: v1 kind: Service metadata: name: pilot spec: selector: app: pilot ports: - port: 9090 targetPort: http name: http

Secrets

Create secrets for API tokens:

kubectl create secret generic pilot-secrets \ --from-literal=github-token=ghp_xxxx \ --from-literal=anthropic-api-key=sk-ant-xxxx

Or use a manifest:

apiVersion: v1 kind: Secret metadata: name: pilot-secrets type: Opaque stringData: github-token: ghp_xxxx anthropic-api-key: sk-ant-xxxx

For production, use a secrets manager like HashiCorp Vault, AWS Secrets Manager, or Kubernetes External Secrets Operator.


ConfigMap

apiVersion: v1 kind: ConfigMap metadata: name: pilot-config data: config.yaml: | version: "1.0" gateway: host: "0.0.0.0" port: 9090 adapters: github: enabled: true token: "${GITHUB_TOKEN}" repo: "your-org/your-repo" autopilot: enabled: true auto_merge: true

Persistent Volume

Pilot uses SQLite for state persistence. Create a PVC:

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pilot-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: standard # Adjust for your cluster

SQLite requires ReadWriteOnce access mode. This means Pilot must run as a single replica.


Helm Chart

A minimal Helm chart structure:

pilot-chart/ ├── Chart.yaml ├── values.yaml └── templates/ ├── deployment.yaml ├── service.yaml ├── configmap.yaml ├── secret.yaml └── pvc.yaml

values.yaml:

replicaCount: 1 image: repository: ghcr.io/anthropics/pilot tag: latest pullPolicy: IfNotPresent service: type: ClusterIP port: 9090 resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "1Gi" cpu: "1000m" persistence: enabled: true size: 1Gi storageClass: "" config: gateway: host: "0.0.0.0" port: 9090 secrets: githubToken: "" anthropicApiKey: ""

Install:

helm install pilot ./pilot-chart \ --set secrets.githubToken=ghp_xxxx \ --set secrets.anthropicApiKey=sk-ant-xxxx

For a complete Helm reference including the official helm/pilot/ chart, values.yaml options, secret management (External Secrets, Sealed Secrets), and production hardening, see the Docker & Helm deployment guide.


Ingress

Expose Pilot via Ingress for webhook access:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: pilot annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: ingressClassName: nginx tls: - hosts: - pilot.example.com secretName: pilot-tls rules: - host: pilot.example.com http: paths: - path: / pathType: Prefix backend: service: name: pilot port: number: 9090

Scaling Considerations

Do not use HPA (Horizontal Pod Autoscaler) with Pilot.

Pilot uses SQLite for state and is designed for single-instance operation. Running multiple replicas will cause:

  • Database lock contention
  • Duplicate task processing
  • Inconsistent state

For high availability, consider:

  • Using a deployment with replicas: 1 and a Recreate strategy
  • Monitoring with alerts for pod restarts
  • Database backup/restore procedures
spec: replicas: 1 strategy: type: Recreate # Ensures clean shutdown before new pod starts