Skip to content

AWS SAM - Serverless Application Model

AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, databases and APIs.

SAM CLI is an open-source. Better to use within Cloud9 environment and install sam CLI.

SAM includes two parts:

  1. SAM template specification: It is an extension on top of AWS CloudFormation.
  2. A CLI to create new project, build and deploy, perform local debugging and testing, configure pipeline.

Here is an example of definition of a serverless app including: AWS Lambda, API gateway with HTTP api, database in DynamoDB and then IAM permissions for those services to work together.

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
  getAllItemsFunction:
    Type: AWS::Serverless::Function
    Properties:
        Handler: src/get-all-items.getAllItemsHandler
        Runtime: nodejs12.x
        Events:
            Api:
            Type: HttpApi
            Properties:
                Path: /
                Method: GET
        Connectors:
        MyConn:
            Properties:
            Destination:
            Id: SampleTable
            Permissions:
                - Read
    SampleTable:
        Type: AWS::Serverless::SimpleTable

During deployment, SAM transforms and expands the SAM syntax into AWS CloudFormation syntax.

See SAM templates here

Value propositions

  • Define the application infrastructure code as quickly, using less code.
  • Manage the serverless applications through their entire development lifecycle.
  • Quickly provision permissions between resources with AWS SAM connectors.
  • Continuously sync local changes to the cloud as we develop.
  • On top of CloudFormation or Terraform.

Getting started

SAM CLI provides a Lambda-like execution environment that lets you locally build, test, and debug applications defined by SAM templates or through the AWS Cloud Development Kit (CDK).

  • Install, which can be summarized as:
brew install aws-sam-cli
# or upgrade
brew upgrade aws-sam-cli
sam --version

Summary of application development with SAM

The diagram below presents the classical app components that can be created with SAM:

The following steps presents how to get a Lambda in Python exposed with API in API Gateway.

  • Create a SAM project

    # Create a new function using interactive mode:
    sam init
    # or using parameters: Xray tracing, CloudWatch insights, python
    sam init --name sam-app --runtime python3.9 --architecture arm64 --app-template hello-world --tracing --application-insights 
    # or using powertool so we have metrics, logging, tracing
    sam init --app-template hello-world-powertools-python --name carridegenerator --package-type Zip --runtime python3.9 --no-tracing
    

    See the code templates in the git repo.

  • When using container Image as the packaging mechanism, we need to login to ECR repo via:

    aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
    
  • Run locally - Any code update will be refreshed. First call may take sometime to download docker image. It needs docker engine to run locally. (finch is not supported yet)

    # a python app:
    cd sam-app/hello_world
    pip3 install -r requirements.txt
    
    cd ..
    sam local invoke
    # test with input event
    sam local invoke HelloWorldFunction --event events/event.json
    # Emulate API on port 8080
    sam local start-api --port 8080
    curl http://localhost:8080/hello
    
  • Run unit tests

    # under sam-app
    pip3 install pytest pytest-mock
    python3 -m pytest tests/unit
    
  • Build the packaging for AWS

    # under sam-app
    sam build
    # see .aws-sam folder
    # Build with Image on Mac
    DOCKER_HOST=unix://$HOME/.docker/run/docker.sock sam build --use-container
    # Build on linux
    sam build --use-container
    
  • Deploy (be sure to get aws cli 'configured' with access key and secret). It is creating the resources (Lambda function, API Gateway and IAM roles)

    # under sam-app
    sam deploy --guided
    

    The code is zipped and uploaded to a s3 bucket: aws-sam-cli-managed-default-samclisourcebucket-...

    # deploy with parameters
    export AWS_REGION=$(aws --profile default configure get region)
    sam deploy \
        --stack-name wild-rydes-async-msg-1 \
        --capabilities CAPABILITY_IAM \
        --region $AWS_REGION \
        --guided
    
    Deployment Output

    A cloud formation template is created which includes Role, and API Gateway so the Lambda is accessible via REST API.

    CloudFormation stack changeset
    ----------------------------------------------------------------------------------------------------------------------------
    Operation                                    LogicalResourceId                            ResourceType                                                                 
    ----------------------------------------------------------------------------------------------------------------------------
    + Add                                        ApplicationInsightsMonitoring                AWS::ApplicationInsights::Application                                               
    + Add                                        ApplicationResourceGroup                     AWS::ResourceGroups::Group                   
    + Add                                        HelloWorldFunctionHelloWorldPermissionProd   AWS::Lambda::Permission                                                           
    + Add                                        HelloWorldFunctionRole                       AWS::IAM::Role                                                                     
    + Add                                        HelloWorldFunction                           AWS::Lambda::Function                                                               
    + Add                                        ServerlessRestApiDeployment47fc2d5f9d        AWS::ApiGateway::Deployment                                                        
    + Add                                        ServerlessRestApiProdStage                   AWS::ApiGateway::Stage                                                            
    + Add                                        ServerlessRestApi                            AWS::ApiGateway::RestApi                                                           
    -------------------------------------------------------------------------------------------------------------------------
    

  • [Optional] We can continuously synchronize local change to the cloud:

    # look at all changes
    sam sync --watch
    # look to code only updates
    sam sync --watch --code
    

    The sam sync command can also synchronize code changes to the cloud without updating the infrastructure. This code synchronization uses the service APIs and bypasses CloudFormation, allowing AWS SAM to update the code in seconds instead of minutes.

  • To clean up, we have two choices:

    aws cloudformation delete-stack --stack-name sam-app --region us-west-2
    # with sam
    sam delete
    
  • For building a CodePipeline using sam cli see next section.

