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:
AWS_PUBLIC_BASE_URL(si está definida) — se usa tal cual. Ejemplo:https://bucket.nyc3.digitaloceanspaces.comAWS_ENDPOINT_URL(derivada) — path-style:{endpoint}/{bucket}. Ejemplo:https://storage.yandexcloud.net/my-bucket- 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
AllowedOriginsa 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_codehttp_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ónGET /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:
- Variables de entorno
- Kubernetes ConfigMap/Secrets
- 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_LENGTHy 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_URLcoincide 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 entornoPUPPETEER_EXECUTABLE_PATHesté 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_URLde forma explícita. La generación de URL por defecto asume el estilo de bucket virtual-hosted de AWS.