Guía de configuración de Image Converter

Image converter es un microservicio de Node.js que renderiza fondos SVG de recintos en imágenes WebP optimizadas. Produce tres variantes por cada fondo: resolución completa, una previsualización de 1000px y un marcador de posición difuminado de 400px con datos base64 incorporados para la carga progresiva. Las imágenes se almacenan en almacenamiento de objetos compatible con S3 o en el sistema de archivos local.

Stack: Node.js 22, Express 5, Puppeteer (Chromium headless para renderizar SVG), Sharp (procesamiento de imágenes), Redis opcional (cola asíncrona de resultados).

Ajustes principales

Setting Type Default Descripción
PORT integer 3000 Puerto de escucha del servidor Express
NODE_ENV string production Entorno de Node
DEBUG boolean false Activa el modo de depuración (establece LOG_LEVEL en debug)
LOG_LEVEL string info Nivel de log de Winston: error, warn, info, http, verbose, debug

Ajustes de manejo de archivos

Setting Type Default Descripción
UPLOAD_FOLDER string /tmp Directorio temporal para los archivos subidos (se limpia tras el procesamiento)
MAX_CONTENT_LENGTH integer 16777216 Tamaño máximo del archivo subido en bytes (por defecto 16 MB)

Ajustes de procesamiento de imágenes

Setting Type Default Descripción
MAX_IMAGE_WIDTH integer 15000 Ancho máximo permitido de la imagen de salida en píxeles
MAX_IMAGE_HEIGHT integer 15000 Alto máximo permitido de la imagen de salida en píxeles
DEFAULT_WIDTH integer 440 Ancho por defecto para el endpoint básico de conversión
DEFAULT_HEIGHT integer 246 Alto por defecto para el endpoint básico de conversión
PNG_OPTIMIZATION boolean false Activa la compresión de imágenes
PNG_OPTIMIZATION_QUALITY string 0.6-0.8 Rango de calidad para la salida WebP

Ajustes de almacenamiento

Setting Type Default Descripción
STORAGE_TYPE string s3 Backend de almacenamiento: s3 o local
LOCAL_STORAGE_PATH string ./storage Ruta del sistema de archivos al usar almacenamiento local

Configuración de AWS S3

Estos ajustes son obligatorios cuando STORAGE_TYPE=s3.

Setting Type Default Descripción
AWS_ACCESS_KEY_ID string (required) Clave de acceso IAM para la autenticación en S3
AWS_SECRET_ACCESS_KEY string (required) Clave secreta IAM para la autenticación en S3
AWS_REGION string us-east-1 Región de AWS para el bucket de S3
AWS_BUCKET_NAME string (required) Nombre del bucket de S3 para almacenar las imágenes
AWS_ENDPOINT_URL string Endpoint S3 personalizado para proveedores compatibles con S3 (MinIO, DigitalOcean Spaces, Garage)
AWS_PUBLIC_BASE_URL string Sobrescribe la base de la URL pública para las URL de imágenes generadas (ver más abajo)

ImportantLas credenciales de AWS deben proporcionarse mediante variables de entorno seguras o secretos de Kubernetes. Nunca incluyas credenciales en el control de versiones.

Resolución de la URL pública

El conversor genera URL públicas para las imágenes subidas. La base de la URL se resuelve en este orden de prioridad:

  1. AWS_PUBLIC_BASE_URL (si está definida) — se usa tal cual. Ejemplo: https://bucket.nyc3.digitaloceanspaces.com
  2. AWS_ENDPOINT_URL (derivada) — path-style: {endpoint}/{bucket}. Ejemplo: https://storage.yandexcloud.net/my-bucket
  3. Por defecto — estilo virtual-hosted de AWS: https://{bucket}.s3.{region}.amazonaws.com

Los clientes self-hosted que usan proveedores de S3 distintos de AWS (DigitalOcean Spaces, MinIO, Garage, Yandex Cloud) deben definir AWS_PUBLIC_BASE_URL para garantizar URL públicas correctas.

Política del bucket de S3

Para permitir el acceso público de lectura a las imágenes, aplica la siguiente política de bucket:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }
  ]
}

Configuración de CORS

Para evitar problemas de tainted canvas al procesar imágenes en navegadores web, configura CORS en el bucket:

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET"],
    "AllowedOrigins": ["*"],
    "ExposeHeaders": []
  }
]

NotePara entornos de producción, restringe AllowedOrigins a tus dominios específicos en lugar de *.

Ajustes de Redis

Redis es opcional. Cuando está activado, los resultados de la conversión se envían a una cola de Redis para su procesamiento asíncrono por otros servicios.

Setting Type Default Descripción
REDIS_ENABLED boolean false Activa la cola de resultados de Redis
REDIS_HOST string localhost Nombre de host del servidor Redis
REDIS_PORT integer 6379 Puerto del servidor Redis
REDIS_PASSWORD string Contraseña de Redis (si se requiere autenticación)
REDIS_QUEUE_NAME string conversion_results Nombre de la cola para almacenar los resultados de la conversión

Si Redis está desactivado o no disponible, las conversiones igualmente se completan con éxito: la publicación en la cola no es bloqueante.

Endpoints de la API

