AWS SAM: Tutorial

This tutorial will show you how to use AWS SAM. You will see how to initialize a sample Python project, build it and deploy your code as an AWS Lambda function.

As a side note - you are not limited to Python. The reason is that AWS SAM can use any runtime supported by AWS Lambda. Also, SAM is an extension of AWS CloudFormation. So, you get all the benefits and capabilities of AWS CloudFormation.

What is AWS CloudFormation?

AWS CloudFormation is an Infrastructure as Code (IaC) service. With AWS CloudFormation, you can spend less time managing resources and more time focusing on your applications. All you need to do is create a template that describes all the AWS resources. Then, CloudFormation takes care of provisioning and configuring those resources for you.

What is AWS SAM?

AWS SAM stands for Serverless Application Model. And, it is an open-source, Infrastructure as Code (IaC) framework. So, you can use AWS SAM for building serverless applications such as AWS-: Lambda, Fargate, API Gateway, SNS, SQS, S3, DynamoDB, and more.

To use SAM, you need:

  • A Liberal set of permissions to apply and deploy changes. For example, the AWS SAM CLI makes calls to Amazon S3 and AWS CloudFormation. Your user will thus need permissions to use these services.
  • A SAM template that includes all the definitions for your serverless infrastructure. SAM templates use a shorthand syntax. This makes the template simple and clean. The key point here is shorthand syntax.
  • To have the AWS SAM command-line interface (CLI) installed on your computer. It requires you to set AWS credentials so that it can make calls to AWS services on your behalf. The SAM CLI provides tools for the developer to build and deploy applications.

What is AWS Lambda?

Lambda is a serverless, high-availability compute service. So, it allows you to run code without provisioning or managing servers. Of course, with serverless, you don't need to be concerned about infrastructure, administration, system maintenance, capacity provisioning, automatic scaling, and logging.

Lambda Supported runtimes

Benefits of AWS SAM include:

  • Node.js
  • Python 
  • Ruby
  • Java 
  • Go 
  • .NET Core

SAM Benefits

Benefits of AWS SAM include:

  • Organize related components and operate a single SAM template.
  • Use the CLI to build, test, debug and deploy SAM applications. You can even delete your SAM stack.
  • Leverage the deep integration with many IDEs. These include AWS Cloud9, Visual Studio Code and more. You can also use it to build with AWS CodeBuild. Deploying is made easy with AWS CodeDeploy and Jenkins.

Install AWS SAM CLI

Use these steps to install the AWS SAM CLI on your Linux platform. Or, you can read the official AWS SAM CLI install guide for the platforms.

First, download the CLI using:

wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

Next, unzip the files into a "sam-installation" folder:

unzip aws-sam-cli-linux-x86_64.zip -d sam-installation

Finally, install the AWS SAM CLI:

sudo ./sam-installation/install

Let's get started!

AWS SAM will allow you to set up a sample application, build it and then deploy the application to AWS. So first, let's set up and deploy a sample application, then let's analyze what AWS SAM did.

Setup a sample application

Next, you can create a sample application using the following command:

sam init

You must then follow the screen prompts to set up an AWS Quick Start Template. Select the Zip package type, the "python3.9" runtime, and the Hello World Example.

Below is an example of the various screen prompts you will see:


	SAM CLI now collects telemetry to better understand customer needs.

	You can OPT OUT and disable telemetry collection by setting the
	environment variable SAM_CLI_TELEMETRY=0 in your shell.
	Thanks for your help!

	Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1
What package type would you like to use?
	1 - Zip (artifact is a zip uploaded to S3)	
	2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

Which runtime would you like to use?
	1 - nodejs14.x
	2 - python3.9
	3 - ruby2.7
	4 - go1.x
	5 - java11
	6 - dotnetcore3.1
	7 - nodejs12.x
	8 - nodejs10.x
	9 - python3.8
	10 - python3.7
	11 - python3.6
	12 - python2.7
	13 - ruby2.5
	14 - java8.al2
	15 - java8
	16 - dotnetcore2.1
