Перейти к содержимому
Архитектура14 мин чтения

Imager: обработка изображений на лету — установка, настройка и интеграция с сайтом

Пошаговая инструкция по установке Imager — сервиса обработки изображений на лету. Разбираем Docker, ресайз, кадрирование, WebP и AVIF, CDN, кэширование, responsive images, клиентские библиотеки и production-настройку.

#архитектура #архитектура веб-приложений #backend #highload #кэширование #масштабирование #проектирование #микросервисы #разработка

Изображения — одна из самых заметных частей веб-приложения с точки зрения производительности. Интернет-магазины, каталоги, новостные сайты, маркетплейсы, социальные сети и корпоративные порталы могут хранить фотографии в нескольких мегабайтах, тогда как браузеру для конкретного места на странице часто нужна картинка размером всего несколько десятков или сотен килобайт.

Традиционный подход — заранее создавать набор миниатюр для каждого изображения: 200x200, 400x400, 800x600, WebP, JPEG, Retina и так далее. При большом количестве изображений количество файлов быстро становится огромным, а требования фронтенда постоянно меняются.

Imager решает эту задачу иначе: изображение хранится в исходном виде, а нужный ассет создаётся автоматически при обращении по URL, сохраняется в кэш и затем отдаётся повторно. Сам URL содержит информацию об исходнике, размере, DPR и формате результата, поэтому результат предсказуем, кешируем и удобен для CDN.

Онлайн-демо позволяет сразу увидеть принцип работы сервиса и клиентской части:

Демо Imager: https://altuh.ru/demo/imager

Что такое Imager

Imager — отдельный микросервис обработки изображений и ассетов. Он получает запрос на конкретный вариант изображения, находит исходник в настроенном хранилище, выполняет необходимые преобразования, сохраняет результат и отдаёт его клиенту.

Архитектурно это выглядит так:

                    ┌─────────────┐
                    │   Браузер   │
                    └──────┬──────┘
                           │
                           ▼
                    ┌─────────────┐
                    │    CDN      │
                    └──────┬──────┘
                           │ cache miss
                           ▼
                    ┌─────────────┐
                    │   Imager    │
                    └──────┬──────┘
                           │
             ┌─────────────┼─────────────┐
             ▼             ▼             ▼
          local FS        S3       HTTP/SFTP/FTP
                           │
                           ▼
                       исходник

Сервис не требует отдельного API-запроса для каждой генерации. Основной интерфейс — обычный GET по URL ассета. Тела обычных запросов не используются; сервис также поддерживает HEAD и OPTIONS.

Это позволяет поставить Imager непосредственно за Nginx, CDN или другим reverse proxy.

Зачем нужен отдельный сервис обработки изображений

Главная проблема предварительной генерации миниатюр — количество комбинаций.

Допустим, на сайте используются:

200x200
400x400
800x600
1200x800

и одновременно нужны:

JPEG
WebP
AVIF

а для Retina:

1x
2x
3x

Для одного исходника уже появляются десятки вариантов.

При добавлении нового размера или формата необходимо либо генерировать новые файлы заранее, либо писать дополнительную логику.

Imager переносит эту задачу в отдельный слой:

исходник
   ↓
Imager
   ↓
нужный вариант

Поэтому приложение хранит исходные файлы, а производные изображения создаются только тогда, когда они действительно понадобились.

Особенно хорошо такая схема работает с CDN: канонический URL конкретного варианта остаётся неизменяемым, поэтому результат можно кэшировать на длительное время. В документации Imager для таких URL используется Cache-Control: public, max-age=31536000, immutable.

Главные возможности Imager

Imager умеет не просто менять размер изображения.

Поддерживаются:

  • resize;
  • центральное кадрирование;
  • trim для удаления полей;
  • smart-crop;
  • кадрирование по лицу;
  • object-crop;
  • водяные знаки;
  • разные форматы вывода;
  • DPR 2x и 3x;
  • анимированные изображения с ограничениями по количеству кадров и длительности;
  • работа с локальной файловой системой, S3, SFTP, FTP/FTPS и HTTP-источниками;
  • Prometheus-метрики;
  • health-check и readiness-check;
  • ограничения ресурсов;
  • deny-by-default политика URL и пресетов.

Поддерживаются современные и классические форматы, включая JPEG, PNG, WebP, GIF, AVIF, HEIF/HEIC и JPEG XL. Для видео сервис также может извлекать кадры из поддерживаемых форматов.

Установка Imager через Docker

