Руководство по настройке 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 разрешается в следующем порядке приоритета:
AWS_PUBLIC_BASE_URL(если задан) — используется как есть. Пример:https://bucket.nyc3.digitaloceanspaces.comAWS_ENDPOINT_URL(производный) — path-style:{endpoint}/{bucket}. Пример:https://storage.yandexcloud.net/my-bucket- По умолчанию — 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_codehttp_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, имя очереди и длину очереди
Способы конфигурации
Приложение можно настраивать несколькими способами, перечисленными в порядке приоритета:
- Переменные окружения
- Kubernetes ConfigMap/Secrets
- Файл
.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.