AWS SAM

Packaging and deploying the function

Now that we have reviewed our function and understand what it does, we are ready to package and deploy this into our AWS account. There are a few ways to accomplish this: (1) AWS Console, (2) AWS CloudFormation, or (3) AWS SAM. For these examples, we will use SAM.

The AWS Serverless Application Model (SAM) is an open-source framework for building serverless applications. It provides shorthand syntax to express functions, APIs, databases, and event source mappings. With just a few lines per resource, you can define the application you want and model it using YAML. During deployment, SAM transforms and expands the SAM syntax into AWS CloudFormation syntax, enabling you to build serverless applications faster.

Earlier in this workshop, we made sure that our Cloud9 environment was setup to use the latest version of the AWS SAM CLI. We will be running a few commands to build our Lambda source code and generate deployment artifacts. When complete, we will package these and store them in an Amazon S3 bucket and lastly deploy using AWS CloudFormation.

First, let’s begin by making sure we are working in the correct directory. Let’s go to our AWS Cloud9 instance and from the terminal switch to this modules directory.

cd ~/environment/aws-code-suite-for-atlassian-connect/lambda-functions/get-commit-id/

This directory should contain the following contents:

.
├── index.js
├── package.json
└── template.yml

The file named index.js is our Lambda function. Next, we have package.json which is our manifest for external dependencies used in our function. In this case, we are using require. Lastly, have our SAM template as template.yml. We also have a hidden file named .npmignore which follows the same format as .gitignore. This file will allow us to exclude certain contents within the source code directory that we do not wish to package along with our function. For example, our SAM templates. While this does not negatively impact the functionality of our code, leaving it is not exactly a best practice. We want to keep things as clean and organized as possible. You can open these files in Cloud9 and examine them at your leisure.

Before we start building, let’s create an S3 bucket to store our artifacts. We will do this using the AWS CLI from our Cloud9 instance by calling s3api.

aws s3api create-bucket --bucket my-bucket  --region us-west-2 --create-bucket-configuration LocationConstraint=us-west-2

Before running the command above, you will need to replace my-bucket with another name. Keep in mind that S3 bucket names are globally unique. If you do not choose a unique name then you will collide with an already existing bucket and the process will fail. For this workshop we are working in the us-west-2 region. However, if you opt to use a different region, also note that you will need to update this accordingly.

Upon successful creation, you will see the following response:

{
    "Location": "http://my-bucket.s3.amazonaws.com/"
}

Now that we have our S3 bucket created, we are ready to build & package our function. We will run two commands for this: sam build and sam package. The sam build command iterates through the functions in your application, looks for a manifest file (such as package.json) that contains the dependencies, and automatically creates deployment artifacts that you can deploy to Lambda using the sam package command. The sam package command is an alias for aws cloudformation package which packages the local artifacts (local paths) that your AWS CloudFormation template references. The command uploads local artifacts, such as source code for an AWS Lambda function to an S3 bucket.

sam build && sam package --output-template-file package.yml --s3-bucket my-bucket

Before running the command above, you will need to replace my-bucket with the name of the bucket you created.

Upon successful completion, you will see the following results:

2019-04-06 04:59:23 Building resource 'LambdaFunction'
2019-04-06 04:59:23 Running NodejsNpmBuilder:NpmPack
2019-04-06 04:59:24 Running NodejsNpmBuilder:CopyNpmrc
2019-04-06 04:59:24 Running NodejsNpmBuilder:CopySource
2019-04-06 04:59:24 Running NodejsNpmBuilder:NpmInstall
2019-04-06 04:59:27 Running NodejsNpmBuilder:CleanUpNpmrc

Build Succeeded

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

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Package: sam package --s3-bucket 
    
Uploading to 9bc2fd97e797a86cba9c7d60f02dd399  1315337 / 1315337.0  (100.00%)
Successfully packaged artifacts and wrote output template to file package.yml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /home/ec2-user/environment/test-sam/package.yml --stack-name 

This process will create a package.yml template based on the contents defined in template.yml but will also include the artifacts of your Lambda function packaged to your S3 bucket. These will be defined in the CodeUri parameter as an S3 URL. Now, we are ready to deploy our package. To do this, we will use sam deploy. sam deploy is an alias for aws cloudformation deploy and will deploy your AWS SAM application package through a specified AWS CloudFormation template. We will run the following:

sam deploy --template-file package.yml --stack-name <STACK_NAME> --capabilities CAPABILITY_IAM

Before running the command above, you will need to replace <STACK_NAME> with a name for your stack.

Upon successful completion, you will see the following results:

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - STACK_NAME