Руководство по настройке Image Converter

Image converter — это микросервис на Node.js, который рендерит SVG-фоны площадок в оптимизированные изображения WebP. Он создаёт три варианта для каждого фона — в полном разрешении, превью на 1000px и размытый плейсхолдер на 400px со встроенными данными base64 для прогрессивной загрузки. Изображения хранятся в S3-совместимом объектном хранилище или в локальной файловой системе.

Стек: Node.js 22, Express 5, Puppeteer (headless Chromium для рендеринга SVG), Sharp (обработка изображений), опционально Redis (асинхронная очередь результатов).

Основные настройки

Setting Type Default Описание
PORT integer 3000 Порт, на котором слушает сервер Express
NODE_ENV string production Окружение Node
DEBUG boolean false Включает режим отладки (устанавливает LOG_LEVEL в debug)
LOG_LEVEL string info Уровень логирования Winston: error, warn, info, http, verbose, debug

Настройки работы с файлами

Setting Type Default Описание
UPLOAD_FOLDER string /tmp Временный каталог для загружаемых файлов (очищается после обработки)
MAX_CONTENT_LENGTH integer 16777216 Максимальный размер загружаемого файла в байтах (по умолчанию 16 МБ)

Настройки обработки изображений

Setting Type Default Описание
MAX_IMAGE_WIDTH integer 15000 Максимально допустимая ширина выходного изображения в пикселях
MAX_IMAGE_HEIGHT integer 15000 Максимально допустимая высота выходного изображения в пикселях
DEFAULT_WIDTH integer 440 Ширина по умолчанию для базового эндпоинта конвертации
DEFAULT_HEIGHT integer 246 Высота по умолчанию для базового эндпоинта конвертации
PNG_OPTIMIZATION boolean false Включает сжатие изображений
PNG_OPTIMIZATION_QUALITY string 0.6-0.8 Диапазон качества для вывода в WebP

Настройки хранилища

Setting Type Default Описание
STORAGE_TYPE string s3 Бэкенд хранилища: s3 или local
LOCAL_STORAGE_PATH string ./storage Путь в файловой системе при использовании локального хранилища

Конфигурация AWS S3

Эти настройки обязательны при STORAGE_TYPE=s3.

Setting Type Default Описание
AWS_ACCESS_KEY_ID string (required) Ключ доступа IAM для аутентификации в S3
AWS_SECRET_ACCESS_KEY string (required) Секретный ключ IAM для аутентификации в S3
AWS_REGION string us-east-1 Регион AWS для бакета S3
AWS_BUCKET_NAME string (required) Имя бакета S3 для хранения изображений
AWS_ENDPOINT_URL string Пользовательский эндпоинт S3 для S3-совместимых провайдеров (MinIO, DigitalOcean Spaces, Garage)
AWS_PUBLIC_BASE_URL string Переопределяет базовый публичный URL для генерируемых URL изображений (см. ниже)

ImportantУчётные данные AWS следует передавать через защищённые переменные окружения или секреты Kubernetes. Никогда не коммитьте учётные данные в систему контроля версий.

Разрешение публичного URL

Конвертер генерирует публичные URL для загруженных изображений. Базовый URL разрешается в следующем порядке приоритета:

  1. AWS_PUBLIC_BASE_URL (если задан) — используется как есть. Пример: https://bucket.nyc3.digitaloceanspaces.com
  2. AWS_ENDPOINT_URL (производный) — path-style: {endpoint}/{bucket}. Пример: https://storage.yandexcloud.net/my-bucket
  3. По умолчанию — virtual-hosted style AWS: https://{bucket}.s3.{region}.amazonaws.com

Клиентам с self-hosted-развёртыванием, использующим не-AWS S3-провайдеров (DigitalOcean Spaces, MinIO, Garage, Yandex Cloud), следует задать AWS_PUBLIC_BASE_URL, чтобы обеспечить корректные публичные URL.

Политика бакета S3

Чтобы разрешить публичный доступ на чтение к изображениям, примените следующую политику бакета:

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

Конфигурация CORS

Чтобы предотвратить проблемы с tainted canvas при обработке изображений в веб-браузерах, настройте CORS на бакете:

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

NoteДля production-окружений ограничьте AllowedOrigins вашими конкретными доменами вместо *.

Настройки Redis

Redis опционален. Когда он включён, результаты конвертации помещаются в очередь Redis для асинхронной обработки другими сервисами.

Setting Type Default Описание
REDIS_ENABLED boolean false Включает очередь результатов Redis
REDIS_HOST string localhost Имя хоста сервера Redis
REDIS_PORT integer 6379 Порт сервера Redis
REDIS_PASSWORD string Пароль Redis (если требуется аутентификация)
REDIS_QUEUE_NAME string conversion_results Имя очереди для хранения результатов конвертации

