サーバレスフレームワークに触れる

## Serverless Frameworkとは
サーバーレスなアーキテクチャをかんたんに作成できるオープンソースのフレームワークです。
サーバーレスへの理解を深めるために軽く触れてみたいと思います。
[Serverless Framework](https://serverless.com/)

## 1.環境構築
コンソール画面から「Cloud9」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/c30e3e49-baf0-5ccc-76c3-40d57eebde7c.png)

「Create enviroment」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/8d3dd698-21c3-248d-a862-54fe8b016fd4.png)

作成する環境名を入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/33be6694-a75a-c105-08fe-19732d06d292.png)

デフォルトの「Create environment」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/62557b9f-b9da-5bfa-8ce4-c46e441834f6.png)

そうすると環境が出来上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/cdb34855-069f-a447-c3d6-3b00ed6d2907.png)

画面の下にターミナルがあり、Cloud9をホストしているEC2に対してコマンド操作ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/61d7b30c-6650-7cb2-4724-6b5e5b78f351.png)

## 2.Serverless Frameworkをインストール

画面下のターミナルから下記のコマンドを入力します。

```
$ npm install -g serverless
```

## 3.Serverless Frameworkのサービスを作成
下記コマンドを入力すると

```
$ serverless create --template aws-python3 --path test-service
```
`test-service`という名のLambdaが作成され
サービスが開始されます。

```
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/home/ec2-user/environment/test-service"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.59.3
 -------'

Serverless: Successfully generated boilerplate for template: "aws-python3"
```
左上にはディレクトリ構成が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/d6c662af-c2c6-f497-69bc-ff974793eb3e.png)

`test-service`のディレクトリ内にある`serverless.yml`はサービス定義のファイルになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/41be9b26-8bdd-ab76-2539-1943a48e85a9.png)

中身は以下のようになっています。

```serverless.yml
# 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: test-service
# app and org for use with dashboard.serverless.com
#app: your-app-name
#org: your-org-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"

provider:
  name: aws
  runtime: python3.8

# you can overwrite defaults here
#  stage: dev
#  region: us-east-1

# you can add statements to the Lambda function's IAM Role here
#  iamRoleStatements:
#    - Effect: "Allow"
#      Action:
#        - "s3:ListBucket"
#      Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ]  }
#    - Effect: "Allow"
#      Action:
#        - "s3:PutObject"
#      Resource:
#        Fn::Join:
#          - ""
#          - - "arn:aws:s3:::"
#            - "Ref" : "ServerlessDeploymentBucket"
#            - "/*"

# you can define service wide environment variables here
#  environment:
#    variable1: value1

# you can add packaging information here
#package:
#  include:
#    - include-me.py
#    - include-me-dir/**
#  exclude:
#    - exclude-me.py
#    - exclude-me-dir/**

functions:
  hello:
    handler: handler.hello
#    The following are a few example events you can configure
#    NOTE: Please make sure to change your handler code to work with those events
#    Check the event documentation for details
#    events:
#      - http:
#          path: users/create
#          method: get
#      - websocket: $connect
#      - s3: ${env:BUCKET}
#      - schedule: rate(10 minutes)
#      - sns: greeter-topic
#      - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
#      - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx
#      - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx
#      - iot:
#          sql: "SELECT * FROM 'some_topic'"
#      - cloudwatchEvent:
#          event:
#            source:
#              - "aws.ec2"
#            detail-type:
#              - "EC2 Instance State-change Notification"
#            detail:
#              state:
#                - pending
#      - cloudwatchLog: '/aws/lambda/hello'
#      - cognitoUserPool:
#          pool: MyUserPool
#          trigger: PreSignUp
#      - alb:
#          listenerArn: arn:aws:elasticloadbalancing:us-east-1:XXXXXX:listener/app/my-load-balancer/50dc6c495c0c9188/
#          priority: 1
#          conditions:
#            host: example.com
#            path: /hello

#    Define function environment variables here
#    environment:
#      variable2: value2

# you can add CloudFormation resource templates here
#resources:
#  Resources:
#    NewResource:
#      Type: AWS::S3::Bucket
#      Properties:
#        BucketName: my-new-bucket
#  Outputs:
#     NewOutput:
#       Description: "Description for the output"
#       Value: "Some output value"

```