Самый простой вариант — использовать готовый Docker-образ altrap/imager.

Клонировать репозиторий и собирать сервис вручную для обычного запуска не требуется. Базовые конфигурационные файлы уже находятся в образе.

Создадим каталоги:

mkdir -p setting data/source data/result
chmod -R a+rwX data/result

Запускаем контейнер:

docker run -d \
  --name imager \
  -p 8080:8080 \
  -v ./setting:/etc/imager/setting:rw \
  -v ./data/source:/data/source:ro \
  -v ./data/result:/data/result:rw \
  -e IMAGER_CONFIG_DIR=/etc/imager/setting \
  altrap/imager:latest

После запуска проверяем health-check:

curl http://localhost:8080/healthz

Ожидаемый ответ:

{ "status": "alive" }

Теперь можно положить изображение в:

data/source/test.jpg

и запросить, например:

curl -o result.webp \
  http://localhost:8080/test-jpg/200x200.webp

Imager создаст нужный вариант изображения и вернёт его клиенту. Структура URL определяет исходник, размер и формат результата.

Docker Compose

Для постоянной эксплуатации удобнее использовать Docker Compose:

services:
    imager:
        image: altrap/imager:latest
        restart: unless-stopped
        stop_signal: INT
        stop_grace_period: 15s

        ports:
            - '8080:8080'

        environment:
            IMAGER_CONFIG_DIR: /etc/imager/setting

        volumes:
            - ./setting:/etc/imager/setting:rw
            - ./data/source:/data/source:ro
            - ./data/result:/data/result:rw

Запуск:

docker compose up -d

Для production в самом репозитории предусмотрены дополнительные настройки: лимиты CPU и памяти, health-check и другие параметры hardening.

Как устроен URL изображения

Одна из ключевых особенностей Imager — отсутствие query-параметров для описания преобразования.

URL строится по понятной схеме:

/{path}/{source_name}-{source_format}/{segment}@{dpr}.{output_format}

Например:

/photos/city-skyline-jpg/300x@2.webp

означает:

источник: city-skyline.jpg
ширина:   300 px
DPR:      2
формат:   WebP

При DPR 2 фактическое изображение будет сформировано с плотностью, необходимой для соответствующего варианта.

Можно использовать именованный пресет:

/test-jpg/thumb.webp

или произвольный размер:

/test-jpg/640x.webp
/test-jpg/x400.webp
/test-jpg/640x480.webp

Специальный сегмент x означает исходный размер с возможностью преобразовать формат.

Таким образом, само имя URL становится декларацией того, что именно требуется от сервиса.

Пресеты вместо бесконтрольных размеров

В реальном проекте не всегда нужно разрешать пользователю запрашивать абсолютно любой размер.

Например, для каталога можно разрешить:

thumb
product
catalog

и соответствующие размеры.

Это настраивается через policy.

У Imager используется deny-by-default модель: разрешены только явно описанные пресеты и custom-размеры, соответствующие правилам конкретного пути. Дополнительно задаются ограничения на размер исходника, размер результата, количество пикселей, кадров и длительность анимации.

Это одновременно даёт контроль над API и защищает сервис от запросов, которые создают чрезмерную нагрузку.

WebP, AVIF, JPEG и другие форматы

Один исходник не обязательно должен храниться в нескольких форматах.

Допустим, оригинал:

product.jpg

Можно отдавать как:

product-jpg/800x600.webp

или:

product-jpg/800x600.avif

Оригинал при этом остаётся JPEG.

Imager поддерживает JPEG, PNG, WebP, GIF, AVIF, HEIF/HEIC и JPEG XL.

Это позволяет централизовать работу с форматами и не заставлять приложение создавать отдельные физические копии каждого изображения.

Responsive images и Retina

Современный сайт редко должен отдавать одну и ту же картинку всем устройствам.

На смартфоне изображение шириной 1200 пикселей часто избыточно. На Retina-дисплее, наоборот, может понадобиться вариант с повышенной плотностью.

Imager Client умеет автоматически строить наборы ассетов и готовый HTML <picture> / <img>.

Например:

html := img.GetAssetsHtml(
    "/images/uploads/example.png",
    "200x200",
    nil,
    nil,
    imager.Options{
        Class: "photo",
        ID:    "main",
        Alt:   "Фото",
        Lazy:  true,
    },
)

Клиентская библиотека умеет формировать srcset в двух режимах: через w-дескрипторы для разных ширин или через x-дескрипторы для разных DPR.

В результате можно построить стандартную responsive-разметку:

