Plataforma de Video Streaming con Transcodificación y CDN Local en Kubernetes

Despliega tu propia Plataforma de Video Streaming con Transcodificación y CDN Local en Kubernetes

Hoy vamos a llevar Kubernetes a otro nivel montando una plataforma de video streaming con transcodificación automática y un pequeño CDN local. Así, podrás crear tu propio clon de YouTube o Twitch usando tu VPS, mientras aprendes a desplegar los microservicios más demandados: ensamblaremos Nginx para servir vídeos estáticos, FFmpeg en un pod para transcodificar y un backend ligero (Node.js) para gestionar las colas y la subida de archivos.

¿Por qué es útil este proyecto?

  • Escalabilidad: Podrás añadir réplicas de tus servicios según aumente tu tráfico.
  • Práctica real: Usarás patrones usados por servicios de streaming profesionales.
  • Automatización: FFmpeg trabaja en segundo plano generando versiones adaptativas de los vídeos.
  • Entrega eficiente: El CDN con Nginx minimiza latencia localmente, ideal para audiencias cercanas.

Arquitectura rápida del sistema

  1. Usuario sube vídeo al backend (Node.js).
  2. El backend almacena el vídeo y ordena a FFmpeg que lo transcodifique a varios formatos.
  3. Los archivos resultantes se sirven mediante Nginx (nuestro mini CDN local).

Ficheros yaml: Despliegue completo en Kubernetes

1. Namespace del proyecto

apiVersion: v1
kind: Namespace
metadata:
  name: videostream

2. Volumen Persistente compartido (vídeos y transcodificados)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: video-pvc
  namespace: videostream
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 30Gi

3. Backend para subida de vídeos (Node.js)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: video-backend
  namespace: videostream
spec:
  replicas: 1
  selector:
    matchLabels:
      app: video-backend
  template:
    metadata:
      labels:
        app: video-backend
    spec:
      containers:
      - name: node-backend
        image: ghcr.io/tuusuario/video-backend:latest
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: videodata
          mountPath: /data
      volumes:
      - name: videodata
        persistentVolumeClaim:
          claimName: video-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: videostream
spec:
  selector:
    app: video-backend
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000

Este backend acepta uploads, los guarda en /data/input, y comunica vía API con FFmpeg para la transcodificación.

4. Worker FFmpeg: transcodificación automática

apiVersion: apps/v1
kind: Deployment
metadata:
  name: transcode-worker
  namespace: videostream
spec:
  replicas: 1
  selector:
    matchLabels:
      app: transcode-worker
  template:
    metadata:
      labels:
        app: transcode-worker
    spec:
      containers:
      - name: ffmpeg-worker
        image: jrottenberg/ffmpeg:5-scratch
        command: ["/bin/sh"]
        args: ["-c", "while true; do node /worker.js; sleep 5; done"]
        volumeMounts:
        - name: videodata
          mountPath: /data
      volumes:
      - name: videodata
        persistentVolumeClaim:
          claimName: video-pvc


El script worker.js monitoriza una carpeta de entrada y ejecuta FFmpeg para crear varias versiones del vídeo (baja/HD), dejando resultados en /data/output.

5. Nginx (CDN local) para servir los vídeos transcodificados

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-cdn
  namespace: videostream
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-cdn
  template:
    metadata:
      labels:
        app: nginx-cdn
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        volumeMounts:
        - name: videodata
          mountPath: /usr/share/nginx/html
          subPath: output
      volumes:
      - name: videodata
        persistentVolumeClaim:
          claimName: video-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: cdn
  namespace: videostream
spec:
  selector:
    app: nginx-cdn
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
    

Los vídeos transcodificados estarán disponibles en rutas tipo http://.../video.mp4 o adaptativamente si incluyes HLS.

Extra: Ingreso externo (Nginx Ingress recomendado)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: videostream-ingress
  namespace: videostream
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: vstream.tudominio.com
    http:
      paths:
      - pathType: Prefix
        path: /api(/|$)(.*)
        backend:
          service:
            name: backend
            port:
              number: 80
      - pathType: Prefix
        path: /cdn(/|$)(.*)
        backend:
          service:
            name: cdn
            port:
              number: 8080

¡A jugar!

  1. Despliega los yaml en un VPS con almacenamiento suficiente.
  2. Compila tu backend y tu worker FFmpeg en imágenes propias (puedes usar Node.js y un Dockerfile sencillo).
  3. Disfruta subiendo vídeos y viendo cómo se transcodifican y sirven por tu propio miniCDN.

Tips y Troubleshooting

  • Básico: Verifica permisos de lectura/escritura en el PVC para evitar errores de acceso.
  • Escalado: Para aguantar más tráfico, sube replicas solo en el Nginx o en el backend.
  • Colas: Si crecen los uploads, implementa un sistema de colas en tu backend (ejemplo: Redis y BullMQ).
  • Transcodificación: Los pods FFmpeg pueden consumir mucha CPU, no los sobredimensiones; limita recursos en el yaml si ves que colapsan el nodo.
  • Vídeos lentos: Usa kubectl logs para ver si hay cuellos de botella en la transcodificación o delivery.
  • HTTPS: Recuerda proteger tu Ingress con TLS (Let’s Encrypt + cert-manager recomendado).

Esta plataforma modular te servirá tanto para pruebas internas, servicios privados de streaming o como base para proyectos mucho más grandes. ¿Te animas? ¡Déjame tus dudas en los comentarios!

Avatar

Por Mid