Как использовать ImageMagick в AWS Lambda (ruby 2.7) с поддержкой WebP


Оглавление

  1. Введение
  2. Настройка проекта
  3. Сборка и тестирование Docker-образа
  4. Автоматическое сохранение образа в AWS ECR с помощью GitHub Actions
  5. Создание функции AWS Lambda
  6. Заключение

0. Введение

Контекст: Я хотел создать функцию AWS Lambda, которая будет вызываться из приложения, чтобы я отправлял изображение, а функция изменяла его размер, сжимала (ограничение на размер файла) и отправляла обратно в формате WebP.

Прежде чем перейти к самому руководству, я хочу сказать, что до работы над этой архитектурой я пытался использовать способ «слоя»: Создание слоя AWS Lambda с зависимостью ImageMagick. Но после того, как я потратил много часов, не добившись успеха из-за множества проблем, решил перейти на этот «докеровский» способ.

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

1. Установите проект

Документация: Создание образа Ruby из базового образа AWS

https://docs.aws.amazon.com/lambda/latest/dg/ruby-image.html#ruby-image-create

Ниже будет приведена нужная нам структура папок.

my-project
-- app.rb
-- Gemfile
-- Dockerfile
Вход в полноэкранный режим Выход из полноэкранного режима

1.1 Содержание Gemfile

Для связи от ruby к ImageMagick мы будем использовать RMagick, поэтому нам нужно добавить его в наш gems.

source 'https://rubygems.org'
gem 'rmagick'
Вход в полноэкранный режим Выйти из полноэкранного режима

1.2 Содержание app.rb

Файл app.rb будет нашей основной программой на языке ruby. Она будет выполняться AWS Lambda, поэтому ей необходимо следовать некоторым именам.

require 'rmagick'
include Magick

module LambdaFunction
    class Handler
        def self.process(event:, context:)
            image_url = event['image_url']
            my_image = ImageList.new(image_url)
            # TODO: Use rmagick to make your image transformations
            # Docs: https://rmagick.github.io
            { "success": true }
        end
    end
end   
Войти в полноэкранный режим Выйти из полноэкранного режима

1.3 Содержание Dockerfile

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

FROM public.ecr.aws/lambda/ruby:2.7

# Our commands will go here

COPY app.rb ${LAMBDA_TASK_ROOT}

COPY Gemfile ${LAMBDA_TASK_ROOT}

ENV GEM_HOME=${LAMBDA_TASK_ROOT}
RUN bundle install

CMD [ "app.LambdaFunction::Handler.process" ]
Войти в полноэкранный режим Выйти из полноэкранного режима
  1. Сначала мы установим все программы, необходимые для сборки библиотек libwebp и ImageMagick.
RUN yum groupinstall -y 'Development Tools'
RUN yum install -y libmagickwand-devel libtool-ltdl-devel libpng-devel pkgconfig glibc ghostscript
Вход в полноэкранный режим Выход из полноэкранного режима
  1. Настроим путь pkgconfig так, чтобы при настройке ImageMagick с поддержкой libwebp он находил собранные нами модули.
ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/lib/pkgconfig
Вход в полноэкранный режим Выйдите из полноэкранного режима
  1. Скачайте и соберите библиотеку libwebp. Это необходимо потому, что образ Amazon ruby не поставляется с обновленной версией библиотеки. Если мы не установим обновленную версию, ImageMagick не сможет настроить поддержку WebP на следующем этапе.
RUN curl https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.2.4.tar.gz --output libwebp-1.2.4.tar.gz 
    && tar xvzf libwebp-1.2.4.tar.gz
    && cd libwebp-1.2.4 
    && ./configure 
    && make 
    && make install 
    && /sbin/ldconfig /usr/local/lib
Вход в полноэкранный режим Выход из полноэкранного режима
  1. Скачайте, настройте и соберите ImageMagick. Код в основном не требует пояснений. Мы просто настроим ImageMagick с поддержкой WebP.
RUN git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.0
RUN cd ImageMagick-7.1.0
 && ./configure CPPFLAGS='-I/opt/local/include' LDFLAGS='-L/opt/local/lib' 
                --prefix=/usr 
                --without-perl 
                --with-modules 
                --without-magick-plus-plus 
                --disable-static 
                --disable-docs 
                --with-png=yes 
                --with-webp=yes 
                --with-gslib=yes 
 && make
 && make install
 && /sbin/ldconfig /usr/local/lib
Вход в полноэкранный режим Выход из полноэкранного режима

Итак, ниже приведена окончательная версия Dockerfile:

FROM public.ecr.aws/lambda/ruby:2.7 # OR: FROM amazon/aws-lambda-ruby:2.7

RUN yum groupinstall -y 'Development Tools'

RUN yum install -y libmagickwand-devel libtool-ltdl-devel libpng-devel pkgconfig glibc ghostscript

ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/lib/pkgconfig

