serverless frameworkを使ってデプロイ

serverless frameworkってなんなん

YAMLに設定を書いておくと、CLIでAWSのデプロイ/設定が行えます。
簡単に言うと、デプロイの自動化ができます。

環境

項目 version
node 6.10.2
serverless framework 1.19.0

インストール

serverless frameworkをglobalにインストール。

npm install -g serverless

config credentials

serverless framework docs AWS – Config Credentials

プロジェクト作成

serverless frameworkのコマンドを使用してプロジェクトを作成します。

mkdir serverless-sample
serverless create -t aws-nodejs

以下内容のファイルが作成されます。試してみたら見れますがw

handler.js
'use strict';

module.exports.hello = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({
      message: 'Go Serverless v1.0! Your function executed successfully!',
      input: event,
    }),
  };

  callback(null, response);

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};
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: serverless-sample

# 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: nodejs6.10

# 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.js
#    - include-me-dir/**
#  exclude:
#    - exclude-me.js
#    - 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
#      - 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
#      - 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

#    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"

region設定

regionの設定を追記します。

serverless.yml
--- 省略 ---
provider:
  name: aws
  runtime: nodejs6.10
  region: ap-northeast-1
--- 省略 ---

API Gateway設定

上記ロジックを呼ぶエンドポイントの設定を追記。

serverless.yml
--- 省略 ---
functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: serverless-sample
          method: get
--- 省略 ---

デプロイ

serverless frameworkのコマンドを使用してデプロイします。
serverless.ymlに記載の内容でデプロイされます。

serverless deploy

参考

serverless

続きを読む

[新ツール]AWS SAMをローカル環境で実行できるSAM Localがベータリリース

コンニチハ、千葉です。 でました、その名もSAM Local !! ※2017/8/16時点でベータです SAM Localとは? AWS SAMを利用すると、サーバーレスアプリケーションをコードで定義しデプロイすること […] 続きを読む

AWS Batch を動かしてみる

概要

AWS Batchを一通り動かしてみる。

↓の続きです
AWSでバッチ処理をするときの方法を考える

実践

※参考にしたサイト
API Gateway + LambdaでAWS BatchのJobを実行する

1. AWS Batchを作成

AWS Batchを開きます。

スクリーンショット 2017-08-14 17.20.26.jpg

色々入力するところがあるけど全部デフォルトでいいです。
スクリーンショット 2017-08-14 19.04.19.jpg

スクリーンショット 2017-08-14 19.48.45.jpg
そしてCreate。

スクリーンショット 2017-08-14 17.25.46.jpg
実行直後はPriorityが1になっていればとりあえず問題ないはずです。
しばらく経つとするとRUNABLEに入り、SUCCEEDEDに入ればJob完了です。

LambdaからBatchを起動する際にBatchのjobQueueArnが必要なのでJob queuesから確認してメモしておきます。
スクリーンショット 2017-08-14 20.29.01.jpg

2. AWS Batchを起動するLambdaの作成

まずLambda用の新規ロール作成からです。
下記のようなポリシーのロールを作成しておきます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "batch:SubmitJob"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

ロールを作成したらLambdaを作っていきます。
スクリーンショット 2017-08-14 17.30.50.jpg

設計図は使用せずに 「一から作成」 を選択。
スクリーンショット 2017-08-14 17.31.03.jpg

トリガーは追加せずに「次へ」。
スクリーンショット 2017-08-14 17.31.12.jpg

関数の設定です。
適当に名前を付けて、サンプル通りPython3.6を選びます。
スクリーンショット 2017-08-14 17.42.22.jpg

Lambdaの関数コードは下記に書き換え。

import boto3

def lambda_handler(event, context):

    client = boto3.client('batch')

    JOB_NAME = event['JobNeme']
    JOB_QUEUE = "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:job-queue/first-run-job-queue"
    JOB_DEFINITION = "first-run-job-definition:1"

    response = client.submit_job(
        jobName = JOB_NAME,
        jobQueue = JOB_QUEUE,
        jobDefinition = JOB_DEFINITION
        )
    print(response)
    return 0

※8行目 JOB_QUEUE = <1.で作成したBtachのQueue arnに書き換え>

ロールは「テンプレートから新規作成し、テンプレートは “AWS Batchアクセス権限” を選びます」
スクリーンショット 2017-08-14 17.42.40.jpg

次へ
スクリーンショット 2017-08-14 17.42.49.jpg

ざっくり確認しておきます
スクリーンショット 2017-08-14 17.43.23.jpg

スクリーンショット 2017-08-14 17.43.29.jpg

おめでとうございます。
スクリーンショット 2017-08-14 17.44.07.jpg

3. LambdaのためのAPI Gatewayを作る

  1. 先に作成したLambdaのトリガータブを開き「+トリガーを追加」します
    スクリーンショット 2017-08-14 17.44.41.jpg

  2. API Gatewayをトリガーとして設定して送信します。
    スクリーンショット 2017-08-14 17.46.24.jpg

  3. メソッドの作成からPOSTを追加します。
    スクリーンショット 2017-08-14 17.47.34.jpg

  4. 先に作成したLambdaのリージョンを選び、Lambda関数を選択します。
    スクリーンショット 2017-08-14 17.49.06.jpg

  5. APIをデプロイします。
    スクリーンショット 2017-08-14 17.49.35.jpg

  6. 実験ですがProdで特に問題ないです。
    スクリーンショット 2017-08-14 17.49.44.jpg

  7. デプロイが完了するとURLが生成されます。
    スクリーンショット 2017-08-14 17.49.55.jpg

4. 動作確認

  1. 生成されたurlにcurlでPOSTしてみます。
