Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AWS ❤ SAM / Serverless On Stage #9

AWS ❤ SAM / Serverless On Stage #9

The presentation features AWS SAM and some recently introduced tools/features that streamline Serverless project development lifecycle (Cloud9, Traffic Shifting, SAM Local)

Francesco Lerro

February 20, 2018
Tweet

More Decks by Francesco Lerro

Other Decks in Technology

Transcript

  1. HELLO! I am Francesco Lerro I am a Solution Architect

    who loves the Cloud Find me on Twitter @flerro
  2. Serverless Application Model ∎ CloudFormation extension for defining serverless application

    ∎ Infrastructure as code, local testing, automated deployment
  3. PROVISIONING aws cloudformation package --template-file template.yaml --output-template-file my-app.yaml --s3-bucket my-bucket

    aws cloudformation deploy --template-file my-app.yaml --capabilities CAPABILITY_IAM --stack-name my-app
  4. CloudFormation {"AWSTemplateFormatVersion":"2010-09-09","Description":"Creates an API gateway that's backed by a Lambda

    function","Parameters":{"APIName":{"Description":"Name of the API to create","Type":"String","AllowedPattern":"[A-Za-z0-9]*","MinLength":"4","MaxLength":"2 048","ConstraintDescription":"must contain only alphanumeric characters (at least four)"},"APIDescription":{"Description":"Description of the API to create","Type":"String","Default":"No description provided. Provide 'APIDescription' param to override this."},"APIPath":{"Description":"URL path for the API","Type":"String","Default":"api","AllowedPattern":"[A-Za-z0-9]*","MinLength":"1"," MaxLength":"64","ConstraintDescription":"must contain only alphanumeric characters (1-64 chars)"},"APIStageName":{"Description":"Stage name to deploy the API to","Type":"String","Default":"dev","AllowedPattern":"[A-Za-z0-9]*","MinLength":"1","M axLength":"64","ConstraintDescription":"must contain only alphanumeric characters (1-64 chars)"},"LambdaCodeBucket":{"Description":"Name of the S3 bucket that's storing the Lamba function's zip file","Type":"String"},"LambdaCodePath":{"Description":"Path to the zip file of code for the Lambda function","Type":"String"},"APIGatewayCustomResourceARN":{"Description":"The ARN pointing to the Lambda function that creates custom API gateway resources (install from https://apigatewaycloudformation.bynordenfelt.com/). Example: arn:aws:lambda:us-east-1:123456789012:function:APIGatewayCustomResource-LambdaFunction -ABCDEFG123","Type":"String"},"DynamoReadCapacityUnits":{"Description":"Provisioned read throughput","Type":"Number","Default":"1","MinValue":"1","MaxValue":"10000","Constrain tDescription":"must be between 1 and 10000"},"DynamoWriteCapacityUnits":{"Description":"Provisioned write throughput","Type":"Number","Default":"1","MinValue":"1","MaxValue":"10000","Constrain tDescription":"must be between 1 and 10000"}},"Resources":{"BackingLambdaFunction":{"Type":"AWS::Lambda::Function","Propert ies":{"Code":{"S3Bucket":{"Ref":"LambdaCodeBucket"},"S3Key":{"Ref":"LambdaCodePath"}}, "FunctionName":{"Fn::Join":["-",[{"Ref":"AWS::StackName"},{"Ref":"APIName"}]]},"Handle r":"index.handler","MemorySize":"128","Role":{"Fn::GetAtt":["BackingLambdaExecutionRol e","Arn"]},"Runtime":"nodejs4.3","Timeout":"3"}},"BackingLambdaInvokePermission":{"Typ e":"AWS::Lambda::Permission","Properties":{"FunctionName":{"Fn::GetAtt":["BackingLambd aFunction","Arn"]},"Action":"lambda: InvokeFunction","Principal":"apigateway.amazonaws.com"}},"BackingLambdaExecutionRole": {"Type":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10- 17","Statement":[{"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]},"A ction":["sts:AssumeRole"]}]},"Policies":[{"PolicyName":{"Fn::Join":["-",[{"Ref":"AWS:: StackName"},"UseDBPolicy"]]},"PolicyDocument":{"Version":"2012-10-17","Statement":[{"E InvokeFunction","Principal":"apigateway.amazonaws.com"}},"BackingLambdaExecutionRole":{"Type ":"AWS::IAM::Role","Properties":{"AssumeRolePolicyDocument":{"Version":"2012-10-17","Stateme nt":[{"Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]},"Action":["sts:Assum eRole"]}]},"Policies":[{"PolicyName":{"Fn::Join":["-",[{"Ref":"AWS::StackName"},"UseDBPolicy "]]},"PolicyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["dyna modb:DeleteItem","dynamodb:GetItem","dynamodb:PutItem","dynamodb:Query","dynamodb:Scan","dyn amodb:UpdateItem"],"Resource":{"Fn::Join":["",["arn:aws:dynamodb:",{"Ref":"AWS::Region"},":" ,{"Ref":"AWS::AccountId"},":table/",{"Ref":"APIDynamoDBTable"}]]}},{"Effect":"Allow","Action ":["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],"Resource":"*"}]}}]}}," MainAPI":{"Type":"Custom::RestApi","Properties":{"name":{"Fn::Join":["-",[{"Ref":"AWS::Stack Name"},{"Ref":"APIName"}]]},"description":{"Ref":"APIDescription"},"ServiceToken":{"Ref":"AP IGatewayCustomResourceARN"}}},"MainAPIResource":{"Type":"Custom::ApiResource","Properties":{ "ServiceToken":{"Ref":"APIGatewayCustomResourceARN"},"restApiId":{"Ref":"MainAPI"},"parentId ":{"Fn::GetAtt":["MainAPI","parentResourceId"]},"pathPart":{"Ref":"APIPath"},"corsConfigurat ion":{"allowMethods":["GET","POST"],"allowHeaders":["x-my-header","some-other-header"],"allo wDefaultHeaders":true,"allowOrigin":"*","exposeHeaders":["some-header","x-another-header"]," maxAge":1800}}},"APIMethodGet":{"Type":"Custom::ApiMethod","Properties":{"ServiceToken":{"Re f":"APIGatewayCustomResourceARN"},"restApiId":{"Ref":"MainAPI"},"resourceId":{"Ref":"MainAPI Resource"},"method":{"httpMethod":"GET","parameters":["querystring.sortBy","header.x-test-he ader","path.entityType"]},"integration":{"type":"AWS","uri":{"Fn::Join":[":",["arn:aws:apiga teway",{"Ref":"AWS::Region"},"lambda:path/2015-03-31/functions/arn:aws:lambda",{"Ref":"AWS:: Region"},{"Ref":"AWS::AccountId"},"function",{"Fn::Join":["/",[{"Fn::Join":["-",[{"Ref":"AWS ::StackName"},{"Ref":"APIName"}]]},"invocations"]]}]]},"httpMethod":"POST","requestTemplates ":{"application/json":["input-pass-through-full",{"DynamoDBTableName":{"Ref":"APIDynamoDBTab le"}}]},"requestParameters":{"integration.request.querystring.sortBy":"'hardcodedValue'"}}," responses":{"default":{"statusCode":"200","headers":{"X-Custom-Header":"'hardcodedValue'"}}, ".*NotFound.*":{"statusCode":"404"}}}},"APIMethodPost":{"Type":"Custom::ApiMethod","Properti es":{"ServiceToken":{"Ref":"APIGatewayCustomResourceARN"},"restApiId":{"Ref":"MainAPI"},"res ourceId":{"Ref":"MainAPIResource"},"method":{"httpMethod":"POST","parameters":["querystring. sortBy","header.x-test-header","path.entityType"]},"integration":{"type":"AWS","uri":{"Fn::J oin":[":",["arn:aws:apigateway",{"Ref":"AWS::Region"},"lambda:path/2015-03-31/functions/arn: aws:lambda",{"Ref":"AWS::Region"},{"Ref":"AWS::AccountId"},"function",{"Fn::Join":["/",[{"Fn ::Join":["-",[{"Ref":"AWS::StackName"},{"Ref":"APIName"}]]},"invocations"]]}]]},"httpMethod" :"POST","requestTemplates":{"application/json":["input-pass-through-full",{"DynamoDBTableNam e":{"Ref":"APIDynamoDBTable"}}]},"requestParameters":{"integration.request.querystring.sortB y":"'hardcodedValue'"}},"responses":{"default":{"statusCode":"200","headers":{"X-Custom-Head er":"'hardcodedValue'"}},".*NotFound.*":{"statusCode":"404"}}}},"DeployApi":{"Type":"Custom: :ApiDeploy","DependsOn":["APIMethodGet","APIMethodPost"],"Properties":{"ServiceToken":{"Ref" :"APIGatewayCustomResourceARN"},"restApiId":{"Ref":"MainAPI"},"stageName":{"Ref":"APIStageNa
  5. SAM LOCAL sam local generate-event api --method GET --path /products

    > event_payload.json sam local invoke MyFunction \ --log-file output.log \ -e event_payload.json sam local start-api \ --debug-port 5858
  6. Serverless framework Features: ∎ Provider-agnostic DSL for serverless application definition

    ∎ CLI commands for local debugging / testing and deployment ∎ Plugin ecosystem to manage additional aspects of app lifecycle
  7. SAM or Serverless framework? ∎ Similar features for local development,

    debugging and deploy ∎ SAM is more integrated with AWS ecosystem, but less mature ∎ Serverless framework has strong pugin ecosystem, but it is developed by a third party