# Networking e Ingress ## Arquitectura de Red ``` Internet │ ▼ [LoadBalancer] (Cloud Provider) │ ▼ [Nginx Ingress Controller] │ ├──► api.aiworker.dev ──► Backend (control-plane) ├──► git.aiworker.dev ──► Gitea (gitea) ├──► app.aiworker.dev ──► Frontend (control-plane) ├──► *.preview.aiworker.dev ──► Preview Deployments ├──► staging-*.aiworker.dev ──► Staging Envs └──► *.aiworker.dev ──► Production Apps ``` ## Ingress Configuration ### Wildcard Certificate ```yaml # k8s/ingress/wildcard-certificate.yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-aiworker namespace: ingress-nginx spec: secretName: wildcard-aiworker-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer commonName: "*.aiworker.dev" dnsNames: - "aiworker.dev" - "*.aiworker.dev" - "*.preview.aiworker.dev" ``` ### Backend Ingress ```yaml # k8s/ingress/backend-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: backend-ingress namespace: control-plane annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/websocket-services: "aiworker-backend" nginx.ingress.kubernetes.io/proxy-body-size: "50m" nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.aiworker.dev" nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, PATCH, DELETE, OPTIONS" nginx.ingress.kubernetes.io/cors-allow-credentials: "true" spec: ingressClassName: nginx tls: - hosts: - api.aiworker.dev secretName: backend-tls rules: - host: api.aiworker.dev http: paths: - path: / pathType: Prefix backend: service: name: aiworker-backend port: number: 3000 ``` ### Frontend Ingress ```yaml # k8s/ingress/frontend-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: frontend-ingress namespace: control-plane annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/configuration-snippet: | more_set_headers "X-Frame-Options: DENY"; more_set_headers "X-Content-Type-Options: nosniff"; more_set_headers "X-XSS-Protection: 1; mode=block"; spec: ingressClassName: nginx tls: - hosts: - app.aiworker.dev secretName: frontend-tls rules: - host: app.aiworker.dev http: paths: - path: / pathType: Prefix backend: service: name: aiworker-frontend port: number: 80 ``` ### Preview Deployments Ingress Template ```typescript // services/kubernetes/ingress.ts export function generatePreviewIngress(params: { taskId: string projectName: string namespace: string }) { const shortId = params.taskId.slice(0, 8) const host = `task-${shortId}.preview.aiworker.dev` return { apiVersion: 'networking.k8s.io/v1', kind: 'Ingress', metadata: { name: `${params.projectName}-preview`, namespace: params.namespace, annotations: { 'cert-manager.io/cluster-issuer': 'letsencrypt-prod', 'nginx.ingress.kubernetes.io/ssl-redirect': 'true', 'nginx.ingress.kubernetes.io/auth-type': 'basic', 'nginx.ingress.kubernetes.io/auth-secret': 'preview-basic-auth', 'nginx.ingress.kubernetes.io/auth-realm': 'Preview Environment', }, labels: { environment: 'preview', task: params.taskId, project: params.projectName, }, }, spec: { ingressClassName: 'nginx', tls: [ { hosts: [host], secretName: `${params.projectName}-preview-tls`, }, ], rules: [ { host, http: { paths: [ { path: '/', pathType: 'Prefix', backend: { service: { name: `${params.projectName}-preview`, port: { number: 80, }, }, }, }, ], }, }, ], }, } } ``` ## Service Mesh (Opcional) Si necesitas más control sobre el tráfico, considera usar Istio o Linkerd: ### Istio Gateway ```yaml apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: aiworker-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE credentialName: wildcard-aiworker-tls hosts: - "*.aiworker.dev" --- apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: backend-vs namespace: control-plane spec: hosts: - "api.aiworker.dev" gateways: - istio-system/aiworker-gateway http: - match: - uri: prefix: /api route: - destination: host: aiworker-backend port: number: 3000 ``` ## DNS Configuration ### Cloudflare DNS Records ```bash # A records api.aiworker.dev A git.aiworker.dev A app.aiworker.dev A # Wildcard for preview and dynamic environments *.preview.aiworker.dev A *.aiworker.dev A ``` ### External DNS (Automated) ```yaml # k8s/external-dns/external-dns-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: external-dns namespace: kube-system spec: replicas: 1 selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns spec: serviceAccountName: external-dns containers: - name: external-dns image: registry.k8s.io/external-dns/external-dns:v0.14.0 args: - --source=ingress - --domain-filter=aiworker.dev - --provider=cloudflare env: - name: CF_API_TOKEN valueFrom: secretKeyRef: name: cloudflare-api-token key: token ``` ## Network Policies ### Isolate Preview Environments ```yaml # k8s/network-policies/preview-isolation.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: preview-isolation namespace: agents spec: podSelector: matchLabels: environment: preview policyTypes: - Ingress - Egress ingress: # Allow from ingress controller - from: - namespaceSelector: matchLabels: name: ingress-nginx # Allow from control-plane - from: - namespaceSelector: matchLabels: name: control-plane egress: # Allow to gitea - to: - namespaceSelector: matchLabels: name: gitea # Allow to external HTTPS (npm, apt, etc) - to: - namespaceSelector: {} ports: - protocol: TCP port: 443 # Allow DNS - to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - protocol: UDP port: 53 ``` ### Allow Backend to All ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: backend-egress namespace: control-plane spec: podSelector: matchLabels: app: aiworker-backend policyTypes: - Egress egress: - {} # Allow all egress ``` ## Load Balancing ### Session Affinity for WebSocket ```yaml apiVersion: v1 kind: Service metadata: name: aiworker-backend namespace: control-plane annotations: service.beta.kubernetes.io/external-traffic: OnlyLocal spec: selector: app: aiworker-backend ports: - name: http port: 3000 targetPort: 3000 sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 3600 type: ClusterIP ``` ## Rate Limiting ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: backend-ingress namespace: control-plane annotations: nginx.ingress.kubernetes.io/rate-limit: "100" nginx.ingress.kubernetes.io/rate-limit-burst: "200" nginx.ingress.kubernetes.io/rate-limit-key: "$binary_remote_addr" spec: # ... spec ``` ## Health Checks ### Liveness and Readiness Probes ```yaml livenessProbe: httpGet: path: /api/health port: 3000 httpHeaders: - name: X-Health-Check value: liveness initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /api/health/ready port: 3000 initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 ``` ### Health Endpoint Implementation ```typescript // api/routes/health.ts import { Router } from 'express' import { getDatabase } from '../../config/database' import { getRedis } from '../../config/redis' const router = Router() router.get('/health', async (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString(), }) }) router.get('/health/ready', async (req, res) => { try { // Check DB const db = getDatabase() await db.execute('SELECT 1') // Check Redis const redis = getRedis() await redis.ping() res.json({ status: 'ready', services: { database: 'connected', redis: 'connected', }, }) } catch (error) { res.status(503).json({ status: 'not ready', error: error.message, }) } }) export default router ``` ## Monitoring Traffic ```bash # Ver logs de Nginx Ingress kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=100 -f # Ver métricas kubectl top pods -n ingress-nginx # Ver configuración generada kubectl exec -n ingress-nginx -- cat /etc/nginx/nginx.conf ```