<picture>
    <source ... />
    <source ... />

    <img src="..." srcset="..." alt="Фото" />
</picture>

И при этом не требуется вручную вычислять десятки URL.

Клиентские библиотеки Imager

Сам сервис занимается обработкой изображений, а клиентские библиотеки решают другую задачу — формируют правильные URL и HTML.

На данный момент есть реализации для:

Go
PHP
Python
TypeScript

А также интеграции:

Vue
React
Twig

Клиентская часть построена таким образом, чтобы разные языки формировали одинаковый результат. Для этого используется единый набор golden-тестов.

Это особенно полезно в проектах, где backend написан на одном языке, а frontend — на другом.

Например:

PHP backend
     +
TypeScript frontend

или:

Go API
     +
React

Обе части могут использовать одну модель построения URL.

Установка клиента для Go

Для Go:

go get gitverse.ru/pkg-ru/imager-client/v2

Пример:

import imager "gitverse.ru/pkg-ru/imager-client/v2"

client := imager.New(imager.Options{
    BaseURL: "https://images.example.com/",
    Format:  "webp",
})

Получить URL:

url := client.GetAssetPath(
    "/images/photo.jpg",
    "800x600",
    "webp",
)

Результат будет примерно таким:

https://images.example.com/images/photo-jpg/800x600.webp

Можно также использовать объект размера:

asset := client.GetAsset(
    "/images/photo.jpg",
    imager.Size{
        Width: 800,
        Height: 600,
    },
    "webp",
    2,
)

API клиента описывает отдельные методы для одного ассета, набора ассетов, HTML и формирования URL.

Установка клиента для PHP

Установка через Composer:

composer require pkg-ru/imager-client

Использование:

use imagerClient\Imager;

$imager = new Imager([
    "baseURL" => "https://images.example.com/",
    "format" => "webp",
]);

$url = $imager->GetAssetPath(
    "/images/photo.jpg",
    "800x600",
    "webp"
);

PHP-клиент имеет ту же модель API, что Go, Python и TypeScript.

Установка клиента для Python

pip install imager_client

Пример:

from imager import Imager

imager = Imager({
    "baseURL": "https://images.example.com/",
    "format": "webp",
})

url = imager.GetAssetPath(
    "/images/photo.jpg",
    "800x600",
    "webp",
)

Для Python доступен тот же набор основных операций построения ассетов.

Установка клиента для TypeScript

npm install imager-client

В браузерном коде достаточно:

import { Imager } from 'imager-client'

const imager = new Imager({
    baseURL: 'https://images.example.com/',
    format: 'webp',
})

const url = imager.GetAssetPath('/images/photo.jpg', '800x600', 'webp')

Здесь есть важная архитектурная особенность: обычный клиент не содержит административного токена и не выполняет административные HTTP-запросы. Серверные административные методы вынесены в отдельный импорт:

import { ImagerServer } from 'imager-client/server'

Это позволяет не тащить секрет в браузерный bundle.

Vue, React и Twig

Поверх ядра клиентской библиотеки существуют тонкие интеграции с популярными frontend и template-фреймворками.

Для Vue:

npm install @pkg-ru/imager-vue

Для React:

npm install @pkg-ru/imager-react

Для Twig:

composer require pkg-ru/imager-twig

Компоненты не реализуют собственную систему преобразований. Они используют общее ядро и добавляют адаптацию props и рендеринг нативного элемента фреймворка.

Например, React:

<ImagerAssets src="/test.png" width={200} height={200} dpr={2} format="webp" alt="Фото" />

Vue:

createApp(App)
    .use(ImagerPlugin, {
        baseURL: '...',
        format: 'webp',
        dpr: 2,
    })
    .mount('#app')

Twig:

{{ imager_assets('/test.png', {
    preset: 'thumb',
    format: 'webp',
    alt: 'Фото'
})|raw }}

SSR и hydration

Клиентская библиотека не привязана только к браузеру.

Ядро формирования URL и HTML не зависит от DOM или window, поэтому тот же код может использоваться при SSR и prerender. Сервер может сформировать готовый <picture> ещё до отправки HTML клиенту, а затем фронтенд использует тот же результат при hydration.

Это удобно, например, для:

Next.js
Nuxt
SvelteKit

где изображения должны быть корректно сформированы уже во время серверного рендеринга.

Почему клиент практически не создаёт нагрузки

Очень важный момент: клиентская библиотека не отправляет HTTP-запросы при каждом GetAssetPath.

Её задача — вычислить строку URL.