Runtime: 2

Project name [sam-app]: simple-python-app

Cloning from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
	1 - Hello World Example
	2 - EventBridge Hello World
	3 - EventBridge App from scratch (100+ Event Schemas)
	4 - Step Functions Sample App (Stock Trader)
	5 - Elastic File System Sample App
Template selection: 1

    -----------------------
    Generating application:
    -----------------------
    Name: simple-python-app
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .

    Next application steps can be found in the README file at ./simple-python-app/README.md
    

    Commands you can use next
    =========================
    [*] Create pipeline: cd simple-python-app && sam pipeline init --bootstrap

Build the serverless application

Next, enter the folder created by SAM Init. Then, as per the example, enter the "simple-python-app" folder.

Then, run the SAM build command:

sam build

This output will produce something like this:

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided

SAM has now built the source and placed it under the ".aws-sam/build" folder. Additionally, AWS SAM included all the dependencies as specified in the requirements file. Finally, the build folder will be zipped and uploaded to Lambda.

Deploy the Lambda application

Finally, you can deploy our serverless application to AWS using the following command:

sam deploy --guided

SAM deploy will guide you through some screen prompts. For example:

	Setting default arguments for 'sam deploy'
	=========================================
	Stack Name [hello-world]: 
	AWS Region [ap-southeast-2]: 
	#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
	Confirm changes before deploy [Y/n]: y
	#SAM needs permission to be able to create roles to connect to the resources in your template
	Allow SAM CLI IAM role creation [Y/n]: y
	#Preserves the state of previously provisioned resources when an operation fails
	Disable rollback [Y/n]: y
	HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
	Save arguments to configuration file [Y/n]: y
	SAM configuration file [samconfig.toml]: 
	SAM configuration environment [default]: 

First, you must accept the defaults or select "y". Then, for the prompt "HelloWorldFunction may not have authorization defined. Is this okay? [y/N]", enter "y". This question means that you are deploying an API Gateway API without authorization to the public internet.

This output will produce something like this:

CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                                              
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                                                        
Description         Implicit IAM Role created for Hello World function                                                                                                               
Value               arn:aws:iam::123414467088:role/hello-world-HelloWorldFunctionRole-1BI5GLQVALG3D                                                                                  

Key                 HelloWorldApi                                                                                                                                                    
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                                                 
Value               https://xxxxx.execute-api.ap-southeast-2.amazonaws.com/Prod/hello/                                                                                          

Key                 HelloWorldFunction                                                                                                                                               
Description         Hello World Lambda Function ARN                                                                                                                                  
Value               arn:aws:lambda:ap-southeast-2:123414467088:function:hello-world-HelloWorldFunction-1H5PD5LsznSy                                                                  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - hello-world in ap-southeast-2

Next, note the value specifying the API Gateway endpoint URL for our deployment:

https://xxxxx.execute-api.ap-southeast-2.amazonaws.com/Prod/hello/   

Finally, you can CURL the URL to get the result:

curl https://xxxxx.execute-api.ap-southeast-2.amazonaws.com/Prod/hello/
{"message": "hello world"}

Analyzing the output

Next, let's analyze the output from SAM Init and SAM Build.

SAM Init

The "sam init" command created the following output when you ran it:

.
โ”œโ”€โ”€ events
โ”‚ย ย  โ””โ”€โ”€ event.json
โ”œโ”€โ”€ hello_world
โ”‚ย ย  โ”œโ”€โ”€ app.py
โ”‚ย ย  โ”œโ”€โ”€ __init__.py
โ”‚ย ย  โ””โ”€โ”€ requirements.txt
โ”œโ”€โ”€ __init__.py
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ samconfig.toml
โ”œโ”€โ”€ template.yaml
โ””โ”€โ”€ tests
    โ”œโ”€โ”€ __init__.py
    โ”œโ”€โ”€ integration
    โ”‚ย ย  โ”œโ”€โ”€ __init__.py
    โ”‚ย ย  โ””โ”€โ”€ test_api_gateway.py
    โ”œโ”€โ”€ requirements.txt
    โ””โ”€โ”€ unit
        โ”œโ”€โ”€ __init__.py
        โ””โ”€โ”€ test_handler.py

