Kubernetes Deployment
Deploy Boards on Kubernetes using the pre-built container images. This guide provides the manifests needed to run Boards in a Kubernetes cluster.
Prerequisites
- Kubernetes cluster (1.24+)
kubectlconfigured to access your cluster- Container registry access to
ghcr.io(or Docker Hub)
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Ingress │ │ Service │ │ Service │ │
│ │ (optional) │──│ boards-api │ │ boards-worker │ │
│ └─────────────┘ └──────┬──────┘ └──────────┬──────────┘ │
│ │ │ │
│ ┌───────────────────────┴─────────────────────┴──────────┐ │
│ │ Deployments │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ API Pods │ │ Worker Pods │ │ │
│ │ │ (replicas) │ │ (replicas) │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴─────────────────────────────────┐ │
│ │ ConfigMap / Secret │ │
│ └──────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌───────────┐
│PostgreSQL│ │ Redis │ │ Storage │
│(managed) │ │(managed) │ │ (S3/GCS) │
└─────────┘ └──────────┘ └───────────┘
For production, use managed services for PostgreSQL, Redis, and object storage rather than running them in Kubernetes.
Namespace
Create a dedicated namespace:
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: boards
Apply:
kubectl apply -f namespace.yaml
Secrets
Store sensitive configuration in a Kubernetes Secret:
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: boards-secrets
namespace: boards
type: Opaque
stringData:
# Database connection (use your managed PostgreSQL)
database-url: "postgresql://user:password@your-db-host:5432/boards?sslmode=require"
# Redis connection (use your managed Redis)
redis-url: "rediss://user:password@your-redis-host:6379/0"
# Generator API keys (JSON format)
generator-api-keys: '{"fal": "your-fal-key", "openai": "your-openai-key"}'
# Auth provider secrets (if using JWT)
jwt-secret: "your-jwt-secret-key"
# Storage credentials (if using S3)
aws-access-key-id: "your-access-key"
aws-secret-access-key: "your-secret-key"
Apply:
kubectl apply -f secret.yaml
warning
For production, use a secrets management solution like:
- Kubernetes External Secrets Operator
- HashiCorp Vault
- AWS Secrets Manager with IRSA
- Google Secret Manager with Workload Identity
ConfigMaps
Store non-sensitive configuration:
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: boards-config
namespace: boards
data:
# Auth configuration
BOARDS_AUTH_PROVIDER: "jwt"
# Logging
BOARDS_LOG_LEVEL: "info"
BOARDS_LOG_FORMAT: "json"
# Storage configuration file
storage_config.yaml: |
default_provider: s3
providers:
s3:
type: s3
bucket: my-boards-bucket
region: us-east-1
# Generators configuration file
generators.yaml: |
generators:
- class: boards.generators.fal.flux.FluxProGenerator
enabled: true
- class: boards.generators.openai.dalle.DallE3Generator
enabled: true
Apply:
kubectl apply -f configmap.yaml
API Deployment
# api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: boards-api
namespace: boards
labels:
app: boards
component: api
spec:
replicas: 2
selector:
matchLabels:
app: boards
component: api
template:
metadata:
labels:
app: boards
component: api
spec:
containers:
- name: api
image: ghcr.io/weirdfingers/boards-backend:latest
command: ["uvicorn", "boards.api.app:app", "--host", "0.0.0.0", "--port", "8800"]
ports:
- containerPort: 8800
name: http
env:
- name: BOARDS_DATABASE_URL
valueFrom:
secretKeyRef:
name: boards-secrets
key: database-url
- name: BOARDS_REDIS_URL
valueFrom:
secretKeyRef:
name: boards-secrets
key: redis-url
- name: BOARDS_GENERATOR_API_KEYS
valueFrom:
secretKeyRef:
name: boards-secrets
key: generator-api-keys
- name: BOARDS_AUTH_PROVIDER
valueFrom:
configMapKeyRef:
name: boards-config
key: BOARDS_AUTH_PROVIDER
- name: BOARDS_JWT_SECRET
valueFrom:
secretKeyRef:
name: boards-secrets
key: jwt-secret
- name: BOARDS_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: boards-config
key: BOARDS_LOG_LEVEL
- name: BOARDS_LOG_FORMAT
valueFrom:
configMapKeyRef:
name: boards-config
key: BOARDS_LOG_FORMAT
- name: BOARDS_GENERATORS_CONFIG_PATH
value: /app/config/generators.yaml
- name: BOARDS_STORAGE_CONFIG_PATH
value: /app/config/storage_config.yaml
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: boards-secrets
key: aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: boards-secrets
key: aws-secret-access-key
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "1000m"
readinessProbe:
httpGet:
path: /health
port: 8800
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8800
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: config
configMap:
name: boards-config
items:
- key: generators.yaml
path: generators.yaml
- key: storage_config.yaml
path: storage_config.yaml
Worker Deployment
# worker-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: boards-worker
namespace: boards
labels:
app: boards
component: worker
spec:
replicas: 2
selector:
matchLabels:
app: boards
component: worker
template:
metadata:
labels:
app: boards
component: worker
spec:
containers:
- name: worker
image: ghcr.io/weirdfingers/boards-backend:latest
command: ["boards-worker", "--log-level", "info", "--processes", "1", "--threads", "1"]
env:
- name: BOARDS_DATABASE_URL
valueFrom:
secretKeyRef:
name: boards-secrets
key: database-url
- name: BOARDS_REDIS_URL
valueFrom:
secretKeyRef:
name: boards-secrets
key: redis-url
- name: BOARDS_GENERATOR_API_KEYS
valueFrom:
secretKeyRef:
name: boards-secrets
key: generator-api-keys
- name: BOARDS_INTERNAL_API_URL
value: "http://boards-api:8800"
- name: BOARDS_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: boards-config
key: BOARDS_LOG_LEVEL
- name: BOARDS_LOG_FORMAT
valueFrom:
configMapKeyRef:
name: boards-config
key: BOARDS_LOG_FORMAT
- name: BOARDS_GENERATORS_CONFIG_PATH
value: /app/config/generators.yaml
- name: BOARDS_STORAGE_CONFIG_PATH
value: /app/config/storage_config.yaml
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: boards-secrets
key: aws-access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: boards-secrets
key: aws-secret-access-key
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "2Gi"
cpu: "2000m"
volumes:
- name: config
configMap:
name: boards-config
items:
- key: generators.yaml
path: generators.yaml
- key: storage_config.yaml
path: storage_config.yaml
Services
# services.yaml
apiVersion: v1
kind: Service
metadata:
name: boards-api
namespace: boards
labels:
app: boards
component: api
spec:
type: ClusterIP
ports:
- port: 8800
targetPort: 8800
protocol: TCP
name: http
selector:
app: boards
component: api
Ingress (Optional)
If using an Ingress controller:
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: boards-ingress
namespace: boards
annotations:
# Adjust annotations for your ingress controller
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- api.boards.example.com
secretName: boards-tls
rules:
- host: api.boards.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: boards-api
port:
number: 8800
Deploy All Manifests
Apply all manifests:
kubectl apply -f namespace.yaml
kubectl apply -f secret.yaml
kubectl apply -f configmap.yaml
kubectl apply -f api-deployment.yaml
kubectl apply -f worker-deployment.yaml
kubectl apply -f services.yaml
kubectl apply -f ingress.yaml # if using ingress
Or combine into a single file and apply:
kubectl apply -f boards-k8s.yaml
Verify deployment:
kubectl -n boards get pods
kubectl -n boards get services
kubectl -n boards logs -l component=api -f
Scaling
Manual Scaling
# Scale API pods
kubectl -n boards scale deployment boards-api --replicas=3
# Scale worker pods
kubectl -n boards scale deployment boards-worker --replicas=5
Horizontal Pod Autoscaler
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: boards-api-hpa
namespace: boards
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: boards-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: boards-worker-hpa
namespace: boards
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: boards-worker
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
Updates and Rollbacks
Rolling Update
# Update to a specific version
kubectl -n boards set image deployment/boards-api api=ghcr.io/weirdfingers/boards-backend:v1.2.0
kubectl -n boards set image deployment/boards-worker worker=ghcr.io/weirdfingers/boards-backend:v1.2.0
# Watch rollout status
kubectl -n boards rollout status deployment/boards-api
Rollback
# Rollback to previous version
kubectl -n boards rollout undo deployment/boards-api
kubectl -n boards rollout undo deployment/boards-worker
Troubleshooting
Check Pod Status
kubectl -n boards get pods
kubectl -n boards describe pod <pod-name>
View Logs
# API logs
kubectl -n boards logs -l component=api -f
# Worker logs
kubectl -n boards logs -l component=worker -f
# Specific pod logs
kubectl -n boards logs <pod-name> -f
Debug Connectivity
# Test database connection from a pod
kubectl -n boards exec -it <api-pod> -- python -c "from boards.db import engine; print(engine.url)"
# Test Redis connection
kubectl -n boards exec -it <api-pod> -- python -c "import redis; r = redis.from_url('$BOARDS_REDIS_URL'); print(r.ping())"
Check Resource Usage
kubectl -n boards top pods
Next Steps
- Configuration Reference - All environment variables
- Database Setup - Configure managed PostgreSQL
- Storage Configuration - Configure S3 or GCS storage
- Upgrades & Migrations - Upgrade versions and run database migrations
- Monitoring - Set up logging and metrics