То есть:

url := client.GetAssetPath(...)

не означает:

HTTP → Imager

Это просто генерация URL.

В README клиента отдельно подчёркивается, что методы генерации ассетов работают без HTTP, валидации и исключений и реализованы как операции построения строк. Поэтому их можно вызывать массово, в том числе при генерации больших списков изображений.

Это полезно для страниц с сотнями и тысячами товаров или фотографий.

Например:

for _, product := range products {
    product.ImageURL = client.GetAssetPath(
        product.Image,
        "300x300",
        "webp",
    )
}

Никаких сетевых запросов к Imager при формировании ответа API не возникает.

Сам браузер обратится к Imager уже тогда, когда получит HTML с соответствующим URL.

Кэширование и CDN

Именно здесь архитектура Imager особенно хорошо раскрывается.

Вместо:

Приложение
   ↓
генерация файла
   ↓
сохранение
   ↓
раздача

получается:

Браузер
   ↓
CDN
   ↓ cache miss
Imager
   ↓
storage

После первой генерации результат может обслуживаться непосредственно CDN или внешним reverse proxy.

Поскольку URL однозначно определяет вариант ассета, можно использовать длительное кеширование и immutable.

При этом изменение исходника должно сопровождаться изменением URL или другой выбранной стратегией инвалидирования. Это позволяет избежать ситуации, когда CDN бесконечно хранит старую версию под тем же URL.

Поддержка S3 и других хранилищ

Imager не ограничивает проект локальной файловой системой.

Источники и результаты могут находиться отдельно и использовать разные backend'ы:

fs
s3
sftp
ftp
ftps
http

Причём хранилище результата может отличаться от хранилища исходника. HTTP-источники работают в режиме read-only.

Например:

Original:
S3 bucket

Generated:
S3 bucket / CDN storage

или:

Original:
локальный filesystem

Generated:
S3

Это позволяет использовать Imager и в небольшом проекте на одном сервере, и в распределённой инфраструктуре.

Водяные знаки

Водяной знак можно сделать частью политики обработки.

Например:

исходник
   ↓
resize
   ↓
crop
   ↓
watermark
   ↓
WebP

Результат также кэшируется, поэтому повторный запрос уже не требует повторного выполнения всех операций.

Это удобно для:

  • каталогов;
  • маркетплейсов;
  • фотобанков;
  • публикации фотографий;
  • защищённых превью;
  • демонстрации изображений с брендингом.

Smart crop, face crop и object crop

Простое центральное кадрирование не всегда хорошо работает.

Для фотографии человека:

┌──────────────────────┐
│                      │
│       лицо           │
│                      │
│                      │
└──────────────────────┘

центральный crop может обрезать человека не там, где нужно.

Поэтому Imager поддерживает smart-crop, а также кадрирование с учётом лиц и объектов. Для соответствующих режимов используется ONNX Runtime и модели детекции.

Это особенно полезно для карточек товаров, аватаров, каталогов и изображений с различным расположением объектов.

Анимация

Imager поддерживает работу с анимированными изображениями, в частности GIF и WebP, с ограничениями количества кадров и длительности. APNG также может обрабатываться как анимированный PNG, а возможности записи APNG зависят от используемой сборки libvips.

Для production это важно не только из-за функциональности, но и с точки зрения защиты ресурсов: анимация может быть значительно тяжелее обычного статического изображения, поэтому ограничения задаются централизованно.

Безопасность

Сервис обработки изображений нельзя оставлять полностью «всеядным».

Если разрешить пользователю произвольные пути, размеры и преобразования, можно получить нежелательные обращения к файловой системе, чрезмерное потребление памяти или генерацию огромного количества комбинаций.

Поэтому Imager использует несколько уровней защиты.

Во-первых, применяется deny-by-default политика для URL и пресетов.

Во-вторых, существуют ограничения:

размер исходного файла
размер результата
количество пикселей
количество кадров
длительность анимации

Также есть ограничения размера HTTP-запроса, защищённые операции с файлами и защита от symlink-атак.

Для Docker предусмотрены возможности hardening и ресурсные ограничения, что позволяет не превращать обработчик изображений в неконтролируемый потребитель ресурсов.

Наблюдаемость

Imager предоставляет готовые точки для мониторинга:

/healthz
/readyz
/metrics

/healthz используется для проверки жизнеспособности процесса, /readyz — готовности сервиса, а /metrics отдаёт данные в формате Prometheus.

Это позволяет без написания дополнительной инфраструктуры встроить Imager в стандартную систему мониторинга:

