I’ve found that AWS SAM is a simple way to deploy and manage an AWS Lambda function and it’s associated services. In this article, I’ll describe what I learned as I used it for a bare bones deploy of a simple Lambda function.
The AWS Serverless Application Model (SAM) is a framework for building serverless applications at AWS. It provides a simplified way to define the Amazon API Gateway APIs, AWS Lambda functions, and Amazon DynamoDB tables needed by your serverless application. For the purposes of this article, we’ll focus on using SAM solely for AWS Lambda.
With SAM, you can define your serverless application using a YAML or JSON template file. This template is used to specify all the details about your Lambda function, many of the AWS resources it uses (e.g. IAM Roles, Cloudwatch Log Groups, EventBridge triggers, etc.), and the information needed to deploy it to AWS.
SAM also provides a set of command-line tools for packaging, deploying, and managing your serverless applications. These tools simplify the process of deploying your application, managing your AWS resources, and handling updates and rollbacks. GitHub has integrated SAM CLI into GitHub Actions which makes setting up your CI/CD workflows really simple.
Of course, you don’t NEED to use SAM to deploy or manage a Lambda function at AWS. You can create everything I’m about to show you using the AWS Management Console. SAM is probably overkill for the silly little Lambda function we’ll be working with today, but as you start to create more complex Lambdas, using the console is going to become an increasingly bad idea. Here are a few reasons why:
- You’re (presumably) a human being. Human beings make mistakes. If you’re defining your Lambda manually using the console, you’re probably going to forget some key steps somewhere along the line.
- If you want to create more than a single Lambda function, you have to do all of the (mostly) same work for each one. Sure, each Lambda function may have different requirements and needed resources, but there are a number of common steps that need to be performed every time.
- If you’re like me, you’re just experimenting and don’t want to be spending a ton of money on this little experiment. If you set up everything manually, you have to tear it all down manually. Don’t forget to remove anything though or you may end up with a surprise AWS bill at the end of the month. ( HINT: if you’re using SAM to deploy a Lambda, you’ll have an S3 cost if nothing else. Granted, it’ll probably be small, but it will be > $0. So don’t forget to sam delete.)
Now that you have a vague idea of what SAM is and a few good reasons to use it, let’s dive into the details. First I need to spell out a few prerequisites (see the embedded links, or the resource links at the end of the article for help with some of these):
- Fork my GitHub repository (medium-simple-java-lambda) and clone it to your workstation
- Create AWS account and an IAM user that has an access key created
- Install and configure AWS CLI and SAM CLI on your workstation
- Configure AWS credentials in your terminal session (i.e. set environment variables)
- Create GitHub repository secrets for GitHub Actions to work (see .github/workflows/sam-deploy.yml in the repository for details)
sam build --template-file sam.template.yaml
sam deploy \
--template-file .aws-sam/build/template.yaml \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--stack-name simple-java-lambda \
--s3-bucket <bucket name> \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--region <region name e.g. us-east-1>
SAM is able to detect that this project is set up to build with Gradle, and will run the Gradle build when you execute the sam build command. The sam deploy command will upload the built artifact to S3 into the bucket specified by --s3-bucket which must already exist. Take note that these two commands each take a different template file as a parameter. The sam build command takes the SAM template file and creates a full CloudFormation template which is what the sam deploy command uses. Looking at the command output, we see that SAM deploys the Lambda as part of a full CloudFormation application stack which, not surprisingly, has the name specified by the --stack-name parameter.
CloudFormation events from stack operations (refresh every 0.5 seconds)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::IAM::Role SimpleJavaFunctionRole -
CREATE_IN_PROGRESS AWS::IAM::Role SimpleJavaFunctionRole Resource creation Initiated
CREATE_COMPLETE AWS::IAM::Role SimpleJavaFunctionRole -
CREATE_IN_PROGRESS AWS::Lambda::Function SimpleJavaFunction -
CREATE_IN_PROGRESS AWS::Lambda::Function SimpleJavaFunction Resource creation Initiated
CREATE_COMPLETE AWS::Lambda::Function SimpleJavaFunction -
CREATE_COMPLETE AWS::CloudFormation::Stack simple-java-lambda -
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - simple-java-lambda in us-east-1
For me, this is the one downside of using SAM. CloudFormation stacks can take forever to create, update, and delete. But I suppose it’s a decent tradeoff for the simplicity you can achieve. The other thing I’ve learned about CloudFormation stacks is that it’s possible to get them into an invalid state where the whole stack must be deleted in the AWS CloudFormation console because the SAM CLI will not function properly.
Unless you went off script and defined one or more triggers for your shiny new Lambda function, you’ll have to log in to the AWS Lambda console and use the built-in test functionality to see that it returns the string “Hello World!”
To delete your Lambda and ensure that you’re not going to incur any sneaky AWS charges, you can run the sam delete command as shown below. Notice that the SAM CLI deletes the S3 objects that were created earlier as well as the CloudFormation stack itself.
sam delete --stack-name simple-java-lambda
Are you sure you want to delete the stack simple-java-lambda in the region us-east-1? [y/N]: y
Do you want to delete the template file 389d4cb200cca272c3f9f211fce1afc5.template in S3? [y/N]: y
- Deleting S3 object with key 481802c173d3f3ef734bf763ade4be88
- Deleting S3 object with key 389d4cb200cca272c3f9f211fce1afc5.template
- Deleting Cloudformation stack simple-java-lambda
Deleted successfully
Now that you’ve seen the SAM CLI commands used to build, deploy, and delete a Lambda, Let me show you how I set up GitHub Actions workflows so that I never have to actually type those commands. First the build/deploy workflow:
name: SAM Build/Deploy
on:
push:
branches:
- main
paths:
- 'sam.template.yaml'
- 'src/main/**'
- 'build.gradle'
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: 8
distribution: 'adopt'
- name: Set Up Python
uses: actions/setup-python@v2
- name: Set up AWS SAM
uses: aws-actions/setup-sam@v1
- name: Set up AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Run SAM Build
run: sam build -t sam.template.yaml
- name: Run SAM Deploy
run: |
sam deploy \
--template-file .aws-sam/build/template.yaml \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--stack-name simple-java-lambda \
--s3-bucket ${{ secrets.AWS_S3_BUCKET }} \
--capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \
--region ${{ secrets.AWS_REGION }}
You can see that after some Java and Python setup, we’re leveraging the aws-actions/setup-sam@v1 step so that GitHub can run the sam build and sam deploy commands as the last steps of the workflow. There’s also a delete workflow that runs sam delete instead of sam deploy. Checkout the .github/workflows folder in the GitHub repository.
To be sure, AWS SAM is capable of much more complicated tasks than what I’ve presented here. This is essentially the bare minimum of what you can specify to deploy a serverless application at AWS. Check out the AWS Serverless Application Model documentation for all the details you didn’t get here.
Was this article helpful? Did you learn anything? Did I get it all wrong? Did you find it a waste of time? I’d love to hear any feedback you have and/or help you get past any stumbling blocks you may have encountered along the way!
Resources:
- Creating an AWS account
- Creating an IAM user
- Creating an access key for an IAM user
- Install AWS CLI
- Install SAM CLI
Top comments (0)