$ curl -X POST -d '{ "JobName" : "test" }' https://xxxxxxxxxx.execute-api.us-east-2.amazonaws.com/prod/ToBatch/
  1. コマンドラインに応答はありませんが、BatchのJob queuesに新しいJobが入ってきます。
    スクリーンショット 2017-08-14 18.30.40.jpg

5. 完了

一旦これで実用的な形になったと思います。
あとはJobに自分の処理内容を乗せておけば、APIでいつでも実行可能となります。

続きを読む

Amazon API Gateway + AWS Lambdaで、iOSでの定期購読をリアルタイムでSlackへ投稿する

2017年7月18日のnewsで、自動更新登録を含むすべてのレシートに、カスタマーの登録のステータスに関するリアルタイムの情報が含まれるように、なったためリアルタイムでslack通知するためにサクッと作りました。
Amazon API Gateway + AWS Lambda のレシピ用意されてて簡単だったので、ぜひ :roller_coaster:

構成

server-notifications.jpeg

  1. iTunes Connect

    • Server notifications for auto-renewable subscriptions
  2. Amazon API Gateway
  3. AWS Lambda
  4. Slack

Lambda 準備

Amazon API Gateway + AWS Lambda の構成はレシピ用意されている。
今回は、python3.6のfunctionを利用(node.js・python2.7も用意されている)

Lambda code

Webhook URLを取得して以下のコード
http://qiita.com/vmmhypervisor/items/18c99624a84df8b31008

import json
import urllib.request
import time

print('Loading function')

def respond(err, res=None):
    return {
        'statusCode': '400' if err else '200',
        'body': err.message if err else json.dumps(res),
        'headers': {
            'Content-Type': 'application/json',
        },
    }

class Receipt:
    def __init__(self, params):
         # 必要に応じて追加する
        self.notification_type = params['notification_type']
        self.product_id        = params['latest_receipt_info']['product_id']
        self.bid               = params['latest_receipt_info']['bid']

def send_slack(channel, receipt): 
    # slack webhook URLは入れ替え 
    url = 'https://hooks.slack.com/services/xxxxxxxxx/xxxxxxxxxxx'
    attachments = [
            {
                "fallback": "iOS Subscription Report",
                "color": "#36a64f",
                "author_name": "mikan",
                "author_link": "http://mikan.link",
                "author_icon": "http://flickr.com/icons/bobby.jpg",
                "title": "購読レポート",
                "text": "App: " + receipt.bid,
                "fields": [
                    {
                        "title": "購読",
                        "value": receipt.notification_type,
                        "short": False
                    },
                    {
                        "title": "商品id",
                        "value": receipt.product_id,
                        "short": False
                    }
                ],
                "image_url": "http://my-website.com/path/to/image.jpg",
                "thumb_url": "http://example.com/path/to/thumb.png",
                "footer": "Server notifications for auto-renewable subscriptions",
                "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
                "ts": time.time()
            }
        ]
    params = {"channel": channel, "username": "dekopon", "attachments": attachments}
    params = json.dumps(params).encode("utf-8")
    req = urllib.request.Request(url, data=params, method="POST")
    res = urllib.request.urlopen(req)

def lambda_handler(event, context):
    params = json.loads(json.dumps(event))
    body = params['body']
    receipt = Receipt(json.loads(body))
    send_slack("playground", receipt)
    return respond(None, "Post slack successfully!")

処理できるかテスト

以下のような方法で、jsonをPOSTしてみてテスト
sample jsonは記事下部に掲載しておきました。

  • Lambdaでテストイベントを設定して実行
  • curlやDHCでPOST実行

Subscription Status URL を設定

iTunes ConnectのMy Appsから、対象アプリを選択して、Subscription Status URLに作成したAPI GateWayのエンドポイントを指定
App StoreApp InformationSubscription Status URL

https://help.apple.com/itunes-connect/developer/#/dev0067a330b

あとは購読してもらえるものを作り込みましょう :rocket:

sample json

{
    "body": {
        "auto_renew_product_id": "link.mikan.sub.sample", 
        "auto_renew_status": "true", 
        "environment": "PROD", 
        "latest_receipt": "xxxxxxxxx", 
        "latest_receipt_info": {
            "app_item_id": "xxxxxxxxx", 
            "bid": "link.mikan.sample", 
            "bvrs": "1", 
            "expires_date": "123456", 
            "expires_date_formatted": "2017-09-05 22:19:54 Etc/GMT", 
            "expires_date_formatted_pst": "2017-09-05 15:19:54 America/Los_Angeles", 
            "item_id": "xxxxxxxxx", 
            "original_purchase_date": "2017-08-05 22:19:56 Etc/GMT", 
            "original_purchase_date_ms": "1501971596000", 
            "original_purchase_date_pst": "2017-08-05 15:19:56 America/Los_Angeles", 
            "original_transaction_id": "730000169590752", 
            "product_id": "link.mikan.sub.sample", 
            "purchase_date": "2017-08-05 22:19:54 Etc/GMT", 
            "purchase_date_ms": "1501971594000", 
            "purchase_date_pst": "2017-08-05 15:19:54 America/Los_Angeles", 
            "quantity": "1", 
            "transaction_id": "xxxxxxxxx", 
            "unique_identifier": "xxxxxxxxx", 
            "unique_vendor_identifier": "xxxxxxxxx", 
            "version_external_identifier": "xxxxxxxxx", 
            "web_order_line_item_id": "xxxxxxxxx"
        }, 
        "notification_type": "INITIAL_BUY", 
        "password": "xxxxxxxxx"
    }
}

参考

Lambda 関数を公開するための API を作成する
Amazon API Gatewayを使ってAWS LambdaをSDKなしでHTTPS越しに操作する
Advanced StoreKit – WWDC 2017 – Videos – Apple Developer

続きを読む