709 lines
15 KiB
Markdown
709 lines
15 KiB
Markdown
🎯 ARQUITECTURA PROPUESTA PARA KUBERNETES
|
|
|
|
Stack Definitivo:
|
|
|
|
- Pre/Post-Evento: Typebot + Formbricks (ambos en K8s)
|
|
- Durante Evento: Claper (en K8s)
|
|
- Datos: PostgreSQL (con operador en K8s)
|
|
- Storage: PVC para persistencia
|
|
|
|
📦 CONFIGURACIONES KUBERNETES
|
|
|
|
1. Typebot Deployment
|
|
|
|
# typebot-deployment.yaml
|
|
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: rust-meetup
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: typebot-config
|
|
namespace: rust-meetup
|
|
data:
|
|
DATABASE_URL: "postgresql://typebot:password@postgres-service:5432/typebot"
|
|
NEXTAUTH_URL: "<https://typebot.rustmeetup.com>"
|
|
NEXT_PUBLIC_VIEWER_URL: "<https://typebot.rustmeetup.com>"
|
|
ENCRYPTION_SECRET: "your-encryption-secret-min-32-chars"
|
|
ADMIN_EMAIL: "<admin@rustmeetup.com>"
|
|
---
|
|
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: typebot
|
|
namespace: rust-meetup
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: typebot
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: typebot
|
|
spec:
|
|
containers:
|
|
- name: typebot
|
|
image: baptistearno/typebot:latest
|
|
ports:
|
|
- containerPort: 3000
|
|
envFrom:
|
|
- configMapRef:
|
|
name: typebot-config
|
|
resources:
|
|
requests:
|
|
memory: "512Mi"
|
|
cpu: "250m"
|
|
limits:
|
|
memory: "1Gi"
|
|
cpu: "500m"
|
|
volumeMounts:
|
|
- name: typebot-storage
|
|
mountPath: /app/uploads
|
|
volumes:
|
|
- name: typebot-storage
|
|
persistentVolumeClaim:
|
|
claimName: typebot-pvc
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: typebot-service
|
|
namespace: rust-meetup
|
|
spec:
|
|
selector:
|
|
app: typebot
|
|
ports:
|
|
- port: 80
|
|
targetPort: 3000
|
|
type: ClusterIP
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: typebot-pvc
|
|
namespace: rust-meetup
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteMany
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
storageClassName: standard
|
|
|
|
1. Formbricks Deployment
|
|
|
|
# formbricks-deployment.yaml
|
|
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: formbricks-config
|
|
namespace: rust-meetup
|
|
data:
|
|
DATABASE_URL: "postgresql://formbricks:password@postgres-service:5432/formbricks"
|
|
NEXTAUTH_SECRET: "your-nextauth-secret-32-chars"
|
|
NEXTAUTH_URL: "<https://surveys.rustmeetup.com>"
|
|
MAIL_FROM: "<noreply@rustmeetup.com>"
|
|
SMTP_HOST: "smtp.gmail.com"
|
|
SMTP_PORT: "587"
|
|
SMTP_SECURE: "false"
|
|
---
|
|
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: formbricks
|
|
namespace: rust-meetup
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: formbricks
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: formbricks
|
|
spec:
|
|
containers:
|
|
- name: formbricks
|
|
image: formbricks/formbricks:latest
|
|
ports:
|
|
- containerPort: 3000
|
|
envFrom:
|
|
- configMapRef:
|
|
name: formbricks-config
|
|
resources:
|
|
requests:
|
|
memory: "512Mi"
|
|
cpu: "250m"
|
|
limits:
|
|
memory: "1Gi"
|
|
cpu: "500m"
|
|
volumeMounts:
|
|
- name: formbricks-storage
|
|
mountPath: /home/nextjs/apps/web/uploads
|
|
volumes:
|
|
- name: formbricks-storage
|
|
persistentVolumeClaim:
|
|
claimName: formbricks-pvc
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: formbricks-service
|
|
namespace: rust-meetup
|
|
spec:
|
|
selector:
|
|
app: formbricks
|
|
ports:
|
|
- port: 80
|
|
targetPort: 3000
|
|
type: ClusterIP
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: formbricks-pvc
|
|
namespace: rust-meetup
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteMany
|
|
resources:
|
|
requests:
|
|
storage: 5Gi
|
|
|
|
1. Claper Deployment
|
|
|
|
# claper-deployment.yaml
|
|
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: claper-config
|
|
namespace: rust-meetup
|
|
data:
|
|
DATABASE_URL: "postgresql://claper:password@postgres-service:5432/claper"
|
|
SECRET_KEY_BASE: "your-secret-key-base-64-chars"
|
|
PHX_HOST: "claper.rustmeetup.com"
|
|
PORT: "4000"
|
|
---
|
|
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: claper
|
|
namespace: rust-meetup
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: claper
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: claper
|
|
spec:
|
|
containers:
|
|
- name: claper
|
|
image: claperco/claper:latest
|
|
ports:
|
|
- containerPort: 4000
|
|
envFrom:
|
|
- configMapRef:
|
|
name: claper-config
|
|
resources:
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "200m"
|
|
limits:
|
|
memory: "512Mi"
|
|
cpu: "400m"
|
|
volumeMounts:
|
|
- name: claper-uploads
|
|
mountPath: /app/uploads
|
|
volumes:
|
|
- name: claper-uploads
|
|
persistentVolumeClaim:
|
|
claimName: claper-pvc
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: claper-service
|
|
namespace: rust-meetup
|
|
spec:
|
|
selector:
|
|
app: claper
|
|
ports:
|
|
- port: 80
|
|
targetPort: 4000
|
|
type: ClusterIP
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: claper-pvc
|
|
namespace: rust-meetup
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteMany
|
|
resources:
|
|
requests:
|
|
storage: 20Gi
|
|
|
|
1. PostgreSQL con Operador
|
|
|
|
# postgres-operator.yaml
|
|
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: postgres-config
|
|
namespace: rust-meetup
|
|
data:
|
|
init.sql: |
|
|
CREATE DATABASE typebot;
|
|
CREATE USER typebot WITH ENCRYPTED PASSWORD 'password';
|
|
GRANT ALL PRIVILEGES ON DATABASE typebot TO typebot;
|
|
|
|
CREATE DATABASE formbricks;
|
|
CREATE USER formbricks WITH ENCRYPTED PASSWORD 'password';
|
|
GRANT ALL PRIVILEGES ON DATABASE formbricks TO formbricks;
|
|
|
|
CREATE DATABASE claper;
|
|
CREATE USER claper WITH ENCRYPTED PASSWORD 'password';
|
|
GRANT ALL PRIVILEGES ON DATABASE claper TO claper;
|
|
---
|
|
|
|
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: postgres
|
|
namespace: rust-meetup
|
|
spec:
|
|
serviceName: postgres-service
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: postgres
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: postgres
|
|
spec:
|
|
containers:
|
|
- name: postgres
|
|
image: postgres:15-alpine
|
|
ports:
|
|
- containerPort: 5432
|
|
env:
|
|
- name: POSTGRES_PASSWORD
|
|
value: "superpassword"
|
|
- name: POSTGRES_USER
|
|
value: "postgres"
|
|
- name: PGDATA
|
|
value: /var/lib/postgresql/data/pgdata
|
|
volumeMounts:
|
|
- name: postgres-storage
|
|
mountPath: /var/lib/postgresql/data
|
|
- name: postgres-init
|
|
mountPath: /docker-entrypoint-initdb.d
|
|
resources:
|
|
requests:
|
|
memory: "256Mi"
|
|
cpu: "250m"
|
|
limits:
|
|
memory: "512Mi"
|
|
cpu: "500m"
|
|
volumes:
|
|
- name: postgres-init
|
|
configMap:
|
|
name: postgres-config
|
|
volumeClaimTemplates:
|
|
- metadata:
|
|
name: postgres-storage
|
|
spec:
|
|
accessModes: ["ReadWriteOnce"]
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
---
|
|
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: postgres-service
|
|
namespace: rust-meetup
|
|
spec:
|
|
selector:
|
|
app: postgres
|
|
ports:
|
|
- port: 5432
|
|
type: ClusterIP
|
|
|
|
1. Ingress Configuration
|
|
|
|
# ingress.yaml
|
|
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: rust-meetup-ingress
|
|
namespace: rust-meetup
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
|
spec:
|
|
ingressClassName: nginx
|
|
tls:
|
|
- hosts:
|
|
- typebot.rustmeetup.com
|
|
- surveys.rustmeetup.com
|
|
- claper.rustmeetup.com
|
|
secretName: rust-meetup-tls
|
|
rules:
|
|
- host: typebot.rustmeetup.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: typebot-service
|
|
port:
|
|
number: 80
|
|
- host: surveys.rustmeetup.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: formbricks-service
|
|
port:
|
|
number: 80
|
|
- host: claper.rustmeetup.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: claper-service
|
|
port:
|
|
number: 80
|
|
|
|
🚀 HELM CHARTS ALTERNATIVOS
|
|
|
|
Opción con Helm (Más Mantenible)
|
|
|
|
# values-typebot.yaml
|
|
|
|
replicaCount: 2
|
|
image:
|
|
repository: baptistearno/typebot
|
|
tag: latest
|
|
pullPolicy: IfNotPresent
|
|
|
|
service:
|
|
type: ClusterIP
|
|
port: 80
|
|
|
|
ingress:
|
|
enabled: true
|
|
className: nginx
|
|
hosts:
|
|
- host: typebot.rustmeetup.com
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
tls:
|
|
- secretName: typebot-tls
|
|
hosts:
|
|
- typebot.rustmeetup.com
|
|
|
|
postgresql:
|
|
enabled: false
|
|
external:
|
|
host: postgres-service
|
|
port: 5432
|
|
database: typebot
|
|
user: typebot
|
|
|
|
persistence:
|
|
enabled: true
|
|
size: 10Gi
|
|
storageClass: standard
|
|
|
|
resources:
|
|
requests:
|
|
cpu: 250m
|
|
memory: 512Mi
|
|
limits:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
|
|
autoscaling:
|
|
enabled: true
|
|
minReplicas: 2
|
|
maxReplicas: 10
|
|
targetCPUUtilizationPercentage: 70
|
|
|
|
📊 MONITOREO Y OBSERVABILIDAD
|
|
|
|
# monitoring-stack.yaml
|
|
|
|
apiVersion: v1
|
|
kind: ServiceMonitor
|
|
metadata:
|
|
name: typebot-metrics
|
|
namespace: rust-meetup
|
|
spec:
|
|
selector:
|
|
matchLabels:
|
|
app: typebot
|
|
endpoints:
|
|
- port: metrics
|
|
interval: 30s
|
|
---
|
|
|
|
# Grafana Dashboard ConfigMap
|
|
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: grafana-dashboards
|
|
namespace: rust-meetup
|
|
data:
|
|
rust-meetup-dashboard.json: |
|
|
{
|
|
"dashboard": {
|
|
"title": "Rust Meetup 2025 Metrics",
|
|
"panels": [
|
|
{
|
|
"title": "Active Survey Sessions",
|
|
"targets": [
|
|
{
|
|
"expr": "sum(typebot_active_sessions)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"title": "Response Rate",
|
|
"targets": [
|
|
{
|
|
"expr": "rate(typebot_responses_total[5m])"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"title": "Live Poll Participation",
|
|
"targets": [
|
|
{
|
|
"expr": "sum(claper_active_participants)"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
🔧 SCRIPTS DE DEPLOYMENT
|
|
|
|
Deploy Script
|
|
|
|
#!/bin/bash
|
|
|
|
# deploy.sh - Deploy completo del stack
|
|
|
|
echo "🚀 Deploying Rust Meetup 2025 Stack on Kubernetes"
|
|
|
|
# Create namespace
|
|
|
|
kubectl create namespace rust-meetup --dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
# Deploy PostgreSQL
|
|
|
|
echo "📊 Deploying PostgreSQL..."
|
|
kubectl apply -f postgres-operator.yaml
|
|
|
|
# Wait for PostgreSQL to be ready
|
|
|
|
kubectl wait --for=condition=ready pod -l app=postgres -n rust-meetup --timeout=300s
|
|
|
|
# Deploy applications
|
|
|
|
echo "🎯 Deploying Typebot..."
|
|
kubectl apply -f typebot-deployment.yaml
|
|
|
|
echo "📝 Deploying Formbricks..."
|
|
kubectl apply -f formbricks-deployment.yaml
|
|
|
|
echo "🎤 Deploying Claper..."
|
|
kubectl apply -f claper-deployment.yaml
|
|
|
|
# Deploy Ingress
|
|
|
|
echo "🌐 Configuring Ingress..."
|
|
kubectl apply -f ingress.yaml
|
|
|
|
# Check deployment status
|
|
|
|
echo "✅ Checking deployment status..."
|
|
kubectl get pods -n rust-meetup
|
|
kubectl get svc -n rust-meetup
|
|
kubectl get ingress -n rust-meetup
|
|
|
|
echo "🎉 Deployment complete!"
|
|
|
|
Backup Script
|
|
|
|
#!/bin/bash
|
|
|
|
# backup.sh - Backup de datos
|
|
|
|
NAMESPACE="rust-meetup"
|
|
BACKUP_DIR="/backups/$(date +%Y%m%d-%H%M%S)"
|
|
|
|
# Backup PostgreSQL
|
|
|
|
kubectl exec -n $NAMESPACE postgres-0 -- pg_dumpall -U postgres > $BACKUP_DIR/postgres-backup.sql
|
|
|
|
# Backup persistent volumes
|
|
|
|
kubectl get pvc -n $NAMESPACE -o json > $BACKUP_DIR/pvcs.json
|
|
|
|
# Upload to S3
|
|
|
|
aws s3 sync $BACKUP_DIR s3://rust-meetup-backups/
|
|
|
|
💡 MEJORES PRÁCTICAS
|
|
|
|
1. Seguridad
|
|
|
|
# Network Policy
|
|
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: NetworkPolicy
|
|
metadata:
|
|
name: rust-meetup-network-policy
|
|
namespace: rust-meetup
|
|
spec:
|
|
podSelector: {}
|
|
policyTypes:
|
|
- Ingress
|
|
- Egress
|
|
ingress:
|
|
- from:
|
|
- namespaceSelector:
|
|
matchLabels:
|
|
name: ingress-nginx
|
|
egress:
|
|
- to:
|
|
- podSelector:
|
|
matchLabels:
|
|
app: postgres
|
|
- to:
|
|
- namespaceSelector: {}
|
|
podSelector:
|
|
matchLabels:
|
|
k8s-app: kube-dns
|
|
ports:
|
|
- protocol: UDP
|
|
port: 53
|
|
|
|
1. Auto-scaling
|
|
|
|
apiVersion: autoscaling/v2
|
|
kind: HorizontalPodAutoscaler
|
|
metadata:
|
|
name: typebot-hpa
|
|
namespace: rust-meetup
|
|
spec:
|
|
scaleTargetRef:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
name: typebot
|
|
minReplicas: 2
|
|
maxReplicas: 20
|
|
metrics:
|
|
- type: Resource
|
|
resource:
|
|
name: cpu
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 70
|
|
- type: Resource
|
|
resource:
|
|
name: memory
|
|
target:
|
|
type: Utilization
|
|
averageUtilization: 80
|
|
behavior:
|
|
scaleUp:
|
|
stabilizationWindowSeconds: 60
|
|
policies:
|
|
- type: Percent
|
|
value: 100
|
|
periodSeconds: 60
|
|
|
|
📋 CHECKLIST DE PRODUCCIÓN
|
|
|
|
Pre-Deployment
|
|
|
|
- Cluster Kubernetes ready (EKS/GKE/AKS/on-prem)
|
|
- Ingress controller instalado (nginx/traefik)
|
|
- Cert-manager configurado
|
|
- Storage class disponible
|
|
- Secrets management (Sealed Secrets/Vault)
|
|
|
|
Deployment
|
|
|
|
- Deploy PostgreSQL y verificar
|
|
- Deploy apps y verificar pods running
|
|
- Configurar DNS para subdominios
|
|
- Verificar certificados SSL
|
|
- Test end-to-end de cada aplicación
|
|
|
|
Post-Deployment
|
|
|
|
- Configurar backups automáticos
|
|
- Setup monitoring (Prometheus/Grafana)
|
|
- Configurar alertas
|
|
- Load testing con k6/Locust
|
|
- Documentar runbooks
|
|
|
|
🎯 VENTAJAS DE ESTA ARQUITECTURA
|
|
|
|
1. Escalabilidad: Auto-scaling basado en métricas
|
|
2. Resiliencia: Multi-replica deployments
|
|
3. Portabilidad: Funciona en cualquier K8s
|
|
4. Observabilidad: Métricas y logs centralizados
|
|
5. Seguridad: Network policies y RBAC
|
|
6. Cost-Effective: Optimización de recursos
|
|
|
|
💰 ESTIMACIÓN DE COSTOS
|
|
|
|
| Componente | Recursos | Costo Mensual |
|
|
|-----------------------|------------------|---------------|
|
|
| K8s Cluster (3 nodes) | 6 vCPU, 12GB RAM | $150 |
|
|
| Storage | 50GB SSD | $10 |
|
|
| Load Balancer | 1 LB | $20 |
|
|
| Backups S3 | 100GB | $5 |
|
|
| TOTAL | | $185/mes |
|
|
|
|
¿Te gustaría que detalle algún aspecto específico o prepare los templates de Typebot para los cuestionarios?
|