The following files are the most important ones to note:

  • app.py - Contains the AWS Lambda handler code.
  • requirements.txt - Contains all the Python dependencies used during the SAM build.
  • template.yaml - Contains the AWS SAM template defining your application's AWS resources.

SAM Build

The "sam build" command created the following output when you ran it:

 .aws-sam/
   โ””โ”€โ”€ build/
       โ”œโ”€โ”€ HelloWorldFunction/
       โ””โ”€โ”€ template.yaml

This folder contains your app.py file. It also contains third-party dependencies that your application uses. AWS SAM will zip the contents of this folder as a package during the deployment.

AWS SAM template anatomy

The following is the output of the template file:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  simple-python-app

  Sample SAM Template for simple-python-app

Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api 
          Properties:
            Path: /hello
            Method: get

Outputs:
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

You can simplify the template file to the following basic structure:

Transform: AWS::Serverless-2016-10-31

Globals:
  set of globals

Description:
  String

Metadata:
  template metadata

Parameters:
  set of parameters

Mappings:
  set of mappings

Conditions:
  set of conditions

Resources:
  set of resources

Outputs:
  set of outputs

You will notice that your template file does not contain all the mentioned sections. The reason for this is that some of the missing sections are optional.

Let's discuss the template sections in more detail:

Transform (required)

First, the transform section specifies macros used to process your template. You must include this section with a value of "AWS::Serverless-2016-10-31". Other transformations are possible, but it is only relevant to AWS CloudFormation.

Globals (optional)

Then, you have the globals section. This section is unique to AWS SAM. It contains standard information for all your serverless functions, APIs, and simple tables. Thus, it helps you avoid duplicating information for every resource.

For example, the code below will ensure that all functions use the python3 runtime. It also sets a default timeout:

Globals:
  Function:
    Runtime: python3
    Timeout: 180
    Handler: index.handler
    Environment:
      Variables:
        TABLE_NAME: data-table

Description (optional)

The description is a string that describes the template in the form of comments.

For example:

Description: >
  Here are some
  details about
  the template.

Metadata (optional)

The metadata section includes objects that provide extra information about the template. In fact, as an example, this is where AWS CloudFormation adds information used by the GUI interface. The information usually informs the GUI how to position the objects on the screen and so forth.

For example:

Metadata:
  Instances:
    Description: "Information about the instances"
  Databases: 
    Description: "Information about the databases"

Parameters (optional)

Next, the parameters section contains values to pass to your template. You can also override values using the: "--parameter-overrides" parameter when deploying.

For example:

Parameters:
  InstanceTypeParameter:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - m1.small
      - m1.large
    Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro.

Mappings (optional)

Think of mappings as a lookup table. You can use it to match a key to a corresponding value. For example, the Fn::FindInMap function does the lookup for you in the Resources and Outputs sections.

The mappings example below is quite helpful as it allows you to specify a different EC2 instance AMI ID for each region. This type of lookup is needed since AMI IDs are not always the same across regions.

For example:

Mappings: 
  RegionMap: 
    us-east-1: 
      "HVM64": "ami-0ff8a91507f77f867"
    us-west-1: 
      "HVM64": "ami-0bdb828fd58c52235"
    eu-west-1: 
      "HVM64": "ami-047bb4163c506cd98"
    ap-southeast-1: 
      "HVM64": "ami-08569b978cc4dfa10"
    ap-northeast-1: 
      "HVM64": "ami-06cd52961ce9f0d85"

Finally, the example below shows how you can use the FindInMap function. As you can see below, the resource below looks up a value in the region map section.

