Serverless Components A
Overview
This project is a prototype of a new concept Serverless has been exploring called "components". Our aim is to introduce highly configurable and composable pieces that allow for multi-cloud & third party resource use cases.
Components are capable of provisioning infrastructure while including both application logic AND lifecycle management. They have a focus on serverless/cloud resources and they also greatly enable reuse, sharing and simplicity.
Table of contents
Getting started
Please make sure that you've installed Node.js with a recent npm version.
Note: If not explicitly provided, the prototype will use the default
AWS profile on your machine.
- Setup
npm install --global @serverless/serverless-components-a
- Clone this repository
- (Optionally) set your AWS credentials via env variables
export AWS_ACCESS_KEY_ID=my_access_key_id
export AWS_SECRET_ACCESS_KEY=my_secret_access_key
- Configuring
cd src/examples/github-webhook
- Open up the example in your favorite editor (e.g.
atom .
) - Update the
repository
andgithubToken
parameters with your values
- Deployment
proto deploy
- Testing
proto test
- Updating
- Change some parameters (e.g. the
event
orhttpPath
property) proto deploy
- Change some parameters (e.g. the
- Removal
proto remove
Concepts
Components
Components are a way to share and re-use pre-built functionality throughout different projects. A project can contain one or more components. Furthermore components can be wrapped and composed together to extend functionality.
Components take parameters as their input and compute outputs when run. One example use-case for an output is the .state.json
file which is created for every project and holds state information for every single component used in the project.
Components can be defined in a serverless.yml
file like this:
# serverless.yml
components:
myDynamoDbTable:
type: pmuens:aws-dynamodb-table@0.1.0
parameters:
attributeDefinitions:
- attributeName: id
attributeType: S
keySchema:
- attributeName: id
keyType: HASH
provisionedThroughput:
readCapacityUnits: 1
writeCapacityUnits: 1
tableName: my-dynamodb-table
In this example we're using the aws-dynamodb-table
component at version 0.1.0
which was authored by pmuens
. We pass in different parameters to configure the infrastructure this component will setup. In our case we set the attributeDefinitions
, the keySchame
, the provisionedThroughput
as well as the tableName
.
Most components ship with sane defaults so that it's not necessary to provide all parameters.
A components underpinning functionality is provided by a function.
In this PoC implementation a function is equal to a component. This makes it possible to use components in a declarative way as well as through code.
The function which expresses the components functionality above looks like this:
// index.js
module.exports = (context, params, options) => {
// destructuring the component parameters
const {
attributeDefinitions,
keySchema,
provisionedThroughput,
tableName
} = params
// ...snip...
async function createTable(tableName) {
return sdk('DynamoDB', 'createTable', {
TableName: tableName
})
}
async function deleteTable(tableName) {
return sdk('DynamoDB', 'deleteTable', {
TableName: tableName
})
}
// ...snip...
// logic to setup the infrastructure
async function deploy() {
await createTable(params.tableName)
}
// logic to tear down the infrastructure
async function remove() {
await deleteTable(params.tableName)
}
// these functions are exposed and accessible through the CLI
return {
deploy,
remove
}
}
The components parameters and CLI options are passed in to the function and are accessible via params
and options
. The returned functions at the bottom of the function are exposed and accessible via CLI commands.
Treating a component and the corresponding function equally makes it possible to pull in pre-written components in code and therefore re-use them to write parent components which orchestrate different child components. Take a look at the code for the github-webhook-receiver
component to see how existing components can be re-used in code.
Serverless Registry
The "Serverless Registry" is a core part in this implementation since it makes it possible to discover, publish and share existing components.
The registry is not only constrained to serve components. Since components are functions it's possible to wrap existing business logic into functions and publish them to the registry as well.
While implementing this prototype we've created two util functions / components called util-aws-request
and util-zipper
. Both are used in various components to steamline AWS SDK calls and .zip
archive creation.
Looking into the future it could be possible to serve functions which are written in different languages through the registry.
Docs
aws-api-gateway-lambda-endpoint
Creates / Removes an API endpoint which is exposed via AWS API Gateway and connects directly to an AWS Lambda function.
Parameters
Name | Description | Type |
---|---|---|
path |
The HTTP path | String |
method |
The HTTP method | String |
lambdaArn |
The AWS Lambda functions arn which should be connected via the API Gateway |
String |
roleArn |
The role arn which is used to give the API Gateway the permission to call the AWS Lambda function |
String |
Commands
proto deploy
proto remove
Example
type: pmuens:aws-api-gateway-lambda-endpoint@0.1.0
parameters:
path: my-path
method: GET
lambdaArn: arn:aws:lambda:us-east-1:XXXXX:function:some-lambda-function
roleArn: arn:aws:iam::XXXXX:role/some-api-gateway-role
aws-dynamodb-table
Creates / Removes an AWS DynamoDB table.
Parameters
Name | Description | Type |
---|---|---|
attributeDefinitions |
The tables attribute definitions | Array |
keySchema |
The tables key schema | Array |
provisionedThroughput |
The tables provisioned throughput | Object |
tableName |
The tables name | String |
Commands
proto deploy
proto remove
Example
type: pmuens:aws-dynamodb-table@0.1.0
parameters:
attributeDefinitions:
- attributeName: id
attributeType: S
keySchema:
- attributeName: id
keyType: HASH
provisionedThroughput:
readCapacityUnits: 1
writeCapacityUnits: 1
tableName: my-dynamodb-table
aws-iam-role
Creates / Removes an AWS IAM role.
Parameters
Name | Description | Type |
---|---|---|
roleName |
The name for the IAM role | String |
service |
The service the role targets | String |
policyArn |
The policy arn this role should assume |
String |
Commands
proto deploy
proto remove
Example
type: pmuens:aws-iam-role@0.1.0
parameters:
roleName: my-ec2-role
service: ec2.amazonaws.com
policyArn: arn:aws:iam::aws:policy/AdministratorAccess
aws-lambda-function
Creates / Removes an AWS Lambda function.
Parameters
Name | Description | Type |
---|---|---|
codeDirPath |
Path to the location where the functions code is located | String |
functionName |
The functions name | String |
handler |
The functions handler | String |
roleArn |
The role arn the lambda should use |
String |
runtime |
The functions runtime | String |
environment |
The functions environment variables | Object |
memorySize |
The functions memory size | Number |
timeout |
The functions timeout | Number |
Commands
proto deploy
proto remove
Example
type: pmuens:aws-lambda-function@0.1.0
parameters:
codeDirPath: ./code
functionName: my-lambda-function
handler: index.handler
roleArn: arn:aws:iam::XXXXX:role/some-lambda-role
runtime: nodejs6.10
environment:
variables:
foo: bar
memorySize: 512
timeout: 60
github-webhook-receiver
Creates / Removes / Tests a GitHub Webhook. Uses AWS as the cloud provider.
AWS resource names created by this component:
Resource | Name |
---|---|
Lambda function name | ${name}-lambda-function |
DynamoDB table name | ${name}-logging-table |
Lambda role name | ${name}-role-lambda |
API Gateway role name | ${name}-role-api-gateway |
Parameters
Name | Description | Type |
---|---|---|
name |
The webhooks name (Note: this name will be used as a prefix for all AWS resources (see above)) | String |
codeDirPath |
Path to the location where the functions code is located | String |
httpPath |
The HTTP path | String |
repository |
Name of the GitHub repository the Webhook should be created for | String |
event |
The Webhooks event | String |
githubToken |
The GitHub token which is used to create the Webhook on your behalf | String |
Commands
proto deploy
proto remove
proto test
Example
type: pmuens:github-webhook-receiver@0.1.0
parameters:
name: my-github-webhook
codeDirPath: ./code
httpPath: webhook
repository: jdoe/some-repo
event: issue_comment
githubToken: s0me3g1thu8t0k3n
util-aws-request
Helper which wraps the AWS SDK and provides some convenience functions.
Parameters
- None
Commands
- None
Example
const request = loadFunction(context, 'pmuens:util-aws-request@0.1.0', params, options)
const res = await request.send('Lambda', 'deleteFunction', {
FunctionName: params.functionName
})
util-zipper
Helper which provides functionality to create a .zip
archive.
Parameters
- None
Commands
- None
Example
const zipper = loadFunction(context, 'pmuens:util-zipper@0.1.0', params, options)
const artifactFilePath = await zipper.zip(codeDirPath, context.componentRootPath)