Введение в модель сервера приложений AWS
1. обзор
Вour previous article мы уже реализовали полнофункциональное бессерверное приложение на AWS, используя API Gateway для конечных точек REST, AWS Lambda для бизнес-логики, а также DynamoDB в качестве базы данных.
Однако развертывание состоит из множества этапов, выполняемых вручную, что может оказаться затруднительным из-за растущей сложности и количества сред.
В этом руководстве мы обсудим, как использоватьAWS Serverless Application Model (SAM), which enables a template-based description and automated deployment of serverless applications on AWS.
Подробно рассмотрим следующие темы:
-
Основы модели серверных приложений (SAM), а также базовой CloudFormation
-
Определение безсерверного приложения с использованием синтаксиса шаблона SAM
-
Автоматическое развертывание приложения с использованием CloudFormation CLI
2. основы
Как обсуждалосьpreviously, AWS позволяет нам реализовывать полностью бессерверные приложения, используя API Gateway, функции Lambda и DynamoDB. Несомненно, это предлагает уже много преимуществ для производительности, стоимости и масштабируемости.
Однако недостатком является то, что в настоящий момент нам нужно много ручных шагов в Консоли AWS, таких как создание каждой функции, загрузка кода, создание таблицы DynamoDB, создание ролей IAM, создание API и структуры API и т. Д.
Для сложных приложений и с несколькими средами, такими как тестирование, подготовка и производство, это усилие быстро увеличивается.
Именно здесь вступает в игру CloudFormation для приложений в AWS в целом и Модель без серверов (SAM) специально для приложений без серверов.
2.1. AWS CloudFormation
CloudFormation - это сервис AWS для автоматического выделения ресурсов инфраструктуры AWS. Пользователь определяет все необходимые ресурсы в схеме (называемой шаблоном), а AWS заботится о предоставлении и настройке.
Следующие термины и понятия необходимы для понимания CloudFormation и SAM:
A template is a description of an application, как он должен быть структурирован во время выполнения. Мы можем определить набор необходимых ресурсов, а также то, как эти ресурсы должны быть настроены. CloudFormation предоставляет общий язык для определения шаблонов, поддерживая JSON и YAML в качестве формата.
Resources are the building blocks in CloudFormation. Ресурсом может быть что угодно, например RestApi, этап RestApi, пакетное задание, таблица DynamoDB, экземпляр EC2, сетевой интерфейс, роль IAM и многие другие. The official documentation в настоящее время перечисляет около 300 типов ресурсов для CloudFormation.
A stack is the instantiation of a template. CloudFormation позаботится о предоставлении и настройке стека.
2.2. Модель бессерверного приложения (SAM)
Как часто, использование мощных инструментов может быть очень сложным и неудобным, что также имеет место в CloudFormation.
Вот почему Amazon представила модель бессерверных приложений (SAM). SAM started with the claim to provide a clean and straightforward syntax for defining serverless applications. Currently, it has only three resource types, which are Lambda functions, DynamoDB tables, and APIs.
SAM основан на синтаксисе шаблона CloudFormation, поэтому мы можем определить наш шаблон, используя простой синтаксис SAM, и CloudFormation будет и дальше обрабатывать этот шаблон.
Более подробная информация доступна как вat the official GitHub repository, так и вAWS documentation.
3. Предпосылки
Для следующего руководства нам понадобится учетная запись AWS. A free tier account должно быть достаточно.
Кроме того, нам нужен AWS CLIinstalled.
Наконец, нам нужен S3 Bucket в нашем регионе, который можно создать с помощью интерфейса командной строки AWS с помощью следующей команды:
$>aws s3 mb s3://example-sam-bucket
Хотя в следующем руководстве используетсяexample-sam-bucket, имейте в виду, что имена сегментов должны быть уникальными, поэтому вы должны выбрать свое имя.
В качестве демонстрационного приложения мы будем использовать код изUsing AWS Lambda with API Gateway.
4. Создание шаблона
В этом разделе мы создадим наш шаблон SAM.
Прежде чем определять отдельные ресурсы, мы сначала рассмотрим общую структуру.
4.1. Структура шаблона
Во-первых, давайте посмотрим на общую структуру нашего шаблона:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example
Resources:
PersonTable:
Type: AWS::Serverless::SimpleTable
Properties:
# Define table properties here
StorePersonFunction:
Type: AWS::Serverless::Function
Properties:
# Define function properties here
GetPersonByHTTPParamFunction:
Type: AWS::Serverless::Function
Properties:
# Define function properties here
MyApi:
Type: AWS::Serverless::Api
Properties:
# Define API properties here
Как мы видим, шаблон состоит из заголовка и тела:
В заголовке указывается версия шаблона CloudFormation (AWSTemplateFormatVersion), а также версия нашего шаблона SAM (Transform). Мы также можем указатьDescription.
Тело состоит из набора ресурсов: каждый ресурс имеет имя, ресурсType и наборProperties.
В настоящее время спецификация SAM поддерживает три типа:AWS::Serverless::Api,AWS::Serverless::Function, а такжеAWS::Serverless::SimpleTable.
Поскольку мы хотим развернуть нашexample application, мы должны определить одинSimpleTable, дваFunctions, а также одинApi в нашем теле шаблона.
4.2. Определение таблицы DynamoDB
Теперь давайте определим нашу таблицу DynamoDB:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example
Resources:
PersonTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: id
Type: Number
TableName: Person
Нам нужно только определить два свойства для нашегоSimpleTable: имя таблицы, а также первичный ключ, который называетсяid и в нашем случае имеет типNumber .
Полный список поддерживаемых свойствSimpleTable можно найти вin the official specification.
Примечание. Поскольку мы хотим получить доступ к таблице только с использованием первичного ключа, нам достаточноAWS::Serverless::SimpleTable. Для более сложных требований вместо него можно использовать собственный тип CloudFormationAWS::DynamoDB::Table.
4.3. Определение лямбда-функций
Затем давайте определим две наши функции:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example
Resources:
StorePersonFunction:
Type: AWS::Serverless::Function
Properties:
Handler: com.example.lambda.apigateway.APIDemoHandler::handleRequest
Runtime: java8
Timeout: 15
MemorySize: 512
CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
Policies: DynamoDBCrudPolicy
Environment:
Variables:
TABLE_NAME: !Ref PersonTable
Events:
StoreApi:
Type: Api
Properties:
Path: /persons
Method: PUT
RestApiId:
Ref: MyApi
GetPersonByHTTPParamFunction:
Type: AWS::Serverless::Function
Properties:
Handler: com.example.lambda.apigateway.APIDemoHandler::handleGetByParam
Runtime: java8
Timeout: 15
MemorySize: 512
CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
Policies: DynamoDBReadPolicy
Environment:
Variables:
TABLE_NAME: !Ref PersonTable
Events:
GetByPathApi:
Type: Api
Properties:
Path: /persons/{id}
Method: GET
RestApiId:
Ref: MyApi
GetByQueryApi:
Type: Api
Properties:
Path: /persons
Method: GET
RestApiId:
Ref: MyApi
Как мы видим, каждая функция имеет одинаковые свойства:
Handler defines the logic of the function. Поскольку мы используем Java, это имя класса, включая пакет, в связи с именем метода.
Runtime defines how the function was implemented, в нашем случае это Java 8.
Timeout defines how long the execution of the code may take at most до того, как AWS завершит выполнение.
MemorySizedefines the size of the assigned memory in MB. Важно знать, что AWS распределяет ресурсы ЦП пропорциональноMemorySize. Таким образом, в случае функции, интенсивно использующей ЦП, может потребоваться увеличитьMemorySize, даже если функции не требуется столько памяти.
CodeUridefines the location of the function code. В настоящее время он ссылается на целевую папку в нашей локальной рабочей области. Когда мы позже загрузим нашу функцию с помощью CloudFormation, мы получим обновленный файл со ссылкой на объект S3.
Policiescan hold a set of AWS-managed IAM policies or SAM-specific policy templates. Мы используем специальные политики SAMDynamoDBCrudPolicy дляStorePersonFunction иDynamoDBReadPolicy дляGetPersonByPathParamFunction иGetPersonByQueryParamFunction.
Environmentdefines environment properties at runtime. Мы используем переменную среды для хранения имени нашей таблицы DynamoDB.
Eventscan hold a set of AWS events, which shall be able to trigger the function. В нашем случае мы определяемEvent типаApi. Уникальная комбинацияpath, HTTPMethod иRestApiId связывает функцию с методом нашего API, который мы определим в следующем разделе.
Полный список поддерживаемых свойствFunction можно найти вin the official specification.
4.4. Определение API как файл Swagger
После определения таблицы и функций DynamoDB теперь мы можем определить API.
Первая возможность - определить наш встроенный API-интерфейс в формате Swagger:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model example
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: test
EndpointConfiguration: REGIONAL
DefinitionBody:
swagger: "2.0"
info:
title: "TestAPI"
paths:
/persons:
get:
parameters:
- name: "id"
in: "query"
required: true
type: "string"
x-amazon-apigateway-request-validator: "Validate query string parameters and\
\ headers"
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetPersonByHTTPParamFunction.Arn}/invocations
responses: {}
httpMethod: "POST"
type: "aws_proxy"
put:
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${StorePersonFunction.Arn}/invocations
responses: {}
httpMethod: "POST"
type: "aws_proxy"
/persons/{id}:
get:
parameters:
- name: "id"
in: "path"
required: true
type: "string"
responses: {}
x-amazon-apigateway-integration:
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetPersonByHTTPParamFunction.Arn}/invocations
responses: {}
httpMethod: "POST"
type: "aws_proxy"
x-amazon-apigateway-request-validators:
Validate query string parameters and headers:
validateRequestParameters: true
validateRequestBody: false
НашApi имеет три свойства:StageName определяет стадию API,EndpointConfiguration определяет, является ли API региональным или оптимизированным по краям, аDefinitionBody содержит фактическую структуру API.
ВDefinitionBody мы определяем три параметра: версиюswagger как“2.0”,info:title: как“TestAPI”, а также наборpaths .
Как мы видим,paths представляют структуру API, которую нам пришлось определить вручнуюbefore. paths в Swagger эквивалентны ресурсам в консоли AWS. Точно так же каждыйpath может иметь один или несколько HTTP-глаголов, которые эквивалентны методам в Консоли AWS.
Каждый метод может иметь один или несколько параметров, а также валидатор запроса.
Самая интересная часть - это атрибутx-amazon-apigateway-integration, который является специфичным для AWS расширением Swagger:
uri указывает, какая лямбда-функция должна быть вызвана.
responses определяют правила преобразования ответов, возвращаемых функцией. Поскольку мы используем интеграцию с лямбда-прокси, нам не нужно никаких конкретных правил.
type определяет, что мы хотим использовать интеграцию с лямбда-прокси, и поэтому мы должны установитьhttpMethod на“POST”, так как это то, что ожидают лямбда-функции.
Полный список поддерживаемых свойствApi можно найти вin the official specification.
4.5. Неявное определение API
Второй вариант - это неявное определение API в ресурсах Function:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: example Serverless Application Model Example with Implicit API Definition
Globals:
Api:
EndpointConfiguration: REGIONAL
Name: "TestAPI"
Resources:
StorePersonFunction:
Type: AWS::Serverless::Function
Properties:
Handler: com.example.lambda.apigateway.APIDemoHandler::handleRequest
Runtime: java8
Timeout: 15
MemorySize: 512
CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref PersonTable
Environment:
Variables:
TABLE_NAME: !Ref PersonTable
Events:
StoreApi:
Type: Api
Properties:
Path: /persons
Method: PUT
GetPersonByHTTPParamFunction:
Type: AWS::Serverless::Function
Properties:
Handler: com.example.lambda.apigateway.APIDemoHandler::handleGetByParam
Runtime: java8
Timeout: 15
MemorySize: 512
CodeUri: ../target/aws-lambda-0.1.0-SNAPSHOT.jar
Policies:
- DynamoDBReadPolicy:
TableName: !Ref PersonTable
Environment:
Variables:
TABLE_NAME: !Ref PersonTable
Events:
GetByPathApi:
Type: Api
Properties:
Path: /persons/{id}
Method: GET
GetByQueryApi:
Type: Api
Properties:
Path: /persons
Method: GET
Как мы видим, наш шаблон теперь немного изменился: больше нет sresourceAWS::Serverless::Api .
Однако CloudFormation принимает атрибутыEvents типаApi как неявное определение и в любом случае создает API. Как только мы протестируем наше приложение, мы увидим, что оно ведет себя так же, как и при явном определении API с помощью Swagger.
Кроме того, есть разделGlobals, в котором мы можем определить имя нашего API, а также указать, что наша конечная точка должна быть региональной.
Имеется только одно ограничение: при неявном определении API мы не можем установить имя этапа. Вот почему AWS в любом случае создаст этап под названиемProd.
5. Развертывание и тестирование
После создания шаблона мы можем приступить к развертыванию и тестированию.
Для этого мы загрузим код нашей функции в S3, прежде чем запускать фактическое развертывание.
В конце концов, мы можем протестировать наше приложение, используя любой HTTP-клиент.
5.1. Загрузка кода в S3
На первом этапе мы должны загрузить код функции на S3.
Мы можем сделать это, вызвав CloudFormation через интерфейс командной строки AWS:
$> aws cloudformation package --template-file ./sam-templates/template.yml --s3-bucket example-sam-bucket --output-template-file ./sam-templates/packaged-template.yml
С помощью этой команды мы запускаем CloudFormation, чтобы взять код функции, указанный вCodeUri:, и загрузить его в S3. CloudFormation создаст файлpackaged-template.yml с таким же содержимым, за исключением того, чтоCodeUri: теперь указывает на объект S3.
Давайте посмотрим на вывод CLI:
Uploading to 4b445c195c24d05d8a9eee4cd07f34d0 92702076 / 92702076.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-template.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file c:\zz_workspace\tutorials\aws-lambda\sam-templates\packaged-template.yml --stack-name
5.2. развертывание
Теперь мы можем запустить фактическое развертывание:
$> aws cloudformation deploy --template-file ./sam-templates/packaged-template.yml --stack-name example-sam-stack --capabilities CAPABILITY_IAM
Поскольку нашему стеку также нужны роли IAM (например, роли функций для доступа к нашей таблице DynamoDB), мы должны явно подтвердить это, указав–capabilities parameter.
И вывод CLI должен выглядеть так:
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - example-sam-stack
5.3. Обзор развертывания
После развертывания мы можем рассмотреть результат:
$> aws cloudformation describe-stack-resources --stack-name example-sam-stack
CloudFormation перечислит все ресурсы, которые являются частью нашего стека.
5.4. Test
Наконец, мы можем протестировать наше приложение, используя любой HTTP-клиент.
Давайте посмотрим на несколько примеров командcURL, которые мы можем использовать для этих тестов.
StorePersonFunction:
$> curl -X PUT 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons' \
-H 'content-type: application/json' \
-d '{"id": 1, "name": "John Doe"}'
GetPersonByPathParamFunction:
$> curl -X GET 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons/1' \
-H 'content-type: application/json'
GetPersonByQueryParamFunction:
$> curl -X GET 'https://0skaqfgdw4.execute-api.eu-central-1.amazonaws.com/test/persons?id=1' \
-H 'content-type: application/json'
5.5. Очистить
В конце мы можем очистить, удалив стек и все включенные ресурсы:
aws cloudformation delete-stack --stack-name example-sam-stack
6. Заключение
В этой статье мы познакомились с моделью серверных приложений AWS (SAM), которая обеспечивает описание на основе шаблонов и автоматическое развертывание приложений без серверов в AWS.
Подробно мы обсудили следующие темы:
-
Основы модели серверного приложения (SAM), а также базовая CloudFormation
-
Определение безсерверного приложения с использованием синтаксиса шаблона SAM
-
Автоматическое развертывание приложения с использованием CloudFormation CLI
Как обычно, весь код для этой статьи доступен черезon GitHub.