AWSTemplateFormatVersion: "2010-09-09"
Mappings: 
  RegionMap: 
    us-east-1:
      HVM64: ami-0ff8a91507f77f867
      HVMG2: ami-0a584ac55a7631c0c
    us-west-1:
      HVM64: ami-0bdb828fd58c52235
      HVMG2: ami-066ee5fd4a9ef77f1
    eu-west-1:
      HVM64: ami-047bb4163c506cd98
      HVMG2: ami-0a7c483d527806435
    ap-northeast-1:
      HVM64: ami-06cd52961ce9f0d85
      HVMG2: ami-053cdd503598e4a9d
    ap-southeast-1:
      HVM64: ami-08569b978cc4dfa10
      HVMG2: ami-0be9df32ae9f92309
Resources: 
  myEC2Instance: 
    Type: "AWS::EC2::Instance"
    Properties: 
      ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", HVM64]
      InstanceType: m1.small

Conditions (optional)

The conditions section allows you to create a resource conditionally. This is useful when you want to perform actions on specific resources. Also, you could use conditions to avoid performing actions, such a recreating data storage.

For example:

Conditions:
  CreateProdResources: !Equals 
    - !Ref EnvType
    - prod

Finally, the example below shows how to use a condition. For example, the CreateProdResources condition will only deploy EC2Instance if it's true.

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EnvType:
    Description: Environment type.
    Default: test
    Type: String
    AllowedValues:
      - prod
      - test
    ConstraintDescription: must specify prod or test.
Conditions:
  CreateProdResources: !Equals 
    - !Ref EnvType
    - prod
Resources:
  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: ami-0ff8a91507f77f867
  MountPoint:
    Type: 'AWS::EC2::VolumeAttachment'
    Condition: CreateProdResources
    Properties:
      InstanceId: !Ref EC2Instance
      VolumeId: !Ref NewVolume
      Device: /dev/sdh
  NewVolume:
    Type: 'AWS::EC2::Volume'
    Condition: CreateProdResources
    Properties:
      Size: 100
      AvailabilityZone: !GetAtt 
        - EC2Instance
        - AvailabilityZone

Resources (optional)

The resources section contains information about the resources you want to deploy. The resource definition changes according to the resource type. Read the AWS resource and property types reference for more information.

Next, As per the example in this AWS SAM tutorial:

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api 
          Properties:
            Path: /hello
            Method: get

Outputs (optional)

Then finally, there is the values section that specifies values that AWS SAM must return.

For example:

Outputs:
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

Delete your stack

Remember to delete your stack when you complete the AWS SAM tutorial.

You can do this with the following command:

sam delete

Result:

Are you sure you want to delete the stack hello-world in the region ap-southeast-2 ? [y/N]: y
	Are you sure you want to delete the folder hello-world in S3 which contains the artifacts? [y/N]: y
	- Deleting S3 object with key hello-world/50a6c52901d59bd40e0b2bfb3bf9e40d
	- Deleting S3 object with key hello-world/c3ce3e106671c4da35cfb4e4c9cfa4dc.template
	- Deleting Cloudformation stack hello-world

Deleted successfully

Wrapping up the AWS SAM tutorial

This tutorial showed you how to use AWS SAM. First, you initialized a sample Python project. You then built it and finally deployed it as an AWS Lambda function. Next, you should remember to delete your stack so that you do not incur costs. Also, remember that your Lambda function is not secure, and anyone can access it.

You may also be interested in

Sources:



About the Authors

Anto's editorial team loves the cloud as much as you! Each member of Anto's editorial team is a Cloud expert in their own right. Anto Online takes great pride in helping fellow Cloud enthusiasts. Let us know if you have an excellent idea for the next topic! Contact Anto Online if you want to contribute.

Support the Cause

Support Anto Online and buy us a coffee. Anything is possible with coffee and code.

Buy me a coffee



Leave a Reply

Your email address will not be published. Required fields are marked *