eolas/DevOps/AWS/SAM/SAM.md

300 lines
7.2 KiB
Markdown
Raw Normal View History

2023-04-14 20:19:01 +01:00
---
categories:
- DevOps
- Backend
tags: [AWS]
---
# AWS SAM
SAM stands for **serverless application model**. It is a framework developed by
AWS to simplify the process of building, deploying and managing serverless
applications. It provides a concise syntax for defining the components of a
serverless application, such as
[Lambda functions](/DevOps/AWS/AWS_Lambda/Lambda_programming_model.md),
[API gateway](/DevOps/AWS/AWS_API_Gateway.md) and database tables.
The SAM infrastructure is defined in a YAML file which is then deployed to AWS.
SAM syntax gets transformed into CloudFormation during the deployment process.
(CloudFormation is a broader and more robust AWS tool for large, highly
scaleable infrastructures).
2023-04-14 20:19:01 +01:00
## Key features of SAM
- Single deployment configuration
- Integration with development tools
- Local testing and debugging
- Built on AWS CloudFormation
## Main technologies required
### Docker
Whilst SAM can be used to create a deployable file for AWS it can also be run as
a container for local development with Docker.
2023-04-14 20:19:01 +01:00
### AWS CLI
This is installed using Python and allows you to interact directly with AWS via
the command-line.
2023-04-14 20:19:01 +01:00
### AWS SAM CLI
See
[https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
2023-04-14 20:19:01 +01:00
## Setting up credentials for the AWS CLI
You require an access key for the given
[IAM user](/DevOps/AWS/AWS_User_management_and_roles.md#iam). You should create
an IAM account specific to the project with bounded permissions.
2023-04-21 07:34:17 +01:00
2023-04-14 20:19:01 +01:00
```
aws configure
AWS Access Key ID [None]: AK*******
AWS Secret Access Key [None]: ukp******
Default region name [None]:
Default output format [None]:
```
This information can be found in the Security Credentials section of the given
[IAM](/DevOps/AWS/AWS_User_management_and_roles.md#iam) user:
2023-04-14 20:19:01 +01:00
![](/_img/access-key-aws.png)
### Switching between credentials
You should set up a different IAM user for each project.
You can do this with:
```sh
aws configure --profile <profile-name>
```
This will then ask you to add the credentials for the user.
You can switch between different credentials for the user as follows:
```sh
AWS_PROFILE=<profile-name> sam build
```
2023-04-14 20:19:01 +01:00
## Starting a SAM project
First create a directory for your project which will serve as the repository:
```sh
mkdir aws-sam-learning
cd aws-sam-learning
```
Then we can use the `sam` cli to bootstrap the project:
```sh
sam init --runtime nodejs16.x
```
We can just click through and accept the basic HelloWorld Lambda.
This will create the Lambda as well as an API Gateway trigger URL.
### `template.yaml`
This is autogenerated and details the main constituents of the project. There
are lots of fields but the most important are the following:
2023-04-14 20:19:01 +01:00
```yaml
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: app.lambdaHandler
Runtime: nodejs16.x
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
```
This details the location of the
[handler function](/DevOps/AWS/AWS_Lambda/Lambda_handler_function.md) which is
contained at the path `hello-world/app.js`:
2023-04-14 20:19:01 +01:00
```js
exports.lambdaHandler = async (event, context) => {
try {
// const ret = await axios(url);
response = {
statusCode: 200,
body: JSON.stringify({
message: "hello world",
// location: ret.data.trim()
}),
};
} catch (err) {
console.log(err);
return err;
}
return response;
};
```
It also lists the `get` event that we can use to call API Gateway and trigger
the Lambda.
2023-04-14 20:19:01 +01:00
The full template is below:
![](/_img/sam-template-yaml.png)
2023-04-16 19:16:14 +01:00
## Adding our own code
We will create our own function and API Gateway trigger.
We will place our function after the existing `HelloWorldFunction`
```yaml
ClockFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: clock/
Handler: handler.clock
Runtime: nodejs16.x
Events:
ClockApi:
Type: Api
Properties:
Path: /clock
Method: get
```
We can test the syntax with:
```sh
sam validate
```
Just like with `HelloWorld`, we will create a directory for this function:
`clock` and we will initialise it as an `npm` project.
2023-04-16 19:16:14 +01:00
```sh
mkdir clock
cd clock
npm init
```
We will use `handler.js` as our root, handler function.
We have said in the template file that our `Handler: handler.clock`, therefore
the main function in the `handler` module should be `clock`:
2023-04-16 19:16:14 +01:00
```js
const moment = require("moment");
exports.clock = async (event) => {
console.log("Clock function run");
const message = moment().format();
const response = {
statusCode: 200,
body: JSON.stringify(message),
};
return response;
};
```
2023-04-21 07:34:17 +01:00
The directory structure is as follows:
![](/_img/sam-directory.png)
When we call the API Gateway path `/clock` with `GET`, our function will be
triggered.
2023-04-21 07:34:17 +01:00
## Deploying the project
We will now deploy our project to AWS from the local environment.
The process is as follows:
1. Build
2. Package
3. Deploy
### Build
We need to install the runtime dependencies for the function. We do this by
running `sam build`. This ignores test files and development dependencies and
installs the project dependencies and source files to a temporary subdirectory.
2023-04-21 07:34:17 +01:00
![](/_img/sam-build.png)
The build directory is `.aws-sam/build/`. There will be a subdirectory for each
of our files.
2023-04-21 07:34:17 +01:00
### Package
As noted, CloudFront handles the deployment of the application. It can only
receive one file as an input. The packaging process consists in creating that
single file.
2023-04-21 07:34:17 +01:00
The packaging proces will first archive all of the project artefacts into a zip
file and then upload that to [S3](/DevOps/AWS/AWS_S3.md). A reference to this S3
entity is then provided to CloudFormation.
2023-04-21 07:34:17 +01:00
![](/_img/s3-package-again.svg)
The command is as follows:
```sh
sam package
--template-file template.yaml
--output-template-file pkg.yml
--region eu-west-1
```
This will automatically create a hashed bucket name for you in S3 (I have tried
to add my own naming but it doesn't comply.)
### Local development with Docker
In order to work with your application locally without actually sending requests
to AWS and using credit, you can run a local instance.
See
[Local AWS Development with SAM](/DevOps/AWS/SAM/Local_AWS_development_with_SAM.md).
### Deploy
Once you have packaged the app you can deploy with `sam deploy --guided`. This
will talk you through the defaults and will deploy the package to
CloudFormation. In CloudFormation each individual project is called a **stack**.
If we then go to Cloud Formation we will see the deployed application.
![](/_img/cloud-formation-stack.png)
## Call the endpoint
If we now go to the Lambda console, we will see our function listed, and the API
Gateway endpoint under `triggers`:
![](/_img/gateway-trigger.png)
We can then call this from Postman to check everything is working as it should:
![](/_img/postman-aws-output.png)
## Clean up and erase the stack
We can delete the stack and remove all the resources we have created with a
single CLI method:
```sh
aws cloudformation delete-stack --stack-name <name> --region <region>
```