The sam template

For the function section of the template, see the lambda reference.

SAM Pipelines

AWS SAM Pipelines makes it easier to create CI/CD pipelines.

aws codecommit create-reposiory --repository-name sam-app
# if needed install python library to access code commit
pip3 install git-remote-codecommit
  • Be sure to add .aws-sam and samconfig.yaml in .gitignore
echo -e "\n\n.aws-sam" >> .gitignore
echo -e "samconfig.toml" >> .gitignore
  • To commit change use remote URL like:
git remote add origin codecommit://sam-app
  • Create pipeline resources:

sam pipeline init --bootstrap command creates the AWS resources and permissions required to deploy application artifacts from our code repository into our AWS environments.

An Amazon S3 bucket is required to store application build artifacts during the deployment process.

Pipelines defines two stages, dev and production.

A .gitlab-ci.yml pipeline file is generated. The file contains a number of environment variables, which reference the details from AWS SAM pipeline bootstrap command.

The Cloud Formation template deploy two stacks and all the needed elements for the CI/CD in dev and prod envs. Going to Code Pipeline console to see the create pipeline.

To create a github and git action pipeline see this doc..

Canary deployments

Technique to slowly rolling out the changes to a small subset of users before rolling it out to the entire customer base.

AWS Lambda allows us to publish multiple versions of the same function. Each version has its own code and associated dependencies, as well as its own function settings.

Useful information

How to / assessment

Difference between SAM template and CloudFormation

SAM template is an abstraction above CloudFormation (Transform: AWS::Serverless-2016-10-31) but it reuses cloud formation templates for IaC in the "resources" section. It includes a "Global section" to define properties that are common to all your serverless functions and APIs. Product doc

How to create and validate a SAM template?

Use CLI:

sam init -h
sam init --runtime python3.9 --dependency-manager pip --app-template hello-world --name sam-app
sam validate
Invoke function locally with SAM CLI
sam local invoke -e ./event.json
Declare an API Gateway
RestAPI:
Type: AWS::Serverless::Api
Properties:
  StageName: Prod
  TracingEnabled: true
  Tags:
    Name: !Sub "${AWS::StackName}-API"
    Stack: !Sub "${AWS::StackName}" 
Run API Gateway locally with SAM CLI
sam local start-api --port 8080
Package and deploy an application with SAM CLI
sam build
sam deploy --guided
Familiar with security best practices and how to leverage SAM policies when working with other services

To invoke a Lambda, from external service, we need to define resource policies. For example a Step function calling a Lambda

 ProcessFormStateMachineExpressSync:
    Type: AWS::Serverless::StateMachine
     Properties:
        Policies:  
            - LambdaInvokePolicy:
                FunctionName: !Ref FunctionNameDeclareAbove

For the function to call a AWS service we need to define execution policy:

  OrderPublisher:
    Type: AWS::Serverless::Function
    Properties:
    FunctionName: OrderPublisher
    Handler: com.example.OrderPublisher::handleRequest
    CodeUri: target/sourceCode.zip
    Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref OrdersDDBTable
Build, package a Lambda Layer and/or Lambda Extension

Lambda layer helps to reuse dependencies. Layers are uploaded as zip within S3 bucket. Content is in the /opt of the EC2 runner. This is the same process as function.

