Создание превью картинок в объектном хранилище с помощью Yandex Cloud Functions

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

Довольно распространенная задача – создание превью картинок для сайта из полноразмерных изображений. Автоматизируем этот процесс с помощью триггера для Yandex Object Storage с функцией в Yandex Cloud Functions, которую он будет запускать с наступлением определенного события в бакете – в нашем случае, появлением в нем картинки. Функция сделает из нее превью и сохранит в соседний бакет. Возможна вариация сохранения превью в тот же бакет, но с другим префиксом.

Также с помощью триггера в Yandex.Cloud можно задавать действия не только для объектов в хранилище, но и для событий в очереди.

Триггер для Object Storage и Cloud Functions

Для решения этой задачи необходим настроенный бакет в Object Storage, в него будут загружаться файлы и в нем же будет лежать архив с кодом функции. Репозиторий с примером кода можно скачать тут. После выполнения инструкций из репозитория у вас будет готовая функция, к которой необходимо подключить триггер, срабатывающий на загрузку новых файлов.

В настройках триггера задаем его параметры: название, описание и тип – в нашем случае Object Storage. Также указываем бакет, в который будут загружаться картинки. Если дополнительно указать префикс и суффикс объекта, то можно обойтись одним бакетом и для исходных файлов, и для превью.

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

Превью на лету

Но у такого решения есть пара ограничений.

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

  2. Необходимо заранее определять высоту и ширину превью, чтобы внести изменения в соотношение сторон или размер необходимо заново масштабировать все картинки.

Воспользуемся новой возможностью Yandex.Cloud - runtime для функций — C#, чтобы доработать нашу функцию на csharp.

Теперь схема будет работать так.

При первичном обращении за превью:

  1. Пользователь запрашивает картинку, указав в URL ее желаемые размеры.

  2. Объектное хранилище не находит нужного файла и согласно настроенным правилам, переадресует запрос в функцию.

  3. Функция идет за оригинальным изображением в объектное хранилище.

  4. Масштабирует его до нужных размеров и сохраняет по ключу, содержащему эти размеры.

  5. Сразу отдает готовый файл пользователю. 

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

Особенности технической реализации

Прописываем правила переадресации для бакета, чтобы Object Storage и Cloud Functions смогли работать в связке.

s3.putBucketWebsite({
    Bucket: "%bucket_name%",
    WebsiteConfiguration: {
        IndexDocument: {
            Suffix: "index.html"
        },
        RoutingRules: [
            {
                Condition: {
                    HttpErrorCodeReturnedEquals: "404",
                    KeyPrefixEquals: "images/"
                },
                Redirect: {
                    HttpRedirectCode: "302",
                    HostName: "functions.yandexcloud.net",
                    Protocol: "https",
                    ReplaceKeyPrefixWith: "%function_id%?path=",
                }
            }
        ]
    }
})

Если объектное хранилище не найдет (HttpErrorCodeReturnedEquals: "404") запрошенный файл с указанным KeyPrefixEquals, то применит указанный ниже редирект. Подробнее можно посмотреть в документации к AWS S3, а скачать готовый код функции можно в репозитории тут. 

В Yandex.Cloud удобно реализовано создание функций с помощью CLI. Вам не надо архивировать код и загружать его в объектное хранилище, достаточно лишь сложить все файлы в директорию и указать на нее при создании версии функции в ключе --source-path. Так же вы можете не передавать все node_modules, а загрузить только package.json и выбрать --runtime nodejs12 или --runtime nodejs14. Все зависимости будут подтянуты в момент создания версии функции.

Обращаться к фалам надо не по обычному хосту %bucket_name%.storage.yandexcloud.net, так как редиректы обрабатываться не будут, а через %bucket_name%.website.yandexcloud.net/PREFIX/%width%x%height%/%path%.

Например, при обращении  к %bucket_name%.website.yandexcloud.net/images/500x500/cats/meow.png вы получите картинку которую положили в бакет %bucket_name% по ключу images/cats/meow.png но отмасштабированную до размеров 500x500px.

Чтобы не выстрелить себе в ногу

Если не задать значение переменной окружения ALLOWED_DIMENSIONS, то в функции не будут накладываться ограничения на размеры. Это значит, что если будут запрошены много разных вариантов размеров, то все они будут созданы и загружены в объектное хранилище. Поэтому если вы точно знаете, что вам понадобятся определенные размеры картинок лучше их указать. В противном случае, вы быстро израсходуете все свободное пространство хранилища.

Так же, если у вас очень много изображений, можно задать некоторое значение TTL, создать LRU схему кэширования.

P.S.

Любые вопросы по Serverless и Yandex Cloud Functions обсуждаем у нас в Telegram: Yandex Serverless Ecosystem

Полезные ссылки:

  • Создание триггера для Object Storage

  • Документация по Cloud Functions

  • Документация по Yandex Object Storage

Источник: https://habr.com/ru/post/547394/


Интересные статьи

Интересные статьи

В этой статье мы рассмотрим, как система управления 1С-Битрикс справляется с большими нагрузками. Данный вопрос особенно актуален сегодня, когда электронная торговля начинает конкурировать по обороту ...
Привет, меня зовут Костя Крамлих, я ведущий разработчик подразделения Virtual Private Cloud в Яндекс.Облаке. Я занимаюсь виртуальной сетью, и, как можно догадаться, в этой статье расскажу об устр...
Почему GCP? При написание телеграмм ботов столкнулся с вопросом, как быстро и бесплатно сделать так, чтобы бот работал постоянно. Варианты с Heroku и Pythonanywhere имеют слишком маленькие лимит...
Я хотел, чтобы в моей игре The Last Boundary была туманность. Они потрясающе выглядят и космос без них не космос, а просто разбросанные по фону белые пиксели. Но так как игру я делаю в стиле «пик...
Здравствуйте. Я уже давно не пишу на php, но то и дело натыкаюсь на интернет-магазины на системе управления сайтами Битрикс. И я вспоминаю о своих исследованиях. Битрикс не любят примерно так,...