Production-ready Serverless

on AWS

James Allardice

orangejellyfish

James Allardice

The Serverless framework

James Allardice

The Serverless framework

James Allardice

Production-ready?

James Allardice

Maintainable

James Allardice

Performant

James Allardice

Scalable

James Allardice

Secure

James Allardice

> npm i -g serverless

James Allardice

> npm i -g serverless
> serverless create --template aws-nodejs
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: aws-nodejs # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

James Allardice

# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
#    docs.serverless.com
#
# Happy Coding!

service: aws-nodejs # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
frameworkVersion: "=1.37.0"

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

# serverless.yml
provider:
  name: aws
  runtime: nodejs8.10

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

# serverless.yml
plugins:
  - serverless-webpack

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

// .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "8.10"
        }
      }
    ]
  ]
}

James Allardice

const nodeExternals = require('webpack-node-externals');
const slsw = require('serverless-webpack');

module.exports = {
  entry: slsw.lib.entries,
  target: 'node',
  mode: 'production',
  externals: [nodeExternals()],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
};

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

James Allardice

plugins:
  - serverless-webpack
  - serverless-iam-roles-per-function

James Allardice

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

    iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:PutItem
        Resource:
          - Fn::GetAtt: [ MyTable, Arn ]
      - Effect: Allow
        Action:
          - sns:publish
        Resource:
          - Ref: MyTopic

James Allardice

⚙️

🚀

⚖️

🔒

James Allardice

Resources:

  # A custom API Gateway account to allow us to enable request logging.
  ApiGatewayAccount:
    Type: AWS::ApiGateway::Account
    Properties:
      CloudWatchRoleArn:
        Fn::GetAtt: [ RoleAPIGatewayCloudWatch, Arn ]

  # A custom API Gateway stage (usually handled automatically by the Serverless
  # framework) so that we can turn on CloudWatch request logging. The
  # "MethodSettings" of a stage apply to all methods (effectively all endpoints)
  # within that stage. The ApiGatewayRestApi resource is generated automatically
  # by the Serverless framework.
  ApiGatewayStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId:
        Ref: ApiGatewayRestApi
      MethodSettings:
        - DataTraceEnabled: true
          HttpMethod: "*"
          LoggingLevel: INFO
          ResourcePath: /*
          MetricsEnabled: true

Stage

Account

Resources:

  # An IAM role to allow API Gateway to log requests to CloudWatch.
  RoleAPIGatewayCloudWatch:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - apigateway.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs

James Allardice

Apply to API Gateway

James Allardice

⚙️

🚀

⚖️

🔒

functions:
  getTweets:
    handler: tweets.get
    events:
      - schedule: rate(5 minutes)
    environment:
      TWITTER_ACCESS_TOKEN: "xxxxx"

James Allardice

:(

functions:
  getTweets:
    handler: tweets.get
    events:
      - schedule: rate(5 minutes)
    environment:
      TWITTER_ACCESS_TOKEN: ${ssm:TWITTER_ACCESS_TOKEN}

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

# Lambda function definitions. Each function defines itself in a separate YAML
# file that resides alongside the function implementation. Unfortunately we have
# to duplicate the function name here due to the way Serverless YAML importing
# and parsing works.
functions:
  hello: ${file(src/functions/hello/index.yml):hello}

James Allardice

# src/functions/hello/handler.js
hello:
  handler: src/functions/hello/handler.hello
  events:
    - http:
        path: hello
        method: get

  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:PutItem
      Resource:
        - Fn::GetAtt: [ MyTable, Arn ]
    - Effect: Allow
      Action:
        - sns:publish
      Resource:
        - Ref: MyTopic

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

# Custom AWS resource definitions. This includes anything that the Serverless
# framework doesn't handle for us, such as database setup, and overrides of
# Serverless defaults.
resources:
  - ${file(src/resources/dynamodb.yml)}
  - ${file(src/resources/sns.yml)}

James Allardice

Resources:

  MyTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:service}-${self:custom.stage}-my-table
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      BillingMode: PAY_PER_REQUEST

James Allardice

Resources:

  MyTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:service}-${self:custom.stage}-my-table
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      BillingMode: PAY_PER_REQUEST

James Allardice

James Allardice

⚙️

🚀

⚖️

🔒

⚙️

🚀

⚖️

🔒

James Allardice

GitHub!

James Allardice

What next?

Thank you!

James Allardice

orangejellyfish

Slides: https://slides.com/jamesallardice/production-ready-serverless-on-aws

Production-ready Serverless on AWS (Serverless London, Feb 2019)

By James Allardice

Production-ready Serverless on AWS (Serverless London, Feb 2019)

  • 864