Method Path Descripción
POST / Conversión básica de SVG a imagen. Devuelve el archivo de imagen directamente. Query params: width, height
POST /background/ Conversión completa de fondo. Devuelve JSON con las URL de las tres variantes (full, preview, blurred). Query params: filename, debug
POST /thumbnail/ Conversión de miniatura. Devuelve JSON con las URL de las tres variantes. Query params: filename, debug
GET /health Comprobación de estado del servicio. Devuelve { "status": "healthy" }
GET /health/redis Estado de la conexión con Redis y longitud de la cola
GET /metrics Métricas de Prometheus en formato de texto

Todos los endpoints POST aceptan multipart/form-data con un archivo SVG. Los archivos deben tener la extensión .svg y el tipo MIME image/svg+xml.

Limitación de tasa: 30 solicitudes cada 60 segundos por dirección IP.

Tiempo de espera de la solicitud: 5 minutos (300 segundos).

Formato de salida

El conversor genera imágenes WebP (no PNG), lo que proporciona archivos un 30-50% más pequeños con soporte de canal alfa.

Se producen tres variantes para cada fondo:

Variant Width Quality Propósito
full Original 60-80% Fondo del recinto a resolución completa
preview 1000px 60-80% Previsualización de carga rápida para el render inicial
blurred 400px 30-50% Marcador de posición con datos base64 incorporados para la carga progresiva

Los archivos se almacenan en backgrounds/{filename}/{variant}.webp en el backend de almacenamiento configurado.

Docker

El servicio se ejecuta en un contenedor Docker basado en node:22.14.0-alpine con Chromium instalado para Puppeteer.

Puerto: 3000

Comprobación de estado: GET /health cada 30 segundos (3 reintentos, período de inicio de 5 segundos)

Variables de entorno para Puppeteer:

  • PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true (usa el Chromium del sistema)
  • PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

Seguridad: Se ejecuta como usuario non-root (uid 10001). Usa tini como proceso init para evitar procesos zombie.

Monitorización

Métricas de Prometheus

El endpoint /metrics expone:

  • http_request_duration_seconds — histograma con etiquetas method, route, status_code
  • http_requests_total — contador con etiquetas method, route, status_code
  • Métricas por defecto del proceso de Node.js (memoria, CPU, latencia del event loop, GC)

Los buckets de métricas están optimizados para cargas de procesamiento de imágenes: 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30 segundos.

Endpoints de estado

  • GET /health — devuelve 200 si el servicio está en ejecución
  • GET /health/redis — devuelve el estado de la conexión con Redis, el nombre de la cola y la longitud de la cola

Métodos de configuración

La aplicación se puede configurar mediante varios métodos, enumerados en orden de prioridad:

  1. Variables de entorno
  2. Kubernetes ConfigMap/Secrets
  3. Archivo .env (solo para desarrollo)

Despliegue en Kubernetes

Al desplegar en Kubernetes, la configuración se gestiona mediante valores de Helm y secretos:

converter:
  image:
    repository: registry.gitlab.com/seatmap.pro/seatmap/converter-service
    tag: latest
  env:
    PORT: '3000'
    LOG_LEVEL: 'info'
    STORAGE_TYPE: 's3'
    AWS_REGION: 'us-east-1'
    AWS_BUCKET_NAME: 'your-bucket'
    # AWS_PUBLIC_BASE_URL: "https://your-cdn.example.com"  # if using non-AWS S3

Gestión de secretos

Las credenciales de AWS y las contraseñas de Redis deben gestionarse de forma segura mediante uno de estos métodos:

  • Kubernetes Secrets (inyectados a través de seatmap-helm-secrets)
  • External Secrets Operator
  • IAM roles for Service Accounts (IRSA)

Configuración para desarrollo

Para el desarrollo local usando Docker Compose:

cd products/converter-service
cp .env.sample .env
# Edit .env with your settings (use STORAGE_TYPE=local for development)
docker compose up

Esto inicia el servicio del conversor en el puerto 3000 y una instancia de Redis en el puerto 6379.

Nunca incluyas credenciales sensibles en el control de versiones.

Resolución de problemas

Problemas de configuración comunes:

  • Fallo al subir la imagen: Comprueba MAX_CONTENT_LENGTH y la configuración del tamaño del cuerpo en el ingress. El límite por defecto de 16 MB puede necesitar un aumento para archivos SVG grandes.
  • Acceso denegado a S3: Verifica las credenciales de AWS y los permisos del bucket. Comprueba que AWS_PUBLIC_BASE_URL coincide con el esquema de URL real de tu bucket.
  • Imágenes en blanco o corruptas: Verifica que Chromium esté instalado (/usr/bin/chromium-browser). En Docker, asegúrate de que la variable de entorno PUPPETEER_EXECUTABLE_PATH esté configurada correctamente.
  • Uso elevado de memoria: Sharp y Puppeteer pueden consumir mucha memoria con archivos SVG grandes. Establece límites de memoria del contenedor de al menos 512 MB, con 2 GB recomendados para producción.
  • WebP no se carga en el renderer: Asegúrate de que las cabeceras CORS estén configuradas en el bucket de S3. El renderer necesita acceso de origen cruzado para cargar las imágenes de fondo.
  • URL públicas incorrectas: Si usas un proveedor de S3 distinto de AWS, define AWS_PUBLIC_BASE_URL de forma explícita. La generación de URL por defecto asume el estilo de bucket virtual-hosted de AWS.