Deployment Architecture
Patterns and patterns for deploying agent systems: containers, serverless, edge, and hybrid.
Deployment Models
| Model | Description | Use Case |
|---|---|---|
| Container | Docker/Kubernetes, full control | Production, consistent env |
| Serverless | Functions, pay-per-use | Variable load, cost-sensitive |
| Edge | CDN edge, low latency | Global, real-time |
| Hybrid | Mix of above | Complex workloads |
| On-Premise | Private cloud, air-gapped | Compliance, data sovereignty |
| Multi-Cloud | Multiple providers | Redundancy, best-of-breed |
Container Deployment
Kubernetes (Recommended for Production)
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent-service
labels:
app: agent-service
version: v1.2.3
spec:
replicas: 3
selector:
matchLabels:
app: agent-service
template:
metadata:
labels:
app: agent-service
version: v1.2.3
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
serviceAccountName: agent-service
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: agent
image: myorg/agent-service:v1.2.3
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: agent-secrets
key: openai-api-key
- name: LANGCHAIN_API_KEY
valueFrom:
secretKeyRef:
name: agent-secrets
key: langchain-api-key
- name: ENVIRONMENT
value: "production"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "2Gi"
cpu: "2000m"
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
volumeMounts:
- name: cache
mountPath: /tmp/cache
volumes:
- name: cache
emptyDir:
sizeLimit: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: agent-service
spec:
selector:
app: agent-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: agent-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: agent-service
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
Helm Chart Structure
agent-service/
├── Chart.yaml
├── values.yaml
├── values-prod.yaml
├── values-staging.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── servicemonitor.yaml
│ ├── secret.yaml
│ ├── configmap.yaml
│ └── _helpers.tpl
└── charts/
└── dependencies/
values.yaml
# values.yaml
replicaCount: 3
image:
repository: myorg/agent-service
pullPolicy: Always
tag: "v1.2.3"
service:
type: ClusterIP
port: 80
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 50
targetCPUUtilization: 70
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rate-limit: "100"
hosts:
- host: agent.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: agent-tls
hosts:
- agent.example.com
monitoring:
enabled: true
serviceMonitor:
enabled: true
interval: 30s
secrets:
- name: OPENAI_API_KEY
externalSecret: agent-secrets
- name: LANGCHAIN_API_KEY
externalSecret: agent-secrets
config:
ENVIRONMENT: production
LOG_LEVEL: info
MAX_TOKENS: "4096"
Deployment Commands
# Install
helm install agent-service ./agent-service -f values-prod.yaml --namespace production
# Upgrade
helm upgrade agent-service ./agent-service -f values-prod.yaml --namespace production
# Rollback
helm rollback agent-service 3 --namespace production
# Status
helm status agent-service --namespace production
Serverless Deployment
AWS Lambda (with API Gateway)
# serverless.yml
service: agent-service
provider:
name: aws
runtime: python3.11
region: us-east-1
stage: ${opt:stage, 'prod'}
memorySize: 1024
timeout: 30
environment:
OPENAI_API_KEY: ${env:OPENAI_API_KEY}
LANGCHAIN_API_KEY: ${env:LANGCHAIN_API_KEY}
ENVIRONMENT: ${self:provider.stage}
vpc:
securityGroupIds:
- ${env:SG_ID}
subnetIds:
- ${env:SUBNET_1}
- ${env:SUBNET_2}
functions:
agent:
handler: handler.lambda_handler
events:
- httpApi:
path: /agent
method: post
authorizer: jwt
reservedConcurrency: 100
layers:
- {Ref: PythonDependenciesLayer}
layers:
PythonDependenciesLayer:
path: layer
compatibleRuntimes:
- python3.11
resources:
Resources:
AgentTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: agent-sessions-${self:provider.stage}
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: session_id
AttributeType: S
KeySchema:
- AttributeName: session_id
KeyType: HASH
TTLSpecification:
AttributeName: expires_at
Enabled: true
Deployment
# Deploy
serverless deploy --stage prod
# Invoke
serverless invoke --function agent --data '{"input": "Hello"}'
# Logs
serverless logs --function agent --tail
Edge Deployment
Cloudflare Workers
// worker.js
import { Agent } from './agent';
export default {
async fetch(request, env, ctx) {
const agent = new Agent({
apiKey: env.OPENAI_API_KEY,
model: 'gpt-4o-mini' // Smaller model for edge
});
const request = await request.json();
const response = await agent.run(request.input);
return new Response(JSON.stringify({output: response}), {
headers: {'Content-Type': 'application/json'}
});
}
};
# Deploy
wrangler deploy --env production
# Configure secrets
wrangler secret put OPENAI_API_KEY --env production
Cloudflare Workers AI
// Using Cloudflare's built-in models
export default {
async fetch(request, env, ctx) {
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [{role: 'user', content: request.input}]
});
return Response.json({output: response.response});
}
};
Multi-Cloud Deployment
Crossplane (Universal Control Plane)
# composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: agentclusters.platform.example.org
spec:
group: platform.example.org
names:
kind: AgentCluster
plural: agentclusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
provider:
type: string
enum: [aws, gcp, azure]
region:
type: string
size:
type: string
enum: [small, medium, large]
---
# claim.yaml
apiVersion: platform.example.org/v1alpha1
kind: AgentCluster
metadata:
name: production-cluster
spec:
provider: aws
region: us-east-1
size: large
CI/CD Pipeline
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy Agent
on:
push:
branches: [main]
workflow_dispatch:
inputs:
environment:
type: choice
options: [staging, production]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: {python-version: '3.11'}
- run: pip install -r requirements.txt
- run: pytest --cov=src --cov-fail-under=80
- run: ruff check src
- run: mypy src
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker Image
run: |
docker build -t ${{ env.REGISTRY }}/agent-service:${{ github.sha }} .
- name: Push
run: |
echo ${{ secrets.REGISTRY_PASSWORD }} | docker login ${{ env.REGISTRY }} -u ${{ secrets.REGISTRY_USER }} --password-stdin
docker push ${{ env.REGISTRY }}/agent-service:${{ github.sha }}
deploy-staging:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to Staging
run: |
helm upgrade --install agent-service ./helm/agent-service \
-f values-staging.yaml \
--set image.tag=${{ github.sha }} \
--namespace staging
deploy-production:
needs: build
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to Production
run: |
helm upgrade --install agent-service ./helm/agent-service \
-f values-production.yaml \
--set image.tag=${{ github.sha }} \
--namespace production
- name: Verify Deployment
run: |
kubectl rollout status deployment/agent-service -n production --timeout=300s
- name: Smoke Tests
run: |
python scripts/smoke_tests.py --url https://agent.example.com
Blue-Green Deployment
# Argo Rollouts for Blue-Green
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: agent-service
spec:
replicas: 10
strategy:
blueGreen:
activeService: agent-service-blue
previewService: agent-service-green
autoPromotionEnabled: false
selector:
matchLabels:
app: agent-service
template:
metadata:
labels:
app: agent-service
spec:
containers:
- name: agent
image: myorg/agent-service:v1.2.3
ports:
- containerPort: 8080
# Promote
kubectl argo rollouts promote agent-service -n production
# Abort
kubectl argo rollouts abort agent-service -n production
# Status
kubectl argo rollouts get rollout agent-service -n production
Service Mesh (Istio)
# VirtualService for Canary
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: agent-service
spec:
hosts:
- agent.example.com
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: agent-service
subset: v2
weight: 100
- route:
- destination:
host: agent-service
subset: v1
weight: 90
- destination:
host: agent-service
subset: v2
weight: 10
---
# DestinationRule
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: agent-service
spec:
host: agent-service
subsets:
- name: v1
labels:
version: v1.2.2
- name: v2
labels:
version: v1.2.3
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
h2UpgradePolicy: UPGRADE
http1MaxPendingRequests: 100
http2MaxRequests: 1000
outlierDetection:
consecutive5xxErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
Database Migration
# ArgoCD Application for Migrations
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: agent-migrations
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/agent-migrations
targetRevision: HEAD
path: migrations
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
-- migration_v1.2.3.sql
BEGIN;
-- Add new column
ALTER TABLE agent_sessions ADD COLUMN metadata JSONB DEFAULT '{}';
-- Create index
CREATE INDEX idx_agent_sessions_user_id ON agent_sessions(user_id);
-- Update existing
UPDATE agent_sessions SET metadata = '{"migrated": true}' WHERE metadata = '{}';
COMMIT;
Related Notes
- Scaling Strategies — Scaling strategies
- Observability — Monitoring, logging
- Reliability — Circuit breakers, retries
- Security — Security hardening
- Cost Optimization — Cost optimization
- Compliance — Compliance
- CI CD Best Practices — CI/CD patterns
- Infrastructure as Code — IaC patterns
- Observability — Observability
- Git Workflow — GitOps
- Infrastructure as Code — Terraform, Pulumi
- CI CD Best Practices — CI/CD patterns
- Supply Chain Security — Supply chain security
- Secure Coding — Secure deployments
- Infrastructure as Code — Terraform, Pulumi
- Supply Chain Security — Supply chain security
- Research Directions — Deployment research
Sources: Kubernetes docs, Helm docs, ArgoCD docs, Argo Rollouts, Istio docs, Crossplane docs, AWS Lambda, Serverless Framework, Cloudflare Workers, Cloudflare Workers AI, GitHub Actions, Argo Workflows, Tekton, Spinnaker, Flux, Flagger, KEDA, Kustomize, KPT, Kustomize, Skaffold, Tilt, Garden, DevSpace, Okteto, Telepresence, Skaffold, Garden, DevSpace, Okteto, Telepresence, Skaffold.