Фреймворк Serverless упрощает развертывание приложений в AWS Lambda. Однако в настоящее время Serverless не поддерживает бинарные файлы, но мы можем решить эту проблему, реализовав плагин Serverless и загрузив правильную конфигурацию в AWS API Gateway.
В этой статье мы:
— Настроим npm-проект и создадим приложение «Hello World» с красивым фоновым изображением
— Настроим фреймворк Serverless и развернем это приложение на AWS Lambda
— Научимся использовать AWS SDK, воссоздав плагин serverless для поддержки бинарных файлов в AWS API Gateway
— Опубликуем плагин в репозитории npm
Для выполнения задач в этой статье вам понадобятся:
— Аккаунт AWS
— Аккаунт npm
— Установленные Node.js и npm
— Установленный AWS CLI
# Настройка окружения и «Hello World!»
Создадим наше приложение. Настроим npm-проект и установим зависимости:
Создадим наше приложение:
Внутри `dist/app.js`:
мы будем:
— Инициализировать приложение express
— Устанавливать расширение представлений и каталог
— Добавлять отображение на главную страницу (‘/’)
Для этого вставьте этот код в файл `dist/app.js`:
Далее добавим наше представление. Вставьте этот код в файл `dist/views/index.html`:
Пришло время для некоторой стильной декорации с помощью CSS. Вставьте эти стили в файл `dist/assets/css/main.css`:
Как видите, мы используем изображение в качестве фона для нашего приложения. Вы можете получить его здесь и сохранить в каталоге `dist/assets/img` как `sandbox.gif`:
Оно стильное. Не правда ли?
Мы готовы поместить некоторый код в наш файл «localhost-entry», `local.js`:
Нам нужно только добавить соответствующие скрипты в файл `package.json`:
И мы можем запустить наше приложение на localhost:
Вы должны увидеть вывод этой команды:
Перейдя по указанному URL в браузере, вы должны увидеть:
Ок! Приложение готово. Теперь перейдем к развертыванию его на AWS Lambda. Нам нужно добавить два файла:
В `lambda.js` добавьте код для функции AWS Lambda:
В `serverless.yml` добавьте следующую конфигурацию:
Теперь нам нужно добавить только еще один скрипт в `package.json`:
И мы можем развернуть приложение:
Вывод этой команды должен быть:
Перейдя по предоставленному URL, вы можете увидеть ваше приложение, развернутое на AWS Lambda.
Но… эй… мое потрясающее фоновое изображение отсутствует!
Это связано с отсутствием поддержки бинарных файлов в нашем API Gateway, но мы можем решить это с помощью нашего плагина.
Если вы хотите наверстать этот шаг:
Мы можем использовать консоль AWS для решения проблемы вручную. После входа в консоль выберите «API Gateway» из меню «Services» в разделе «Application Services» и нажмите на ваш API (убедитесь, что вы находитесь в правильном регионе AWS):
Из левой панели навигации выберите `Binary support`:
Как видите, здесь нет ни одного типа. Добавим тип нашего изображения: нажмите кнопку `edit`, затем `add binary media type` введите `image/gif` и нажмите `save`:
После этого (и любого другого) изменения в API Gateway вам нужно будет переразвернуть его:
Какого черта?! Ладно, легко. В AWS API Gateway есть одна «маленькая» проблема. Обновите ваш запрос с заголовком `Accept` и значением `image/gif`. Взрыв! Теперь это работает:
Но… браузер не отправляет заголовок `Accept`. Что теперь? Есть обходной путь. Чтобы API Gateway отправлял бинарные файлы в ответ на каждый запрос (без ожидания заголовка `Accept`), вам нужно указать хотя бы один тип MIME как универсальный `*/*`. Вы можете узнать больше об этой проблеме здесь:
https://github.com/awslabs/serverless-application-model/issues/145#issuecomment-311672573
Как написано в проблеме, теперь все наши бинарные данные отправляются в кодировке base64, поэтому нам нужно декодировать их на стороне сервера. Измените файл `lambda.js` на:
Теперь наше приложение будет работать правильно. Разверните его снова (`npm run deploy`) и проверьте предоставленный URL.
git clone https://github.com/maciejtreder/serverless-apigw-binary.git
cd serverless-apigw-binary
git checkout tutorialSecondStep
npm install
npm run deploy
# Создание плагина Serverless
У нас готово и работает наше приложение. Но мы не можем остановиться на этом. Мы используем Serverless для автоматизации процесса развертывания. Ручная настройка поддержки бинарных файлов в консоли AWS — это определенно не то, что нам нужно. Давайте создадим плагин, который будет настраивать типы бинарных файлов для нас во время развертывания.
Мы будем хранить все в одном репозитории, в двух каталогах `example/express` (здесь будет находиться приложение) и `plugin`.
Перенесем наше приложение в подкаталог:
Создадим основной файл для нашего плагина и инициализируем npm-проект:
Нам нужно внести одно важное изменение в файл `package.json`. Убедитесь, что значение поля «main» — `src/index.js` (точный путь к точке входа нашего плагина). Ваш `package.json` плагина должен выглядеть примерно так:
Теперь мы можем начать писать плагин. Укажем основной класс для него и соответствующий конструктор (в файле `src/index.js`):
Попробуем использовать наш плагин с приложением:
Добавим плагин в вашу конфигурацию Serverless. Вставьте это в `serverless.yml`:
И посмотрим, будет ли сообщение «Hello world!» отображаться в консоли:
Мы должны увидеть вывод:
Ура! Идем дальше. Что мы будем делать сейчас, так это переместим наше сообщение в метод и привяжем его к хуку `after:deploy:deploy` (хуки описываются по соглашению `::`, поэтому наш хук означает: после того, как пользователи запустят команду `deploy`, выполнится `deploy` после метода `afterDeploy`). Вот как должен выглядеть файл `../../plugin/src/index.js` после этих изменений:
Выполнение `deploy` должно дать следующий вывод:
Ок. Плагин работает, хук работает. Теперь подключимся к AWS, используя их SDK, и внесем соответствующие изменения в только что развернутый API. Для начала укажем типы MIME в файле `serverless.yml` (соглашение: `custom -> pluginName -> values`):
Получим их в конструкторе плагина (`../../plugin/src/index.js`):
Дополнительные данные, которые нам нужно собрать, — это используемый провайдер и этап, на который мы развертываем:
Следующим шагом будет добавление метода `getApiId` в наш класс `BinarySupport`. Для этого мы будем использовать метод `describeStacks` из AWS SDK. Мы можем повторно использовать метод `request` из класса `serverless.provider`, потому что он содержит некоторую полезную логику, такую как поддержка различных профилей AWS и повторные попытки запросов в случае ошибки.
В качестве параметра нам нужно передать имя класса из AWS SDK (`CloudFormation`), метод, который мы хотим вызвать (`describeStacks`), и полезную нагрузку, которую мы хотим передать ему:
Попробуем. Обновим метод `afterDeploy` следующим кодом:
Для следующего шага нам нужен URL нашего только что развернутого API. Он скрыт в `Outputs: [Array]`. Выведем его. Внесем изменения в метод `afterDeploy` внутри `plugin/src/index.js`:
Если вы снова вызовете `npm run deploy` (из каталога `example/express`), вы должны получить в выводе эти строки:
Теперь у нас есть полная информация о только что развернутом стеке. Самое важное для нас находится в массиве `Outputs`. Там есть наш `ServiceEndpoint`, который содержит API ID. Отфильтруем этот вывод и получим этот ID:
Что мы собираемся сделать сейчас, так это поместить наши `binaryTypes` в этот API. Мы предоставим изменения в формате Swagger, поэтому подготовим их внутри нашего метода хука – `afterDeploy()`.
Добавьте следующий код в начало метода `afterDeploy()`:
Как видите, внутри JSON-тела константы `swaggerInput` мы предоставляем информацию о версии формата Swagger, заголовке нашего API (если мы этого не сделаем, AWS перезапишет имя нашего API значением по умолчанию) и `x-amazon-apigateway-binary-media-types`, куда мы передаем массив строк, представляющих типы MIME, предоставленные конфигурационным файлом `serverless.yml`.
Реализуем метод `getApiGatewayName` внутри нашего класса `BinarySupport`:
Ок. Мы собрали API ID и имя; теперь мы можем внести изменения. Для этого мы будем использовать метод `putRestApi` из AWS SDK и передавать информацию об изменениях, которые мы хотим выполнить:
Мы будем объединять все добавленные методы в хуке `after:deploy:deploy`. Обновим его:
Мы готовы протестировать наш плагин. Чтобы убедиться, что у нас нет старых развертываний, удалим их:
Теперь мы снова развернем приложение, войдем в консоль AWS и посмотрим на раздел `Binary Support`. Ура! Приложение там! Типы бинарных файлов есть! Перейдем к нему. О… проблема, опять. Красивая картинка пропала..
Причина проста. Вы помните, что мы переразвертывали API после любых изменений в нем? Это то, что мы забыли сделать с нашим плагином Serverless. Добавим этот шаг:
Теперь мы можем развернуть наше приложение и радоваться, потому что оно работает правильно, а процесс развертывания полностью автоматизирован!
Если вы хотите наверстать этот шаг:
Итак, у нас готов плагин. Он работает отлично. Что дальше? Теперь мы сделаем наш плагин доступным для всего мира!
У нас есть несколько способов сделать это.
Это очень просто. Вам нужно сделать две вещи.
Войдите в свою учетную запись npm через npm CLI:
И опубликуйте пакет:
Более интересно (по моему мнению) — развертывание через Git. Почему? Это дает вам возможность сделать ваш пакет доступным только для тех, кого вы хотите, чтобы он использовался (например, команда в вашей компании).
Единственное, что вам нужно сделать, — это отправить ваш код в репозиторий:
После этого, если вы хотите установить пакет в свой проект, вам нужно будет предоставить адрес вашего git-репозитория, например:
`npm install https://github.com/maciejtreder/serverless-apigw-binary.git`
В предыдущей статье мы узнали, как использовать фреймворк Serverless. Сегодня мы создали плагин Serverless с использованием AWS SDK для компенсации отсутствия стандартной поддержки бинарных файлов. Теперь мы готовы использовать эти знания и создать что-то потрясающее. В следующей статье мы создадим и развернем приложение Angular 4 на AWS Lambda!
Живую демонстрацию приложения, использованного в этой статье, можно найти здесь: https://serverless-apigw.maciejtreder.com
Git-репозиторий плагина: https://github.com/maciejtreder/serverless-apigw-binary
NPM-репозиторий плагина: https://www.npmjs.com/package/serverless-apigw-binary
Maciej Treder,
contact@maciejtreder.com
https://www.maciejtreder.com
@maciejtreder (GitHub, Twitter, StackOverflow, LinkedIn)