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.
Table of Contents
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:
- https://github.com/aws/serverless-application-model
- https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html
- https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-description-structure.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html
- https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html