LoginSignup
0
2

More than 5 years have passed since last update.

CloudFormationでサーバーレスのLINEBOTをデプロイする。

Last updated at Posted at 2019-03-10

概要

AWSの学習の中で,CloudFormationを使ってみたくなったので使ってみました。

目標:
Lambda関数をスケジュール起動させて,LINEで通知を送るサーバーレスのBOTをCloudFormationでデプロイします。

今回は1分おきに「slimeはkawaii。」「dragonはkakkoii。」「ghostはkowai。」のメッセージいずれかをランダムでLINEにpush通知するアプリケーションを作ります。

※通知する内容はDynamoDBから取得します。

下のようなネットワーク図になります。
図中のAWSサービスをCloudFormationテンプレートにまとめます。
lambdaCFndraw.png

CloudFormationのテンプレート

CloudFormationのテンプレートです。
リソースはAWS Lambda,Amazon DynamoDB,Amazon CloudWatchです。
また今回はテンプレートの中でLambdaとCloudWatchそれぞれのIAMロールも作るようにしました。

CFnTemplate.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Line_Push_bot
Parameters:
  pushFunctionName:
    Type: String
    Default: PushFunction
    Description: pushFunction
  dynamoDBTableName:
    Type: String
    Default: sampleContents
  pushFuncStoredS3BucketName:
    Type: String
    Description: "pushFunction Stored S3 Bucket" 
  S3KeyName:
    Type: String
    Default: "lambda_function.zip"
  pushFuncHandlerName:
    Type: String
    Default: lambda_function.lambda_handler
  pushFuncIAMPolicyName:
    Type: String
    Default: PushFuncIAM
  lineUserID:
    Type: String
  lineChannelAccessToken:
    Type: String   
Resources:
  pushFunc:
    Type: 'AWS::Lambda::Function'
    Properties:
      FunctionName: !Ref 'pushFunctionName'
      Code:
        S3Bucket: !Ref 'pushFuncStoredS3BucketName'
        S3Key: !Ref 'S3KeyName'
      Description: "push lambda template"
      Handler: !Ref 'pushFuncHandlerName'
      Role: !GetAtt 
        - LambdaExecutionRole
        - Arn
      Runtime: python3.6
      Environment:
        Variables:
          'uid': !Ref 'lineUserID'
          'LINE_CHANNEL_ACCESS_TOKEN': !Ref 'lineChannelAccessToken'
  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: !Ref 'pushFuncIAMPolicyName'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'dynamodb:GetItem'
                Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${dynamoDBTableName}'
              - Effect: Allow
                Action:
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                  - 'logs:CreateLogGroup'
                Resource: '*'
  PushLambdaScheduleEvent:
    Type: AWS::Events::Rule
    Properties:
        Description: 'schedule event for pushFunction'
        ScheduleExpression: 'rate(1 minute)'
        State: ENABLED
        Targets:
          - Arn: !GetAtt pushFunc.Arn
            Id: TargetFunctionV1 
  PushLambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !Ref pushFunctionName
      Principal: events.amazonaws.com
      SourceArn: !GetAtt PushLambdaScheduleEvent.Arn
  sampleTable:
    Type: 'AWS::DynamoDB::Table'
    Properties:
      TableName: !Ref dynamoDBTableName
      AttributeDefinitions:
        - AttributeName: type
          AttributeType: S
      KeySchema:
        - AttributeName: type
          KeyType: HASH
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5

Lambdaのコードは下のようになります。

lambda_function.py
import urllib.request, urllib.parse
import boto3
import json
import os
import random

dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table('sampleContents')

def lambda_handler(event, context):
    types = ["dragon", "slime", "ghost"]
    type = random.choice(types)
    try:
        response = table.get_item(
            Key = {
                    'type': type
            }
        )
        msg = response['Item']['characteristic']
    except:
        msg = "まだいません"
    pushmsg = "{0}は{1}。".format(type, msg)
    url = 'https://api.line.me/v2/bot/message/push'
    body = {
        "to":  os.environ['uid'],
        "messages": [
            {
                "type": "text",
                "text": pushmsg
            }
        ]
    }
    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + os.environ['LINE_CHANNEL_ACCESS_TOKEN']
    }
    req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
    with urllib.request.urlopen(req) as res:
        pass
    return {'statusCode': 200, 'body': '{}'}

手順

上に記述したコードを使ってデプロイする手順を追って説明します。

  1. LINE MessagingAPIを利用できるようにします。
    未登録の場合はLINE Developersに登録しましょう。
    以下記載のURLにしたがって,プロバイダーとチャネルを作成します。
    プロバイダーのプランはフリーではなくDveloper Trialです(Push Messageを利用するため)。
    ↓詳しくはLINE Developersのドキュメントを参照してください。↓

    [Messaging APIを利用するには]https://developers.line.biz/ja/docs/messaging-api/getting-started/

    このとき,アクセストークン(ロングターム)Your user IDを控えておきます。

  2. 1で作成したチャネルの基本設定の中にあるQRコードを読み取り,お友達追加をしてください。

  3. lambda_function.pylambda_function.zipという名前でzip圧縮し,S3バケットにアップロードします。
    この時のS3バケット名を控えておきます。
    S3バケットを作成するリージョンとCloudFormationでスタックを作成するリージョンは一致させてください。
    例えばap-northeast-1にスタックを作成する場合は,ap-northeast-1にS3バケットを作成してください。

  4. CFnTemplate.yamlを基にしてスタックを作成します。
    下図を参考にしてアクセストークン(ロングターム)Your user IDS3バケット名を各パラメーターの値へ入れていきます。
    手順通りに進めた場合,デフォルトで入力されている項目は特に変更する必要はありません。  
    ※スタックの作成完了後は1分おきにLINEが届きますのでご注意ください。
    stackscene.png

動作確認

  1. LINEを確認します。
    「・・・はまだいません。」とメッセージが届くはずです。
    ・・・の部分は slime, dragon, ghostのいずれかです。
    例えば「slimeはkawaii。」のような「・・・は***。」というメッセージがpush通知されることが今回の目標ですが,まだDynamoDBのテーブルに該当の要素がないため,pushFuncがこのようなメッセージを生成して通知しています。

  2. DynamoDBへ要素を追加します。
    「・・・は***。」という形のメッセージをLINEにpush通知するために,DynamoDBのテーブルへ要素を追加します。
    sampleContentsという名前のテーブルができているので,以下のようにします。

type characteristic
slime kawaii
dragon kakkoii
ghost kowai

上のように要素をDBに追加することで,LINEに「・・・は***。」とpushされます。
・・・はtype,***はcharacteristicが対応します。

削除方法

  1. CloudFormationのスタックを削除します。

  2. 次にlambda_function.py がアップロードされているS3バケットを削除します。

  3. 最後にLINE Developersにログインし,チャネル,プロバイダーの順に削除します。

   

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2