aws lambda publish-layer-version --layer-name my-layer --description "My layer" \
--license-info "MIT" --zip-file fileb://layer.zip \
--compatible-runtimes python3.11 --compatible-architectures "arm64" "x86_64"

A layer can be shared with other AWS account via command like:

aws lambda add-layer-version-permission --layer-name my-layer --statement-id xaccount --action lambda:GetLayerVersion  --principal 111122223333 --version-number 1 
To use a Layer or Extension

Add the declaration in the function declaration in the sam template like:

   ...
    Layers:
    - !Ref libs
libs:
Type: AWS::Lambda::LayerVersion
Properties:
  LayerName: my-layer
  Description: Dependencies for the blank sample app.
  Content:
    S3Bucket: my-bucket-region-123456789012
    S3Key: layer.zip
  CompatibleRuntimes:
    - python3.11

Implement AWS Step Functions workflow using SAM

There are multiple sources of template in the serverless-patterns github repo. New project can be created by using one of the Multiple Step function choices.

Able to describe developer workflows

Start by creating a sam project, and then run locally to test the function code locally. Add unit test, package, and deploy to AWS account.

Familiar with AWS CDK and integration with SAM CLI

We can use SAM within a CDK project. In summary we do:

  • create CDK app: cdk init app --language python
  • Add lambda declaration in the CDK stack
  • Implement the lambda function
  • Test locally using SAM CLI and the Stack generated by CDK:
    cdk synth --no-staging
    sam local invoke MyFunction --no-event -t ./cdk.out/CdkSamExampleStack.template.json
    
  • Build using SAM
    sam build -t ./cdk.out/Stackname.template.json
    
  • Deploy via cdk deploy
How to use and deploy SAM Pipelines
sam pipeline init --bootstrap
How to perform canary release or other safe deployment with SAM

We can use canary deployment for different Lambda function version by using alias traffic shifting. Need to add the following within the function declaration in SAM template:

AutoPublishAlias: live
DeploymentPreference:
    Type: Canary10Percent5Minutes

Another type is the linear strategy: Linear10PercentEvery3Minutes. When using pipeline and CodeDeploy, it is possible to see the canary release in action and CodeDeploy can be configured to roll-back if there is an issue coming from CloudWatch alarm.

Deep understanding of debugging and testing strategies with SAM

AWS SAM Accelerate (sam sync --watch) enables developers to test their code quickly against production AWS services in the cloud and avoid sam deploy with CF deployment.

Use environment variables

Declaring an environment variables for a function, and to get the code from an external python script. The Function is also using a policy to be able to CRUD on the DynamoDB table.

UsersFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/api/users.lambda_handler
      Description: Handler for all users related operations
      Environment:
        Variables:
          USERS_TABLE: !Ref UsersTable
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref UsersTable
      Tags:
        Stack: !Sub "${AWS::StackName}"
Enabling X-Ray tracing

Add TracingEnabled: true properties

Add REST API definition for a function

Add the following events declaration in the Lambda function (which will be in the triggers view in Lambda console).

Events:
    GetUsersEvent:
      Type: Api
      Properties:
        Path: /users
        Method: get
        RestApiId: !Ref RestAPI
    PutUserEvent:
      Type: Api
      Properties:
        Path: /users
        Method: put
        RestApiId: !Ref RestAPI
    UpdateUserEvent:
      Type: Api
      Properties:
        Path: /users/{userid}
        Method: put
        RestApiId: !Ref RestAPI
    GetUserEvent:
      Type: Api
      Properties:
        Path: /users/{userid}
        Method: get
        RestApiId: !Ref RestAPI
    DeleteUserEvent:
      Type: Api
      Properties:
        Path: /users/{userid}
        Method: delete
        RestApiId: !Ref RestAPI

Add Cognito User Pool
UserPool:
Type: AWS::Cognito::UserPool
Properties: 
  UserPoolName: !Sub ${AWS::StackName}-UserPool
  AdminCreateUserConfig: 
    AllowAdminCreateUserOnly: false
  AutoVerifiedAttributes: 
    - email
  Schema: 
    - Name: name
      AttributeDataType: String
      Mutable: true
      Required: true
    - Name: email
      AttributeDataType: String
      Mutable: true
      Required: true
  UsernameAttributes: 
    - email
  UserPoolTags:
      Key: Name
      Value: !Sub ${AWS::StackName} User Pool
Specify a s3_bucket to upload code

add s3_bucket in sam


My examples