Prerequisites
- Kubernetes 1.28+
- kubectl configured
- Helm 3.12+ (optional)
- PostgreSQL database (managed or self-hosted)
- Container registry access
Quick Start
1. Create Namespace
kubectl create namespace agent-action-firewall
2. Create Secrets
kubectl create secret generic api-secrets \
--namespace agent-action-firewall \
--from-literal=DATABASE_URL='postgres://user:pass@host:5432/aaf_db' \
--from-literal=SUPABASE_JWT_SECRET='your-jwt-secret' \
--from-literal=ENCRYPTION_MASTER_KEY='your-32-byte-hex-key'
3. Apply Manifests
kubectl apply -f k8s/ --namespace agent-action-firewall
This deploys:
- API Deployment (3 replicas)
- Worker Deployment (2 replicas)
- Web Deployment (2 replicas)
- HPA for auto-scaling
- Ingress configuration
- ConfigMaps and Secrets
Architecture
flowchart TD
Ingress["Ingress (NGINX)"]
Ingress --> API["API\n(3 pods)"]
Ingress --> Web["Web\n(2 pods)"]
Ingress --> Worker["Worker\n(2 pods)"]
API --> PG["PostgreSQL\n(managed)"]
Worker --> PG
Manifests
Deployment
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: agent-action-firewall
spec:
replicas: 3
selector:
matchLabels:
app: aaf-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: aaf-api
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: api
image: ghcr.io/fubak/agent-action-firewall-api:latest
ports:
- containerPort: 3001
envFrom:
- secretRef:
name: api-secrets
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
livenessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3001
initialDelaySeconds: 5
periodSeconds: 5
Horizontal Pod Autoscaler
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
namespace: agent-action-firewall
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Ingress
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: aaf-ingress
namespace: agent-action-firewall
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.agentactionfirewall.com
- agentactionfirewall.com
secretName: aaf-tls
rules:
- host: api.agentactionfirewall.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 3001
- host: agentactionfirewall.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 3000
Configuration
ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
namespace: agent-action-firewall
data:
NODE_ENV: "production"
PORT: "3001"
HOST: "0.0.0.0"
LOG_LEVEL: "info"
OPA_URL: "http://opa:8181"
Secrets Management
For production, use external secrets management:
# Using External Secrets Operator
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: api-secrets
namespace: agent-action-firewall
spec:
refreshInterval: 1h
secretStoreRef:
name: vault
kind: SecretStore
target:
name: api-secrets
data:
- secretKey: DATABASE_URL
remoteRef:
key: aaf/database
property: url
- secretKey: ENCRYPTION_MASTER_KEY
remoteRef:
key: aaf/encryption
property: master_key
Monitoring
Prometheus Scraping
The API exposes metrics at /metrics:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "3001"
prometheus.io/path: "/metrics"
ServiceMonitor (Prometheus Operator)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: aaf-api
namespace: agent-action-firewall
spec:
selector:
matchLabels:
app: aaf-api
endpoints:
- port: http
path: /metrics
interval: 30s
High Availability
Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: agent-action-firewall
spec:
minAvailable: 2
selector:
matchLabels:
app: aaf-api
Pod Anti-Affinity
spec:
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: aaf-api
topologyKey: kubernetes.io/hostname
Troubleshooting
Pods not starting
Check pod events and logs:
kubectl describe pod -l app=aaf-api -n agent-action-firewall
kubectl logs -l app=aaf-api -n agent-action-firewall
Database connection issues
Verify secrets and network policies:
kubectl get secrets api-secrets -n agent-action-firewall -o yaml
kubectl exec -it deploy/api -n agent-action-firewall -- env | grep DATABASE
Ingress not working
Check ingress controller and certificates:
kubectl describe ingress aaf-ingress -n agent-action-firewall
kubectl get certificates -n agent-action-firewall
Upgrades
Rolling Update
# Update image tag
kubectl set image deployment/api \
api=ghcr.io/fubak/agent-action-firewall-api:v1.6.0 \
-n agent-action-firewall
# Watch rollout
kubectl rollout status deployment/api -n agent-action-firewall
Rollback
kubectl rollout undo deployment/api -n agent-action-firewall