Serverless framework
Introduction
Develop, deploy, troubleshoot and secure your serverless applications with radically less overhead and cost by using the Serverless Framework. The Serverless Framework consists of an open source CLI and a hosted dashboard. Together, they provide you with full serverless application lifecycle management.
References
Serverless Framework
https://www.serverless.com/framework/docs/getting-started
Serverless.yml Reference
Including stage parameters, etc.
https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml
serverless.yml - Dynamically replace config values
https://www.serverless.com/framework/docs/providers/aws/guide/variables
Install
npm install serverless
//npm install [package-name]@[version-number]
//-g = global
//-i = skip the execution of any scripts that are defined in the package.json file
Upgrade
npm update -g serverless
Initial setup
serverless
Commands
sls client
Deploy static files to, eg S3, using the plugin finch
sls client deploy --stage dev
sls create
sls create --template aws-nodejs
sls deploy
serverless deploy --region eu-west-1 --stage dev
sls dynamo
Install local DynamoDB, which can be use later w/ sls offline start
sls dynamodb install
Migrate database
sls dynamodb migrate
sls info
Service information, endpoints (eg: of a lambda), functions, layers
serverless info
serverless info --region eu-west-1 --stage labs
sls invoke
Invoke a deployed function
sls invoke -f hello
Invoke a non-deployed function
sls invoke local -f hello
sls logs
Retrieve logs of function
sls logs myfunction
sls offline
sls offline start
sls remove
The sls remove command will remove the deployed service, defined in your current working directory, from the provider.
serverless remove --region eu-west-1 --stage dev
Plugins
serverless-add-api-key
Eg: sixqueue
https://www.serverless.com/plugins/serverless-add-api-key
To create api key and usage pattern (if they don't already exist) and associate them to the Rest Api.
It matches API Key by name, ignores it if it already exists.
serverless-plugin-ifelse
Eg: sixqueue
https://www.serverless.com/plugins/serverless-plugin-ifelse
It allows conditional serverless.yml
serverless-prune-plugin
Eg: sixqueue
https://www.serverless.com/plugins/serverless-prune-plugin
Following deployment, the Serverless Framework does not purge previous versions of functions from AWS, so the number of deployed versions can grow out of hand rather quickly. This plugin allows pruning of all but the most recent version(s) of managed functions from AWS.
Usage, delete all but the n-most recent versions of each function deployed. Versions references by an alias are automatically preserved:
sls prune -n <number of version to keep>
serverless-pseudo-parameters
For serverless version < 2.50.0; it allows to use #{AWS::AccountId}, #{AWS::Region}, etc. in any of your config strings.
https://www.npmjs.com/package/serverless-pseudo-parameters
Install w/ npm:
npm install --save serverless-pseudo-parameters
and add it to the serverless.yml plugins list:
plugins:
- serverless-pseudo-parameters
serverless-python-requirements
Eg: sixqueue
https://www.serverless.com/plugins/serverless-python-requirements
The plugin will bundle your python dependencies specified in your Pipfile when you run sls deploy.
Add the plugin to package.json and the plugins section of serverless.yml
sls plugin install -n serverless-python-requirements
Variables
SSM Parameter Store
You can reference SSM Parameters as the source of your variables with the ssm:/path/to/param syntax. For example:
${ssm:/${self:provider.stackTags.env}/${self:provider.stackTags.ci}/salesforce_username}
For decrypting SecureString (WithDecryption: true) add ~true. Eg:
${ssm:/${self:provider.stackTags.env}/${self:provider.stackTags.ci}/salesforce_password~true}
Functions
API Gateway gateway
a) If using HTTP API (API Gateway v2), not REST API:
provider:
environment:
API_URL: !GetAtt HttpApi.ApiEndpoint
Example:
!Join ['', [!GetAtt HttpApi.ApiEndpoint, '/mylambda']]
b) If using REST API (API Gateway v1), not HTTP API:
provider:
environment:
API_URL: !Sub 'https://${ApiGatewayRestApi}.execute-api.${aws:region}.amazonaws.com/${sls:stage}'
Layer: AWS-Parameters-and-Secrets-Lambda-Extension (functions)
In serverless.yml:
provider:
iamRoleStatements:
- Effect: "Allow"
Action:
- "ssm:GetParameter"
Resource: arn:aws:ssm:${self:provider.region}:#{AWS::AccountId}:parameter/${self:provider.stackTags.UOCEnv}/${self:provider.stackTags.ci}/*
- Effect: "Allow"
Action:
- "kms:Decrypt"
Resource: arn:aws:kms:*:#{AWS::AccountId}:key/alias/aws/ssm
and in the functions section:
functions:
create:
handler: event.jobs
layers:
- arn:aws:lambda:eu-west-1:015030872274:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11
events:
- http:
path: ${self:service}/jobs
method: post
cors: true
private: true
Sample request:
import urllib.parse
import urllib.request
aws_session_token = get_env('AWS_SESSION_TOKEN')
req = urllib.request.Request('http://localhost:2773/systemsmanager/parameters/get?name=' + urllib.parse.quote('/env/ci/cl_id') + '&withDecryption=true')
req.add_header('X-Aws-Parameters-Secrets-Token', aws_session_token)
config = urllib.request.urlopen(req).read().decode('utf-8')
Sample response:
{"Parameter":{"ARN":"arn:aws:ssm:eu-west-1:434374682878:parameter/env/ci/cl_id","DataType":"text","LastModifiedDate":"2024-01-08T16:16:42.673Z","Name":"/env/ci/cl_id","Selector":null,"SourceResult":null,"Type":"String","Value":"MyValue","Version":1},"ResultMetadata":{}}
Resources (Serverless)
Security Group (Resources)
It allows to add CloudFormation resources to the servelss.yml
resources:
Resources:
SecurityGroupLambda: #AWS CloudFormation yaml synxtax
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 'Assigned to authorizer lambda and configured on the OAuth server to allow connections from it'
GroupName: ${self:provider.stackTags.env}-${self:provider.stackTags.ci}-lambda-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: 'IPv4 allow all outbound traffic, eg to the OAuth server'
IpProtocol: -1
- CidrIpv6: ::/0
Description: 'IPv6 allow all outbound traffic, eg to the OAuth server'
IpProtocol: -1
#SecurityGroupIngress: ~
VpcId: ${param:vpc_id}
Outputs:
SgIdForOauth:
Description: 'SG id to be configured in the OAuth server to allow connections from this lambda authorizer'
Value: !Ref SecurityGroupLambda
The id of the created SG can be referenced this way:
securityGroupIds:
- Ref: SecurityGroupLambda
The 'output' (the id of the created security group in this case) can be obtained with:
aws cloudformation describe-stacks --stack-name <ci>-<stage> --output text --region eu-west-1 --query "Stacks[0].Outputs[?OutputKey=='SgIdForOauth'].OutputValue"
Python lambda (Serverless)
Version
package.json contains the 'version' in a Serveless package.
It can be obtained from a Python lambda via:
import json
def lambda_handler(event, context):
with open('package.json', 'r') as f_ver:
f_ver_dict = json.load(f_ver)
tech_comp_version = f_ver_dict.get("version")
logger.info("======== Artifact version: %s ========", tech_comp_version)
Troubleshooting
Deployment bucket has been removed manually. Please recreate it or remove your service and attempt to deploy it again
TLDR: Manually delete the cloud formation stack in AWS console, and then redeploy.