Prometheus
    ↓
Grafana
    ↓
Imager metrics

Для production это особенно полезно при масштабировании нескольких экземпляров сервиса.

Сборка из исходников

Docker — не единственный вариант.

Imager написан на Go и может собираться из исходного кода.

Обычная сборка:

go build -o imager ./cmd/imager

Production-сборка с libvips:

go build \
  -tags libvips \
  -trimpath \
  -ldflags="-s -w" \
  -o imager \
  ./cmd/imager

Для face/object detection:

go build \
  -tags "libvips,onnx" \
  -trimpath \
  -ldflags="-s -w" \
  -o imager \
  ./cmd/imager

Для libvips используются соответствующие системные зависимости и C-компилятор; дополнительные кодеки устанавливаются в зависимости от нужных форматов.

Сам проект использует архитектуру ports-and-adapters: доменная логика отделена от адаптеров хранения, обработки и инфраструктуры. Build tags позволяют выбирать конкретные реализации.

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

Конфигурация сервиса полностью вынесена в YAML.

Основные слои:

server.yaml
generate.yaml
failback.yaml

и локальные переопределения:

server-local.yaml
generate-local.yaml
failback-local.yaml

*-local.yaml предназначены в том числе для секретов и не должны попадать в репозиторий. Локальные конфигурации накладываются поверх базовых.

Такой подход удобен для разделения:

Git
 ├── server.yaml
 ├── generate.yaml
 └── failback.yaml

local
 ├── server-local.yaml
 ├── generate-local.yaml
 └── failback-local.yaml

При обновлении Docker-образа базовые конфигурации могут синхронизироваться с новой версией образа, а *-local.yaml сохраняются.

Production-схема

Для реального сайта я бы рассматривал Imager как самостоятельный сервис за reverse proxy.

Например:

                       ┌─────────────┐
                       │   Browser   │
                       └──────┬──────┘
                              │
                              ▼
                       ┌─────────────┐
                       │     CDN     │
                       └──────┬──────┘
                              │
                              ▼
                       ┌─────────────┐
                       │    Nginx   │
                       └──────┬──────┘
                              │
                   ┌──────────┴──────────┐
                   ▼                     ▼
             ┌───────────┐         ┌───────────┐
             │  Imager 1 │         │  Imager 2 │
             └─────┬─────┘         └─────┬─────┘
                   │                     │
                   └──────────┬──────────┘
                              ▼
                         ┌────────┐
                         │  S3    │
                         └────────┘

В этой схеме CDN снимает основной объём повторных запросов, Nginx выполняет роль reverse proxy, а несколько экземпляров Imager позволяют масштабировать обработку.

TLS при этом можно завершать на reverse proxy; само приложение работает по HTTP на порту 8080.

Imager хорошо подходит для highload

Изображения могут создавать огромную нагрузку не только из-за количества запросов, но и из-за стоимости самой обработки.

Поэтому здесь важны сразу несколько уровней оптимизации:

                CDN
                 ↓
              cache hit
                 ↓
             готовый URL
                 ↓
               Nginx
                 ↓
             Imager
                 ↓
            внутренний cache
                 ↓
             storage

Плюс клиентская библиотека не делает HTTP-запросы при формировании URL.

В результате разделяются две разные задачи:

Backend
  → быстро формирует URL

Imager
  → только при необходимости обрабатывает изображение

CDN
  → отдаёт уже готовый результат

Для страниц с большим количеством изображений это значительно удобнее, чем создавать десятки файлов во время загрузки контента.

Почему client лучше ручной генерации URL

Теоретически URL можно формировать самостоятельно:

url := baseURL + source + "-jpg/300x300.webp"

Но как только появляются:

presets
DPR
несколько форматов
srcset
picture
разные размеры
fallback
SSR

ручная конкатенация быстро становится ошибкоопасной.

Клиентская библиотека берёт эту логику на себя.

Причём API одинаковый во всех поддерживаемых языках, а набор golden-тестов гарантирует одинаковую структуру результата.

Это означает, что backend может сформировать URL в Go или PHP, а frontend — тот же вариант в TypeScript, не создавая две независимые реализации правил.

Что в итоге получает разработчик

Если собрать всё вместе, Imager закрывает сразу несколько задач:

                 ┌──────────────────────┐
                 │       Imager         │
                 ├──────────────────────┤
                 │ resize               │
                 │ crop                 │
                 │ trim                 │
                 │ smart crop           │
                 │ face crop            │
                 │ object crop          │
                 │ watermark             │
                 │ formats               │
                 │ animation             │
                 │ DPR                   │
                 │ caching               │
                 │ storage               │
                 │ security              │
                 │ metrics               │
                 └──────────────────────┘