RUN curl https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.2.4.tar.gz --output libwebp-1.2.4.tar.gz 
    && tar xvzf libwebp-1.2.4.tar.gz
    && cd libwebp-1.2.4 
    && ./configure 
    && make 
    && make install 
    && /sbin/ldconfig /usr/local/lib

RUN git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.1.0
RUN cd ImageMagick-7.1.0
 && ./configure CPPFLAGS='-I/opt/local/include' LDFLAGS='-L/opt/local/lib' 
                --prefix=/usr 
                --without-perl 
                --with-modules 
                --without-magick-plus-plus 
                --disable-static 
                --disable-docs 
                --with-png=yes 
                --with-webp=yes 
                --with-gslib=yes 
 && make
 && make install
 && /sbin/ldconfig /usr/local/lib

# Copy function code
COPY app.rb ${LAMBDA_TASK_ROOT}

# Copy dependency management file
COPY Gemfile ${LAMBDA_TASK_ROOT}

# Install dependencies under LAMBDA_TASK_ROOT
ENV GEM_HOME=${LAMBDA_TASK_ROOT}

RUN bundle install

# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "app.LambdaFunction::Handler.process" ]
Вход в полноэкранный режим Выход из полноэкранного режима

2. Сборка и тестирование образа Docker

Документация: Создание образов из базовых образов AWS:

https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-create-from-base

Следующий шаг — сборка образа Docker, и все должно работать хорошо.

Я создал Makefile, потому что я ленив и не помню команд:

build:
    docker build --rm -t my-project .
run:
    docker run -p 9000:8080 my-project:latest
test:
    curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"image_url": "https://www.cosy.sbg.ac.at/~pmeerw/Watermarking/lena_color.gif"}'
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы уже знаем, что делать: make build, затем make run. И из другой терминальной сессии выполните make test.

3. Автоматическое хранение образа в AWS ECR с помощью GitHub Actions

Начнем с создания репозитория в AWS Elastic Container Registry, где мы будем хранить наши образы.

Создайте контейнер AWS ECR

В AWS Console (убедитесь, что находитесь в нужном регионе):

  1. Перейдите к Amazon Elastic Container Registry.

  2. Создайте новый репозиторий и задайте имя.

  3. Теперь создадим пользователя, который будет иметь доступ к этому репозиторию. Перейдите в Identity Access Management (IAM).

  4. Пользователи → Создать нового пользователя → Пользователь с ключом доступа

  5. Добавьте политику AmazonEC2ContainerRegistryFullAccess из существующих политик.

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

  6. Сохраните наш ключ доступа и секретный ключ.

Создание действия GitHub

Теперь создадим действие GitHub.

  1. Перейдите в свой репозиторий GitHub → вкладка Действия

  2. Выберите Установить рабочий процесс самостоятельно.

  3. Добавьте следующий рабочий процесс, изменив ECR_REPOSITORY и IMAGE_TAG на имена наших проектов. Мы также захотим следить за aws-region, поставьте соответствующее значение.

name: Deploy to ECR
on:
  push:
    branches: [ master ]

jobs:
  build:
    name: Build Image
    runs-on: ubuntu-latest

    steps:
    - name: Check out code
      uses: actions/checkout@v2

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: eu-west-1

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: my-project-ecr-repository
        IMAGE_TAG: my-project-image
      run: |
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
Вход в полноэкранный режим Выход из полноэкранного режима
  1. Как видно из второго шага, нам нужно добавить ключи доступа и секреты AWS в наш репозиторий GitHub. Поэтому в нашем репозитории мы переходим в SettingsSecrets/Actions и добавляем те, которые мы сохранили ранее при создании пользователя на IAM.

    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY
  2. Теперь, когда мы сделаем фиксацию в нашей ветке master, мы запустим это действие, и оно переместит образ в наш репозиторий ECR. Сделайте это.

4. Создайте функцию AWS Lambda

Теперь мы создадим функцию AWS Lambda на основе этого образа Docker.

  1. Перейдите в AWS Lambda

  2. Создать новую функцию → Образ контейнера

  3. Добавьте имя нашей функции и выберите образ из ECR.

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

Когда мы добавляем новые версии образов в наш репозиторий ECR, функция Lambda не обновляется с новой версией, нам приходится делать это вручную. Я уверен, что существует способ автоматического обновления, но это также не является частью данного руководства.

5. Заключение

Вот и все. Теперь у нас есть функция AWS Lambda, которая имеет ImageMagick в качестве зависимости.

Я добавил это руководство в репозиторий. PR и отзывы очень приветствуются.

Репозиторий: https://github.com/alexmorral/public-guides/blob/main/aws/lambda-imagemagick-docker.md

Оцените статью
devanswers.ru
Добавить комментарий