サービス名とプロバイダー情報の記述と
ファンクションでは`handler`ファイルの`hello`メソッドを
呼び出していることがわかります。



handler.pyも中身を見て見ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/d9966ed7-0bc2-f42e-4c4c-e9d12e91a51f.png)

```handler.py
import json


def hello(event, context):
    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event
    }

    response = {
        "statusCode": 200,
        "body": json.dumps(body)
    }

    return response

    # Use this code if you don't use the http event with the LAMBDA-PROXY
    # integration
    """
    return {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "event": event
    }
    """
```
`hello`メソッドが呼び出されると
bodyの`message`の中身が返されるようになっています。

## 4.サービスをデプロイ
今回はデプロイ先を東京リージョンにします。
まず`serverless.yml`の`region`を
`ap-northeast-1`にします。

```serverless.yml
provider:
  name: aws
  runtime: python3.8

# you can overwrite defaults here
#  stage: dev
  region: ap-northeast-1
```

`test-service`に移動して、デプロイコマンドを入力します。

```
$ cd test-service/
$ sls deploy -v
```

実行コマンドを確認するとCloudFormationにより必要なリソースが作成され、
Lambdaがデプロイされていることがわかります。

```
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
CloudFormation - CREATE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_COMPLETE - AWS::S3::Bucket - ServerlessDeploymentBucket
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
CloudFormation - CREATE_IN_PROGRESS - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
CloudFormation - CREATE_COMPLETE - AWS::S3::BucketPolicy - ServerlessDeploymentBucketPolicy
CloudFormation - CREATE_COMPLETE - AWS::CloudFormation::Stack - test-service-dev
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service test-service.zip file to S3 (390 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_COMPLETE - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersionfZV53ZnhGgacYK7o2ukMHtR6ZuuDsESCT1W9HDKNlTE
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Version - HelloLambdaVersionfZV53ZnhGgacYK7o2ukMHtR6ZuuDsESCT1W9HDKNlTE
CloudFormation - CREATE_COMPLETE - AWS::Lambda::Version - HelloLambdaVersionfZV53ZnhGgacYK7o2ukMHtR6ZuuDsESCT1W9HDKNlTE
CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - test-service-dev
CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - test-service-dev
Serverless: Stack update finished...
Service Information
service: test-service
stage: dev
region: ap-northeast-1
stack: test-service-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: test-service-dev-hello
layers:
  None

Stack Outputs
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:test-service-dev-hello:1
ServerlessDeploymentBucketName: test-service-dev-serverlessdeploymentbucket-108d3nky7qbe0
```

## 5.作成されたリソースを見てみる　
コンソール画面から「CloudFormation」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/e4b79903-a3b7-37ca-6001-4aff9f9ffbf3.png)

スタックが作成されているのでクリックして
中身のリソースを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/3d387616-3160-dac7-9974-cfbe4f2946c3.png)

Lambdaの画面からも確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510859/4350bd4e-8bed-71eb-0b8c-d42f80c8ac62.png)

## 6.Lambdaを実行する
下記コマンドから実行します。

```
$ sls invoke -f hello
```

ちゃんと結果が返されました。

```
{
    "statusCode": 200,
    "body": "{\"message\": \"Go Serverless v1.0! Your function executed successfully!\", \"input\": {}}"
}
```

## 7.確認が完了できたらリソースを削除します。
下記コマンドでリソースを削除して完了です。

```
$ sls remove -v
```
[こちら](https://dev.classmethod.jp/cloud/aws/serverless-first-serverlessframework/)を参考に簡単にLambdaをデプロイできました。
感動です。