А клиентские библиотеки закрывают вторую половину задачи:

                 ┌──────────────────────┐
                 │    Imager Client    │
                 ├──────────────────────┤
                 │ URL                  │
                 │ presets              │
                 │ размеры             │
                 │ DPR                  │
                 │ formats              │
                 │ srcset               │
                 │ picture              │
                 │ HTML                 │
                 │ Go                   │
                 │ PHP                  │
                 │ Python               │
                 │ TypeScript           │
                 │ Vue                  │
                 │ React                │
                 │ Twig                 │
                 └──────────────────────┘

Это позволяет не смешивать обработку изображений с бизнес-логикой самого приложения.

Когда стоит использовать Imager

Imager особенно хорошо подходит для проектов, где:

  • много пользовательских изображений;
  • размеры изображений зависят от места использования;
  • нужен WebP или AVIF без хранения отдельных оригиналов;
  • требуется responsive images и srcset;
  • используются Retina-дисплеи;
  • изображения хранятся в S3;
  • нужен CDN-friendly URL;
  • необходимо автоматически создавать превью;
  • есть несколько backend/frontend языков;
  • требуется централизованный контроль обработки;
  • приложение должно масштабироваться горизонтально.

Особенно заметный эффект появляется в каталогах, интернет-магазинах, медиа-сервисах, маркетплейсах, CMS и больших веб-платформах.

Быстрый путь от нуля до production

Практический сценарий можно свести к нескольким шагам.

Сначала запускаем Imager:

docker compose up -d

Проверяем:

curl http://localhost:8080/healthz

Кладём исходное изображение в storage.

После этого проверяем URL:

/images/photo-jpg/300x300.webp

Затем подключаем клиентскую библиотеку:

go get gitverse.ru/pkg-ru/imager-client/v2

или для PHP:

composer require pkg-ru/imager-client

или для TypeScript:

npm install imager-client

После чего приложение начинает генерировать URL через клиент, а не вручную.

Следующим шагом можно вынести Imager за Nginx, подключить CDN, определить пресеты, настроить ограничения и включить Prometheus.

В итоге приложение перестаёт заниматься физическим созданием и хранением десятков разновидностей каждого изображения.

Заключение

Imager — это не просто конвертер JPEG в WebP или сервис для создания thumbnails. Его основная идея — вынести работу с производными изображениями в отдельный слой инфраструктуры и перейти от предварительной генерации файлов к генерации по запросу по каноническому URL.

Приложение хранит оригинал:

photo.jpg

а клиент получает именно тот вариант, который нужен:

photo-jpg/300x300.webp
photo-jpg/600x400.webp
photo-jpg/600x400@2.webp
photo-jpg/1200x800.avif

Все эти варианты описываются URL, могут кэшироваться и отдаваться через CDN.

При этом разработчику не приходится самостоятельно писать генератор URL, собирать srcset, поддерживать несколько языков реализации клиента или создавать отдельную систему для ресайза.

Демо: https://altuh.ru/demo/imager

Imager: https://github.com/pkg-ru/imager

Imager Client: https://github.com/pkg-ru/imager-client

Для production-развёртывания доступны отдельные руководства по конфигурации, установке, storage, безопасности, обработке изображений и настройке Nginx.

Релевантные разделы

Архитектура

Архитектура веб-платформ: как проектировать систему, которая растёт

Как проектировать архитектуру веб-платформ, которая выдерживает рост функциональности, команды и нагрузки: модульность, границы ответственности, данные, интеграции, наблюдаемость и выбор между монолитом и микросервисами.

#архитектура #архитектура веб-приложений #проектирование
9 мин
Архитектура

Высоконагруженные веб-системы: как проектировать архитектуру под рост нагрузки

Как проектировать высоконагруженные веб-системы: поиск узких мест, масштабирование backend и базы данных, кэширование, очереди, отказоустойчивость, нагрузочное тестирование и наблюдаемость.

#highload #высокая нагрузка #масштабирование
12 мин
Разработка

Чистый код и поддерживаемость: почему читаемость важнее скорости

Как писать поддерживаемый код: понятные имена, небольшие функции, явные зависимости, простые интерфейсы, тесты и рефакторинг без усложнения проекта.

#чистый код #поддерживаемость #рефакторинг
10 мин