Kubernetes
Stateless Deployment + Service + ConfigMap + Secret.
Deployment
# auth-backend.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth-backend
spec:
replicas: 3
selector:
matchLabels: { app: auth-backend }
template:
metadata:
labels: { app: auth-backend }
spec:
containers:
- name: auth
image: ghcr.io/identsphere/server:0.1
ports:
- containerPort: 4000
envFrom:
- configMapRef:
name: auth-config
env:
- name: IDENTSPHERE_JWT_SECRET
valueFrom:
secretKeyRef:
name: auth-secrets
key: jwt-secret
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: auth-secrets
key: database-url
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: 1000m, memory: 1Gi }
readinessProbe:
httpGet: { path: /health, port: 4000 }
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet: { path: /health, port: 4000 }
initialDelaySeconds: 30
periodSeconds: 30
Service + Ingress
---
apiVersion: v1
kind: Service
metadata:
name: auth-backend
spec:
selector: { app: auth-backend }
ports:
- port: 80
targetPort: 4000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auth-backend
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-body-size: 6m # avatar uploads up to 5 MiB
spec:
ingressClassName: nginx
tls:
- hosts: [auth.example.com]
secretName: auth-tls
rules:
- host: auth.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: auth-backend, port: { number: 80 } }
ConfigMap + Secret
---
apiVersion: v1
kind: ConfigMap
metadata:
name: auth-config
data:
IDENTSPHERE_PUBLIC_BASE_URL: "https://auth.example.com"
IDENTSPHERE_FROM_EMAIL: "no-reply@example.com"
IDENTSPHERE_COOKIES_SECURE: "true"
IDENTSPHERE_RP_ID: "auth.example.com"
IDENTSPHERE_RP_ORIGIN: "https://auth.example.com"
IDENTSPHERE_APP_NAME: "Acme"
RUST_LOG: "info,identsphere=debug"
---
apiVersion: v1
kind: Secret
metadata:
name: auth-secrets
type: Opaque
stringData:
jwt-secret: "REPLACE_WITH_OPENSSL_RAND_HEX_32"
database-url: "postgres://user:pw@postgres:5432/auth?sslmode=require"
Migrations as a Job
Run before each rollout:
apiVersion: batch/v1
kind: Job
metadata:
name: auth-migrate
spec:
ttlSecondsAfterFinished: 600
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: ghcr.io/identsphere/server:0.1
command: ["IdentSphere", "migrate", "up", "--schema", "identsphere"]
envFrom:
- secretRef: { name: auth-secrets }
Hook into your CI as a pre-deploy step. Migrations are idempotent and take an advisory lock.
Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: auth-backend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: auth-backend
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
CPU-based scaling tracks Argon2id load well.
PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: auth-backend
spec:
minAvailable: 2
selector:
matchLabels: { app: auth-backend }
Helm
A community Helm chart will live in charts/auth-backend/ (planned).
For now, paste the manifests above into templates/ and add a basic
values.yaml over the values you want to parameterize.
Secrets management
The Secret YAML above is illustrative. In production use:
- AWS: External Secrets Operator + Secrets Manager.
- GCP: External Secrets Operator + Secret Manager.
- Azure: AKS + CSI driver + Key Vault.
- HashiCorp Vault: VSO or vault-injector.
Avoid checking the secret YAML into Git.