Если Redis отключён или недоступен, конвертация всё равно проходит успешно — публикация в очередь не блокирует выполнение.

Эндпоинты API

Method Path Описание
POST / Базовая конвертация SVG в изображение. Возвращает файл изображения напрямую. Query-параметры: width, height
POST /background/ Полная конвертация фона. Возвращает JSON с тремя URL вариантов (full, preview, blurred). Query-параметры: filename, debug
POST /thumbnail/ Конвертация миниатюры. Возвращает JSON с тремя URL вариантов. Query-параметры: filename, debug
GET /health Проверка работоспособности сервиса. Возвращает { "status": "healthy" }
GET /health/redis Статус подключения к Redis и длина очереди
GET /metrics Метрики Prometheus в текстовом формате

Все POST-эндпоинты принимают multipart/form-data с SVG-файлом. Файлы должны иметь расширение .svg и MIME-тип image/svg+xml.

Ограничение частоты: 30 запросов за 60 секунд на один IP-адрес.

Таймаут запроса: 5 минут (300 секунд).

Формат вывода

Конвертер генерирует изображения WebP (не PNG), обеспечивая на 30–50% меньший размер файлов с поддержкой альфа-канала.

Для каждого фона создаётся три варианта:

Variant Width Quality Назначение
full Original 60-80% Фон площадки в полном разрешении
preview 1000px 60-80% Быстро загружаемое превью для первоначального рендера
blurred 400px 30-50% Плейсхолдер со встроенными данными base64 для прогрессивной загрузки

Файлы хранятся по пути backgrounds/{filename}/{variant}.webp в настроенном бэкенде хранилища.

Docker

Сервис работает в Docker-контейнере на базе node:22.14.0-alpine с установленным Chromium для Puppeteer.

Порт: 3000

Проверка работоспособности: GET /health каждые 30 секунд (3 повтора, период старта 5 секунд)

Переменные окружения для Puppeteer:

  • PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true (использует системный Chromium)
  • PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

Безопасность: Работает от имени non-root-пользователя (uid 10001). Использует tini в качестве init-процесса для предотвращения зомби-процессов.

Мониторинг

Метрики Prometheus

Эндпоинт /metrics предоставляет:

  • http_request_duration_seconds — гистограмма с метками method, route, status_code
  • http_requests_total — счётчик с метками method, route, status_code
  • Стандартные метрики процесса Node.js (память, CPU, задержка event loop, GC)

Бакеты метрик оптимизированы для нагрузок обработки изображений: 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30 секунд.

Эндпоинты работоспособности

  • GET /health — возвращает 200, если сервис работает
  • GET /health/redis — возвращает статус подключения к Redis, имя очереди и длину очереди

Способы конфигурации

Приложение можно настраивать несколькими способами, перечисленными в порядке приоритета:

  1. Переменные окружения
  2. Kubernetes ConfigMap/Secrets
  3. Файл .env (только для разработки)

Развёртывание в Kubernetes

При развёртывании в Kubernetes конфигурация управляется через значения Helm и секреты:

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

Управление секретами

Учётные данные AWS и пароли Redis следует хранить безопасно, используя один из этих методов:

  • Kubernetes Secrets (внедряются через seatmap-helm-secrets)
  • External Secrets Operator
  • IAM roles for Service Accounts (IRSA)

Настройка для разработки

Для локальной разработки с использованием Docker Compose:

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

Это запускает сервис конвертера на порту 3000 и экземпляр Redis на порту 6379.

Никогда не коммитьте чувствительные учётные данные в систему контроля версий.

Устранение неполадок

Распространённые проблемы конфигурации:

  • Загрузка изображения не удаётся: Проверьте MAX_CONTENT_LENGTH и настройку ограничения размера тела запроса в ingress. Лимит по умолчанию 16 МБ может потребоваться увеличить для больших SVG-файлов.
  • Отказ в доступе к S3: Проверьте учётные данные AWS и права доступа к бакету. Убедитесь, что AWS_PUBLIC_BASE_URL соответствует реальной схеме URL вашего бакета.
  • Пустые или повреждённые изображения: Убедитесь, что Chromium установлен (/usr/bin/chromium-browser). В Docker убедитесь, что переменная окружения PUPPETEER_EXECUTABLE_PATH задана корректно.
  • Высокое потребление памяти: Sharp и Puppeteer могут потреблять значительный объём памяти при работе с большими SVG-файлами. Установите лимиты памяти контейнера не менее 512 МБ, рекомендуется 2 ГБ для production.
  • WebP не загружается в renderer: Убедитесь, что заголовки CORS настроены на бакете S3. Renderer’у нужен кросс-доменный доступ для загрузки фоновых изображений.
  • Неверные публичные URL: Если вы используете не-AWS S3-провайдера, задайте AWS_PUBLIC_BASE_URL явно. Генерация URL по умолчанию предполагает virtual-hosted-стиль бакета AWS.