Давайте узнаем, как использовать Serverless Framework для автоматизации серверной части AWS🔥
Эта статья является частью серии:
- Часть первая - Создание MVP
- Часть вторая - Учимся автоматизировать
Репозиторий GitHub: https://github.com/serverless-guru/real-time-weather
В первой части мы рассказали, как подключить AWS IoT MQTT к интерфейсу ReactJS. Предоставление нашему приложению ReactJS общения в режиме реального времени, при котором каждое устройство будет мгновенно * обновляться при публикации нового сообщения в нашей теме MQTT.
Во второй части мы расширим приложение, включив в него Serverless Framework, и сделаем следующее:
- Создайте базовый проект Serverless Framework
- Ознакомьтесь с лучшими практиками с помощью Serverless Framework
- Добавить ресурсы AWS
- Развернуть в AWS
- Протестируйте развернутую серверную часть AWS
Давай займемся этим!
Создайте базовый проект Serverless Framework
Если вы не знакомы с Serverless Framework и / или еще не настроили учетную запись AWS. Пожалуйста, прочтите нашу статью Введение в Serverless Framework или, при желании, посетите наш обучающий сайт и пройдите курс Serverless Introduction.
Создать новый проект
Мы создадим новый проект, используя шаблон Serverless Framework, который автоматически настраивает функцию NodeJS Lambda, готовую к развертыванию в AWS. Поскольку мы уже создали проект в прошлый раз, просто убедитесь, что вы находитесь в каталоге проекта.
sls create -t aws-nodejs -p backend -n real-time-weather
Эта команда создаст новый бессерверный проект с использованием шаблона aws-nodejs
, который даст нам некоторый шаблон в папке с именем backend
с именем службы, равным real-time-weather
🔥 🔥
Сначала давайте откроем наш любимый текстовый редактор, а затем я покажу вам, как копировать / вставлять, как старший облачный разработчик!
$real-time-weather: code .
Обновите раздел провайдера (добавьте флаги командной строки)
Мы захотим иметь возможность передавать динамическую stage
переменную, динамическую region
переменную и динамическую profile
переменную (для именованных профилей AWS).
Эти переменные помогут обеспечить:
- имена ресурсов AWS могут быть разными (многоэтапные развертывания)
- регион может быть другим (многорегиональное развертывание)
- аккаунт AWS может быть другим (развертывание с несколькими аккаунтами)
Скопируем следующий код в наш serverless.yml
файл:
provider: name: aws runtime: nodejs8.10 stage: ${opt:stage, "dev"} region: ${opt:region, "us-west-2"} profile: ${opt:profile, "default"}
Это добавит следующее:
- поставщик
aws
- время выполнения
nodejs8.10
- необязательный флаг
stage
со значением по умолчаниюstage
dev
- необязательный флаг
region
со значением по умолчаниюregion
us-west-2
- флаг опции
profile
со значением по умолчаниюprofile
default
Чтобы использовать эти флаги, мы запустим следующую команду:
serverless deploy --stage <> --region <> --profile <> -v
Теперь, когда resources/provider.yml
изолирован, давайте обновим serverless.yml
, чтобы он ссылался на наш отдельный файл.
provider: ${file(resources/provider.yml)}
Теперь, когда мы перейдем к развертыванию, свойство provider
будет заполнено файлом resources/provider.yml
.
Создать пользовательские переменные
Давайте создадим custom.yml
файл в нашей resources
папке по адресу resources/custom.yml
. Этот файл будет содержать все наши пользовательские переменные, которые мы можем централизовать в одном месте вместо жесткого кодирования в нескольких местах.
tableName: ${self:service}-${self:provider.stage}-data
На что тоже стоит обратить внимание:
${self:service}
невероятно похож наreal-time-weather
${self:provider.stage}
равноdev
или результат--stage <>
Теперь, когда resources/custom.yml
изолирован, давайте обновим serverless.yml
, чтобы он ссылался на наш отдельный файл.
custom: ${file(resources/custom.yml)}
Теперь, когда мы перейдем к развертыванию, свойство custom
будет заполнено файлом resources/custom.yml
, как если бы оно было написано встроенным.
Добавить ресурсы AWS
Теперь, когда у нас есть бессерверный проект. Давайте начнем добавлять ✨ в наши ресурсы AWS. Мы добавим следующее:
- DynamoDB - база данных NoSQL
- Лямбда - обрабатывает нашу внутреннюю логику.
- API Gateway - управляет маршрутизацией REST API.
Добавить DynamoDB
Теперь давайте создадим general.yml
файл в resources/general.yml
и скопируем следующее:
WeatherTable: Type: AWS::DynamoDB::Table Properties: KeySchema: - AttributeName: zip KeyType: HASH AttributeDefinitions: - AttributeName: zip AttributeType: S BillingMode: PAY_PER_REQUEST TableName: ${self:custom.tableName}
Это создаст таблицу DynamoDB со следующими настройками:
- первичный ключ
zip
, который будет строкой - режим выставления счетов для оплаты за запрос (например, нет трафика = бесплатно)
Давайте обновим файл serverless.yml
, включив в него ссылку на наш resources/general.yml
файл.
resources: Resources: ${file(resources/general.yml)}
Добавить лямбда-функцию API
Теперь давайте создадим functions.yml
файл по адресу resources/functions.yml
и скопируем следующее:
api: handler: api.handler events: - http: path: /api/weather method: GET cors: true environment: TABLE_NAME: Ref: WeatherTable
Здесь мы говорим о нескольких вещах:
- подключите нашу Лямбду к функции
handler()
внутриapi.js
файла - создать API на
/api/weather
, который может обрабатывать запросы GET - установите
cors: true
, чтобы разрешить двустороннюю связь через API - передать переменную окружения
TABLE_NAME
в нашу лямбда-функцию - динамически ссылаться на имя таблицы DynamoDB через
Ref: WeatherTable
Затем нам нужно обновить serverless.yml
, чтобы использовать наш файл resources/functions.yml
.
functions: ${file(resources/functions.yml)}
Добавить разрешения AWS IAM
Наша функция Lambda должна иметь соответствующие разрешения AWS IAM для доступа к DynamoDB и получения данных о погоде.
Давайте добавим раздел, который поможет в этом, под свойством provider
в нашем serverless.yml
файле.
provider: ... iamRoleStatements: - Effect: Allow Action: - dynamodb:GetItem Resource: Fn::GetAtt: - WeatherTable - Arn
Это сделает следующее:
- предоставьте нашей лямбда-функции доступ для выполнения
dynamodb:GetItem
- указать мы можем только
dynamodb:GetItem
наWeatherTable
Проверить прогресс
Отлично, давайте пока рассмотрим файл serverless.yml
.
service: real-time-weather provider: name: aws runtime: nodejs8.10 stage: ${opt:stage, "dev"} region: ${opt:region, "us-west-2"} profile: ${opt:profile, "default"} iamRoleStatements: - Effect: Allow Action: - dynamodb:GetItem Resource: Fn::GetAtt: - WeatherTable - Arn custom: ${file(resources/custom.yml)} functions: ${file(resources/functions.yml)} resources: Resources: ${file(resources/general.yml)}
Выше мы резко сократили общее количество строк в нашем serverless.yml
файле и решили изолировать различные компоненты нашей бессерверной серверной части для отдельных файлов. Этот уровень абстракции особенно полезен, когда вы начинаете масштабировать свои проекты.
По мере роста ваших проектов у вас может быть 3+ таблиц DynamoDB, целый ряд поддерживающих сервисов AWS и 10+ функций Lambda, которым требуются пользовательские переменные. Как вы понимаете, с этим может стать трудно справиться, если все это будет помещено в файл serverless.yml
.
Поэтому разбиваем его по папке resources
и сохраняем все аккуратно и аккуратно. Это называется прочной основой, и на ее создание стоит дополнительное время для каждого создаваемого вами бессерверного проекта.
Настроить лямбда-функцию API
Во-первых, давайте изменим файл handler.js
на api.js
. Затем мы можем вставить следующий код:
'use strict'; const AWS = require('aws-sdk'); const api = {}; const tableName = process.env.TABLE_NAME; api.handler = async (event, context) => { console.log('event', event); let response = {}; try { let data = {}; let path = event.path; if(path.includes('weather')) { data = await api.handleWeather(event); } response.statusCode = 200; response.body = JSON.stringify(data); } catch (error) { response.statusCode = 500; response.body = JSON.stringify(error); } response.headers = { 'Access-Control-Allow-Origin': '*' }; console.log('response: ', response); return response; }; api.handleWeather = async (event) => { if (event.httpMethod === "GET") { return await api.getCurrentWeatherData({ zip: event.queryStringParameters.zipCode }); } else { throw new Error(`event method not known ${event.httpMethod}`); } }; api.getCurrentWeatherData = (key) => { return new Promise((resolve, reject) => { let documentClient = new AWS.DynamoDB.DocumentClient(); let params = { TableName: tableName, Key: key }; documentClient.get(params, (err, data) => { if (err) reject(err); else resolve(data); }); }); }; module.exports = api;
Этот код будет делать несколько вещей:
- импорт
aws-sdk
, позволяющий нам подключиться к DynamoDB - ссылаться на переменную среды через
process.env.TABLE_NAME
- добавить
handleWeather()
функцию для управления всеми запросами API к/weather
- добавить
getCurrentWeatherData()
функцию для запроса погоды поzip
Отсюда у нас должно быть все необходимое для получения данных через zip
(например, 97205
) и получения ответа из таблицы погоды DynamoDB с текущей погодой в нашем zip
.
Разверните серверную часть в AWS
Создана вся наша автоматизация благодаря мощности Serverless Framework. Давайте попробуем развернуть наш бессерверный стек в AWS.
sls --stage test --region us-west-2 --profile default -v
Это развернет наш бэкэнд на этапеtest
и в регионе us-west-2
с профилем AWS с именем default
.
Загрузите данные в DynamoDB
В настоящее время у нас есть только конечная точка GET API, поэтому мы вручную добавим данные в DynamoDB, а затем попытаемся извлечь эти данные.
Протестируйте серверную часть AWS
После успешного развертывания серверной части мы можем протестировать API через Postman, отправив запрос с параметром queryStringParmeter равным ?zipCode=97205
.
Замечательно, мы получили данные из DynamoDB и подтвердили, что наша автоматизация полностью работает, чтобы развернуть весь наш бэкэнд.
Срывать
Если вы хотите остановиться на этом, мы можем закрыть бессерверный бэкэнд, выполнив следующую команду.
sls remove --stage test --region us-west-2 --profile default -v
Это сделает следующее:
- удалите нашу лямбда-функцию
- удалите нашу конечную точку шлюза API на
/api/weather
- удалите нашу таблицу DynamoDB
- удалите наши политики AWS IAM
В следующий раз мы пойдем еще глубже
Если вам понравилось это руководство, следите за обновлениями, мы расскажем о третьей части, в которой будет рассказано о создании функции Lambda, которая запускается по расписанию и автоматически отправляет сообщения на наши устройства AWS MQTT.
Это позволяет нашим пользователям автоматически получать обновления погоды в реальном времени!
Дополнительный контент:
- Отраслевой прогноз на 2019 год
- Лучшие практики для бессерверной разработки
- Бессерверный CI / CD
- Бессерверные веб-приложения - AWS v GCP
- Бессерверное влияние, скорость разработчика
- Путеводитель, Первый бессерверный проект
Что делает Serverless Guru?
Serverless Guru помогает компаниям создавать масштабируемые и экономичные приложения в облаке. Мы помогаем обучать компании тому, как использовать IAC, бессерверные и облачные сервисы. Мы помогаем перенести существующие приложения в облако и оптимизировать существующие приложения в облаке, чтобы сделать их более рентабельными. Мы являемся партнером по бессерверной разработке и партнером-консультантом AWS.
Что мы упустили?
Когда вы оставляете свой ответ, обязательно оставьте комментарий ниже или напишите свой ответ @serverlessgurux в Twitter.
Райан Джонс
Основатель и генеральный директор - Serverless Guru
LinkedIn - @ryanjonesirl
Twitter - @ryanjonesirl
Спасибо за чтение 😃
Если вы хотите узнать больше о Serverless Guru, подпишитесь на нас в Medium, Twitter, Instagram, Facebook или LinkedIn!