お役立ち Twitter Bot を作りながら学ぶ AWS ドリル

~第 9 回 IaC 入門しながら作るリマインダー Bot (前編)

2022-09-02
How to be a Developer

Author : 金澤 圭

ソリューションアーキテクト (SA) の金澤 (@ketancho) です。9 月になりましたが皆さまいかがお過ごしでしょうか ? 私はスポーツ観戦が好きなので、色々なスポーツが終盤戦に差し掛かるここからのシーズンがとても好きで、日々ワクワクしています。現地観戦が全くできていない今日この頃なので、そろそろ熱狂を味わいたいものです。

さて、この連載も 9 回目を迎え、こちらも年内残り 3 回と終盤戦に差し掛かっています。皆さまをワクワクさせられるような内容にできるように頑張っていきたいところです。これまでの連載では、マネジメントコンソール上で各 AWS リソースの作成を手動で行ってきました。年初から AWS ドリルに取り組んでいただいている方は、作業に慣れてきた ! という方もいらっしゃると思いますが、逆に同じ作業を繰り返し行うが少しめんどくさい.. と感じてきている方も出てきているのではないでしょうか ?

そこで、この記事からは皆さまに Infrastructure as Code (IaC) に挑戦していただきます。皆さまはこの IaC という言葉をご存知でしょうか ? IaC は各インフラリソースの状態をコードで記述し、構築作業を自動化する方法です。手動で行っていた構築作業を自動化することで、手間を減らすだけでなく、人手によるミスを回避することができます。また、テンプレート自体をバージョン管理できるので、何かを変更をする際にチームでその差分を見ながらレビューする、といったことも可能になります。AWS において IaC を実現する手段は幾つかあるのですが、今回は AWS Serverless Application Model (AWS SAM) というフレームワークを使っていただきます。

AWS SAM の利用イメージを簡単に紹介します。例えば、Lambda 関数を作成する際は下記のように宣言します。

Resources:
  SendReminderFunction:
    Type: AWS::Serverless::Function 
    Properties:
      FunctionName: twitter-bot-send-reminder-function
      CodeUri: twitter-bot-send-reminder-function/
      Handler: app.lambda_handler
      Runtime: python3.7      

こちらはこの記事で皆さまに作成いただくテンプレートの抜粋になるので、詳細の解説は後ほど行いますが、Lambda 関数の名前やランタイムなどを YAML テンプレートで定義しています (AWS SAM では YAML 形式と JSON 形式を選べますが、この連載では YAML 形式で進めます)。これまでの手作業部分をこのテンプレートに置き換え、これをビルド・デプロイすることで構築を自動化することができます。

構築作業を IaC 化することは、実際の業務でもよく行われます。ぜひこの記事をきっかけに IaC 入門していただき、便利さであったり楽しさであったりをぜひご体験いただければと考えています。

この連載記事のその他の記事はこちら

選択
  • 選択
  • 第 1 回 おはよう Bot 編
  • 第 2 回 昔書いた記事の宣伝 Bot 編
  • 第 3 回 リファクタリング & 曜日ごとのツイート 編
  • 第 4 回 新章突入 ! 気になるワード検索 & 通知 Bot 編
  • 第 5 回 皆さまの代わりに英語でツイートしておくよ Bot 編
  • 第 6 回 AWS Step Functions を使って Well-being Bot を作ろう ! (前編)
  • 第 7 回 AWS Step Functions を使って Well-being Bot を作ろう ! (後編)
  • 第 8 回 - 総集編 & 夏休みの自由研究のすすめ
  • 第 9 回 - IaC 入門しながら作るリマインダー Bot (前編)
  • 第 10 回 - IaC 入門しながら作るリマインダー Bot (中編)
  • 完結回 - IaC & CI/CD 入門しながら作るリマインダー Bot (後編)

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. この記事で作る Bot の機能と、とりあげる AWS サービス・機能

さて、皆さまに作っていただく Twitter Bot を紹介していきます。今回のお題はリマインダー Bot です。皆さまは何か気になった技術記事を見つけたときにどうされていますか  ? もちろん、その場で読めればベストだと思うのですが、それができないこともあると思います。私は「あとで読む」とだけ Twitter でツイートしておき、あとでまとまった時間を確保し、一気に読むということをしています。しかし、最近はそのルーチンをうまく回せておらず、大半の記事はそのまま読まずに流してしまっている気がします。そんな怠惰な私と同じ ( ? ) エンジニアの皆さま向けに、「あとで読む」とした記事を本当に読んだかをチクチク確認するおせっかい Bot を作っていこうと思います。

リマインダー Bot の具体的な要件ですが、

  • 「あとで読む」を含む自分のツイート ID をデータベースに格納しておく
  • 14 日後にそのツイートに対して「本当にあとで読みましたか ?」とメンションを送る
  • リマインドは 12 時に送る

としたいと思います。文字で書くと簡単なのですが、やることは盛りだくさんなので、今回を含め合計 3 つの記事で少しずつリマインダー Bot を育てていきます。AWS の構成図としては、最終的には下記のようになる想定です。

過去の AWS ドリルで実際に手を動かされている方からすると、「あれ ? データベースに保持しなくても、Twitter の検索を工夫して 14 日前の『あとで読む』が含まれるツイートを取ればいいんじゃない ?」と思われた方もいらっしゃるかもしれません。しかし、残念ながらこれまで使ってきた検索機能 (/search/recent) では、過去 7 日分までしか遡ることができません(AWS ドリル 第 4 回 の「4. Twitter の検索 API を使ってみる」でもこの件には触れているので、参照してみてください)。ですので、一度データベースに情報を保持する形に最終的にはしたいと考えています。

と、書きつつ、いきなりこちらの要件を全て実現すると記事が長くなりすぎるので、今回はシンプルに下記の要件のみを AWS SAM で実現するところまで進めようと思います。

  • 「あとで読む」を含む自分のツイートに対して、3 日後に「本当にあとで読みましたか ?」とメンションを送る (3 日後なので、検索がそのまま使えます)
  • リマインドは 12 時に送る

この記事では、AWS SAM を用いたテンプレートからの構築にチャレンジいただきますが、加えて AWS Cloud9 というサービスも使っていただきます。AWS Cloud9 はブラウザのみでコードを記述、実行、デバックできるクラウドベースの統合開発環境です。AWS Cloud9 上のエディタでソースコードや YAML 形式のテンプレートを作成・修正し、同じく AWS Cloud9 上のターミナルを使ってビルドやデプロイをしていきます。


2. 今回から AWS ドリルを始める方の作業

さて、具体的な作業を始める前に前提を揃えたいと思います。この記事では取り扱わない前提作業を AWS ドリル 第 4 回 の「2. 今回から AWS ドリルを始める方の作業」 にまとめています。今回のドリルから初めて手を動かすぞ ! という方は、こちらを先にご確認いただければと思います。

また、このあとのツイートする部分やツイートを検索する部分の実装は、これまでのドリルの内容をそのまま使ったり、ベースにしたりしています。この記事では触れないのですが、実装の意図について過去の記事をあわせてご参照いただくことで、より理解が深まると思います。


3. AWS Cloud9 の環境を準備する

まず AWS Cloud9 の環境を整えていきましょう。AWS Cloud9 のサービス画面 に遷移し、右側にある「Create environment」ボタンをクリックしてください。

AWS Cloud9 が利用できない場合、こちらのブログ をご参考に AWS IDE Toolkits または AWS CloudShell をご利用ください。

AWS Cloud9 から AWS IDE Toolkits または AWS CloudShell に移行する方法 »

環境の名前を入れる画面に遷移するので、「Name」に「aws-drill-twitter-bot」と入力し、「Next step」をクリックしてください。

次の画面でインスタンスタイプなどの細かい設定を変更できるのですが、今回はデフォルトのまま進めていただいて構いません。右下の「Next step」をクリックしてください。

最後に確認画面が出ますので、そのまま「Create environment」としましょう。

クリックすると拡大します

環境構築が終わるまでこのような画面が出てきます。1 ~ 2 分お待ちください。

クリックすると拡大します

このような画面が表示されましたら環境の準備が完了です。

下部にターミナルが表示されているはずですので、この後はこちらを中心に作業を進めていきます。もし、ターミナル画面がない、あるいは間違って消してしまった ! という方がいらっしゃいましたら、上部の Window から「New Terminal」をクリックすることで新しいターミナルウィンドウを出すことが可能です。

クリックすると拡大します


4. AWS SAM の下準備とテンプレートの構成要素の解説

それではここから AWS SAM を利用していきます。AWS SAM を利用する方法は幾つかあるのですが、今回は皆さまのローカル環境でもご利用いただける AWS SAM CLI を使って開発していきます。AWS Cloud9 環境には標準で SAM CLI がインストールされているのですが、もしローカル環境でも SAM CLI を使いたい ! と思われた方は、こちらの SAM CLI インストールガイド をご覧いただければと思います。

AWS Cloud9 環境には標準で SAM CLI が導入されていると書きましたが、まずはターミナルで下記のコマンドを実行していただき、SAM CLI のバージョンをご確認ください。

$ sam --version
SAM CLI, version 1.33.0

この記事を執筆している時点では、1.33.0 がインストールされておりますので、こちらのバージョンを使っていきます。(SAM CLI は日々アップデートされていますので、バージョンが異なると今後の実行結果が変わったり、選ぶ選択肢 (選択番号) を変える必要が出てくるかもしれません。何か記事と結果が変わってる?と思われた際には、SAM CLI のバージョンを確認いただき、適宜読み替えて後続の作業を進めていただければと思います。)

では、具体的な作業を進めていきましょう。SAM CLI のドキュメントは こちら にありますので、各コマンドの該当ページを参照しながら進めていただければと思います。

まず sam init コマンドを使い、対話形式で初期設定を進めます。各項目については、下記のように入力してください。

  • Which template source would you like to use? :  1 - AWS Quick Start Templates を選択 (1 を入力し、Enter)
  • What package type would you like to use? : 1 - Zip (artifact is a zip uploaded to S3) を選択 (1 を入力し、Enter)
  • Which runtime would you like to use? : 10 - python3.7 を選択 (10 を入力し、Enter)
  • Project name [sam-app] : aws-drill-reminder-bot と入力し、Enter
  • AWS quick start application templates : 1 - Hello World Example を選択 (1 を入力し、Enter)


このような実行結果になると思います。

$ sam init

        SAM CLI now collects telemetry to better understand customer needs.

        You can OPT OUT and disable telemetry collection by setting the
        environment variable SAM_CLI_TELEMETRY=0 in your shell.
        Thanks for your help!

        Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

Which runtime would you like to use?
        1 - nodejs14.x
        2 - python3.9
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs12.x
        8 - nodejs10.x
        9 - python3.8
        10 - python3.7
        11 - python3.6
        12 - python2.7
        13 - ruby2.5
        14 - java8.al2
        15 - java8
        16 - dotnetcore2.1
Runtime: 10

Project name [sam-app]: aws-drill-reminder-bot

Cloning from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
        4 - Step Functions Sample App (Stock Trader)
Template selection: 1

    -----------------------
    Generating application:
    -----------------------
    Name: aws-drill-reminder-bot
    Runtime: python3.7
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .
    
    Next steps can be found in the README file at ./aws-drill-reminder-bot/README.md
        

SAM CLI update available (1.53.0); (1.33.0 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html
AWSReservedSSO_AdministratorAccess_fe16a7c8cf43fd3f:~/environment $ 

Python 3.7 を Runtime に選んだ理由を先に説明します。これまでの AWS ドリルでは Python 3.9 で Lambda 関数を作成してきました。このあと AWS SAM のビルドコマンドを利用するのですが、Lambda 関数を Python 3.9 で構築する場合、ビルド環境 (今回のドリルだと AWS Cloud9 環境) に同じ Python 3.9 が必要です。しかし、この記事を執筆している 2022/8 時点では、AWS Cloud9 環境に標準で入っている Python バージョンは 3.7 系になります。Python 3.9 をインストールすることもできるのですが、今回のドリルでやりたいことの本題から外れてしまうのと、今回のテーマは Python 3.7 でも全く問題がないため、この記事では標準で使える Python 3.7 で Lambda 関数を作成しています。

さて、sam init が終わると左側の Environment 欄に aws-drill-reminder-bot というディレクトリができていると思います。

まずは、こちらの左側の三角マークをクリックして中身を確認してみましょう。

クリックすると拡大します

今回の記事で最も多く手を加えるのが aws-drill-reminder-bot 直下にある template.yaml になります。この時点では下記のような内容になっています。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-drill-reminder-bot

  Sample SAM Template for aws-drill-reminder-bot

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

初めて AWS SAM を使われる方が多いと思いますので、この template.yaml の読み解き方を今回のドリルに関連する部分に絞って紹介します。

まず、

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function 

こちらの Resources セクションにおいて、各 AWS リソースの定義をしていきます。ここがテンプレートの肝の部分です。ここで定義されている内容をラフに書くと、「HelloWorldFunction という論理名のリソースを定義したいんだけど、そのリソース Type は Lambda 関数でよろしく」になります。

他のリソース Type については こちらのページ に記載があり、過去の AWS ドリルで取り扱った Amazon DynamoDB や、Web API を構築する際に便利な Amazon API Gateway といったリソースを作成できます。また、AWS には AWS CloudFormation というテンプレートから AWS リソースをプロビジョニングできるサービスがあるのですが、AWS SAM はこの CloudFormation の拡張になります。AWS SAM でも、AWS CloudFormation で利用できる全ての AWS リソースを使用できるので、先ほど紹介したリソース Type のページに記載がない AWS サービスも AWS SAM のテンプレートとして取り扱うことができます。(AWS SAM で取り扱いのないリソース Type については、次回のドリルで利用していきます。)

少し範囲を広げて、下記の内容について解説します。

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get

先ほどリソース Type を Lambda 関数に決定しましたが、この Type で設定できる項目はプロパティとして こちらのページ にまとまっています。「Runtime は Python 3.7 だよ」「トリガーするイベントは API だよ」といった形で、ひとつひとつ設定を定義をしています。

Lambda 関数の肝であるコードについては、

      CodeUri: hello_world/
      Handler: app.lambda_handler

の部分で定義しており、こちらは

  • template.yaml と同じ階層にある hello_world ディレクトリ内にコードを用意しているよ
  • そのファイルは app.py で、関数が呼び出されたときに実行するメソッドは lambda_handler だよ

と定義しています。つまり、hello_world ディレクトリの中の app.py に、AWS Lambda 上で動かしたい Python コードを書いていけばいいということになります。

以上が、デフォルトで用意されたテンプレートのうち、今回の AWS ドリルに関連する部分の簡単な解説になります。Globals セクションや Outputs セクションについては、AWS SAM テンプレートのガイドAWS CloudFormation テンプレートのガイド をご覧いただければと思います。


5. AWS SAM を用いて新しい Lambda 関数 twitter-bot-send-reminder-function を作成する

それでは具体的な作業を再開しましょう。今回やりたいことを再掲すると、

  • 「あとで読む」を含む自分のツイートに対して、3 日後に「本当にあとで読みましたか ?」とメンションを送る
  • リマインドは 12 時に送る

でした。ここでは、まずは前者の部分の実装を進めます。

まず、リマインダーを送る Lambda 関数 twitter-bot-send-reminder-function を作成したいと思います。先程の template.yaml の中身を下記のように書き換えてください。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-drill-reminder-bot

Globals:
  Function:
    Timeout: 3

Resources:
  SendReminderFunction: # 変更
    Type: AWS::Serverless::Function 
    Properties:
      FunctionName: twitter-bot-send-reminder-function # 追加
      CodeUri: twitter-bot-send-reminder-function/ # 変更
      Handler: app.lambda_handler
      Runtime: python3.7
      Policies: # 追加
        - AmazonSSMReadOnlyAccess # 追加
      # Events 以下は(Outputs セクションも含め)全て削除してください

リソース名や Properties の CodeUri の部分を変更しているのに加え、何点か追加している項目があります。まず、FunctionName というプロパティを追加し、Lambda 関数名を指定しています。また、Policies というプロパティを追加しています。こちらは今回作成する Lambda 関数の IAM ロールに AmazonSSMReadOnlyAccess ポリシーをアタッチすることで、Parameter Store に格納している Twitter API の Key / Token 情報を取得できるようにしています。

続いて、Lambda 関数のコード部分を実装していきます。先程 CodeUri で指定した twitter-bot-send-reminder-function ディレクトリがないのでそれを作成し、コードを記載する app.py や、後ほど利用する requirements.txt のファイルだけ用意しておきます。また、デフォルトで用意されている hello_world ディレクトリは不要になったのでこのタイミングで削除してしまいます。

$ cd ~/environment/aws-drill-reminder-bot/
$ rm -r hello_world/
$ mkdir twitter-bot-send-reminder-function
$ touch twitter-bot-send-reminder-function/app.py
$ touch twitter-bot-send-reminder-function/requirements.txt

続いて、app.py を編集し、Lambda 関数のコードを実装しましょう。この app.py への Python コードの実装については、これまでのドリルで Lambda 関数用に Python コードを書いてきた部分と同じ流れになります。

「『あとで読む』を含む自分のツイートに対して、3 日後に『本当にあとで読みましたか?』とメンションを送る」が要件なのですが、言い換えると、

  • 4 日前から 3 日前の自分のツイートのうち「あとで読む」を含むツイートを検索する
  • 該当したツイートがあればそれに対して「本当にあとで読みましたか ?」とメンションする

となります。

前者は AWS ドリル 第 4 回 や 第 5 回 の実装を参考に、後者もこれまでの AWS ドリルの内容を応用していただければ実装ができると思います。もし、実装にチャレンジされたい方は、まずはご自身で実装を進めてみてもいいかもしれません。

 

 


私は下記のように実装してみました。

import json
from requests_oauthlib import OAuth1Session
from datetime import datetime, timedelta

import boto3
ssm_client = boto3.client('ssm')

oauth = None

def lambda_handler(event, context): 
    init()
    
    search_query = 'あとで読む from:ketancho -is:retweet'
    start_time = (datetime.now() + timedelta(days=-4)).strftime('%Y-%m-%dT15:00:00Z')
    end_time =  (datetime.now() + timedelta(days=-3)).strftime('%Y-%m-%dT15:00:00Z')
    
    json_response = get_matching_tweets(search_query, start_time, end_time)
    
    if('data' not in json_response):
        return
    matched_tweets = json_response['data']
    
    for matched_tweet in matched_tweets:
        reply("@ketancho あとで読みましたか?", matched_tweet['id'])
        
    return json_response

def init():
    response = ssm_client.get_parameter(
        Name='/credentials/twitter',
        WithDecryption=True
    )
    twitter_parameters = json.loads(response['Parameter']['Value'])

    consumer_key = twitter_parameters['consumer_key']
    client_secret = twitter_parameters['client_secret']
    access_token = twitter_parameters['access_token']
    access_token_secret = twitter_parameters['access_token_secret']
    
    global oauth
    oauth = OAuth1Session(consumer_key, client_secret, access_token, access_token_secret)
    
def get_matching_tweets(search_query, start_time, end_time):
    url = 'https://api.twitter.com/2/tweets/search/recent'
    params = {
        'query': search_query,
        'max_results': 20,
        'start_time': start_time,
        'end_time': end_time
    }
    response = oauth.get(
       url, params=params
    )
    
    if response.status_code != 200:
        raise Exception(
            '[Error] {} {}'.format(response.status_code, response.text)
        )

    return response.json()
    
def reply(text, target_tweet_id):
    payload = {
        'text': text,
        'quote_tweet_id': target_tweet_id,
        'reply': {
            'in_reply_to_tweet_id': target_tweet_id
        }
    }
    response = oauth.post(
        'https://api.twitter.com/2/tweets',
        json=payload,
    )
    if response.status_code != 201:
        raise Exception(
            '[Error] {} {}'.format(response.status_code, response.text)
        )

これまでの AWS ドリルと異なる点として、

  • 検索時にリツイートは除外 (自分で「あとで読む」と書いたものだけに絞りたいので)
  • 過去のドリルの tweet メソッドを reply メソッドに変更し、対象のツイートにリプライする形 (reply > in_reply_to_tweet_id を追加) かつ 対象のツイートを引用する形 (quote_tweet_id を追加) に変更

といった修正を行っています。(詳細は Twitter API ドキュメント をご覧いただくと分かりやすいと思います。)

また、これまでのドリルと同じく requests_oauthlib という Python モジュールを利用します。AWS SAM で Python で Lambda 関数を実装する場合は、requirements.txt に利用するモジュールを記載します。後続のビルド時にこの依存関係を解決してくれます。twitter-bot-send-reminder-function ディレクトリ内の requirements.txt に下記の1行を追加し、保存してください。

requests_oauthlib

以上で修正が完了したので、AWS SAM のビルドとデプロイを行い、Lambda 関数をプロビジョニングしていきます。twitter-bot-send-reminder-function ディレクトリで、下記のコマンドを実行してください。(AWS Cloud9 環境に入り直すと、カレントディレクトリが ~/environment に戻ってしまうので、もしそうなっていた場合は、twitter-bot-send-reminder-function に cd してください。)

$ sam build

これまでの作業に誤りがなければ、下記のようにビルドが成功すると思います。

$ sam build
Building codeuri: /home/ec2-user/environment/aws-drill-reminder-bot/twitter-bot-send-reminder-function runtime: python3.7 metadata: {} architecture: x86_64 functions: ['SendReminderFunction']
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided

ビルドに成功したら、下記のコマンドを入力しデプロイします。

$ sam deploy --guided

デプロイ時の設定を対話形式で設定していきます。(guieded オプションを付けると対話形式になり、この設定は保存されるので 2 回目以降のデプロイ時は guieded は不要になります。)

  • Stack Name [sam-app] : aws-drill-reminder-bot と入力し、Enter
  • AWS Region [ap-northeast-1] : (何も入力せずに Enter)
  • Confirm changes before deploy [y/N] : y と入力し、Enter
  • Allow SAM CLI IAM role creation [Y/n] : Y と入力し、Enter
  • Save arguments to configuration file [Y/n] : Y と入力し、Enter
  • SAM configuration file [samconfig.toml] : (何も入力せずに Enter)
  • SAM configuration environment [default] : (何も入力せずに Enter)


その後、しばらく待つと、下記のように変更点として追加される AWS リソースの一覧が表示されます。

$ sam deploy --guided

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: aws-drill-reminder-bot
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: Y
        Save arguments to configuration file [Y/n]: Y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 
        
(省略)

Waiting for changeset to be created..

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                               LogicalResourceId                                       ResourceType                                            Replacement                                           
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                                   SendReminderFunctionRole                                AWS::IAM::Role                                          N/A                                                   
+ Add                                                   SendReminderFunction                                    AWS::Lambda::Function                                   N/A                                                   
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:981766141304:changeSet/samcli-deploy1659469408/e2829691-9901-47c3-956d-19ae08261f7f


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:

こちら変更点が問題なければ y と入力してください。更に少し待つと、下記のようにデプロイに成功した旨が表示されるはずです。

Deploy this changeset? [y/N]: y

2022-08-02 19:43:52 - Waiting for stack create/update to complete

CloudFormation events from changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                          ResourceType                                            LogicalResourceId                                       ResourceStatusReason                                  
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                                      AWS::IAM::Role                                          SendReminderFunctionRole                                -                                                     
CREATE_IN_PROGRESS                                      AWS::IAM::Role                                          SendReminderFunctionRole                                Resource creation Initiated                           
CREATE_COMPLETE                                         AWS::IAM::Role                                          SendReminderFunctionRole                                -                                                     
CREATE_IN_PROGRESS                                      AWS::Lambda::Function                                   SendReminderFunction                                    -                                                     
CREATE_IN_PROGRESS                                      AWS::Lambda::Function                                   SendReminderFunction                                    Resource creation Initiated                           
CREATE_COMPLETE                                         AWS::Lambda::Function                                   SendReminderFunction                                    -                                                     
CREATE_COMPLETE                                         AWS::CloudFormation::Stack                              aws-drill-reminder-bot                                  -                                                     
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - aws-drill-reminder-bot in ap-northeast-1

こちらで Lambda 関数が作成できているはずなので、Lambda 関数の一覧画面 にで確認してください。aws-drill-reminder-bot-SendReminderFunction から始まる関数はうまく作られていますでしょうか ?

試しにテスト実行もしてみましょう。こちらのようにメンションが飛びましたら実装成功です🎉

ここのテストがやや難しく、3 日前に「あとで読む」を含むツイートをしている必要があります。「あとで読む」ツイートをして 3 日待つのは現実的ではないので、もしクイックにテストしたい場合は、Lambda 関数のコードの start_timeend_time を調整してテストしてみてください。

クリックすると拡大します


6. Amazon EventBridge と連携し、時間トリガーで Lambda 関数 twitter-bot-send-reminder-function を起動する

最後に、作成した Lambda 関数が毎日12時に起動するように設定します。これまでの AWS ドリルで使ってきた Amazon EventBridge を活用します。AWS SAM で Amazon EventBridge リソースを作成する方法が幾つかあるのですが、今回は Lambda 関数リソースの Events プロパティを使っていきます。詳細は こちらのドキュメント に記載があるのですが、

      Events:
        SendReminderEvent:
          Type: Schedule
          Properties:
            Schedule: 'cron(0 3 * * ? *)'
            Name: SendReminderEvent
            Enabled: True

このような形で Events プロパティを記載することで、日本時間 12 時にトリガーされる EventBridge ルールを作成することができます。template.yaml に下記のように Events プロパティを追加してみてください。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-drill-reminder-bot

Globals:
  Function:
    Timeout: 3

Resources:
  SendReminderFunction:
    Type: AWS::Serverless::Function 
    Properties:
      FunctionName: twitter-bot-send-reminder-function
      CodeUri: twitter-bot-send-reminder-function/
      Handler: app.lambda_handler
      Runtime: python3.7
      Policies:
        - AmazonSSMReadOnlyAccess
      Events: # この行以下を全て追加
        SendReminderEvent:
          Type: Schedule
          Properties:
            Schedule: 'cron(0 3 * * ? *)'
            Name: SendReminderEvent
            Enabled: True

こちら保存ができましたら、再度ビルドとデプロイを行います。

$ sam build
$ sam deploy

変更点が表示されるので、

CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                               LogicalResourceId                                       ResourceType                                            Replacement                                           
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                                   SendReminderFunctionSendReminderEventPermission         AWS::Lambda::Permission                                 N/A                                                   
+ Add                                                   SendReminderFunctionSendReminderEvent                   AWS::Events::Rule                                       N/A                                                   
* Modify                                                SendReminderFunction                                    AWS::Lambda::Function                                   False                                                 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:981766141304:changeSet/samcli-deploy1659473363/5a2019c8-f963-40b6-a979-631e6ae8f771


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: 

y と入力してください。

少しお待ちいただくと、デプロイが完了した旨、メッセージが表示されます。

Deploy this changeset? [y/N]: y

2022-08-02 20:50:53 - Waiting for stack create/update to complete

CloudFormation events from changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                          ResourceType                                            LogicalResourceId                                       ResourceStatusReason                                  
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS                                      AWS::Lambda::Function                                   SendReminderFunction                                    -                                                     
UPDATE_COMPLETE                                         AWS::Lambda::Function                                   SendReminderFunction                                    -                                                     
CREATE_IN_PROGRESS                                      AWS::Events::Rule                                       SendReminderFunctionSendReminderEvent                   -                                                     
CREATE_IN_PROGRESS                                      AWS::Events::Rule                                       SendReminderFunctionSendReminderEvent                   Resource creation Initiated                           
CREATE_COMPLETE                                         AWS::Events::Rule                                       SendReminderFunctionSendReminderEvent                   -                                                     
CREATE_IN_PROGRESS                                      AWS::Lambda::Permission                                 SendReminderFunctionSendReminderEventPermission         -                                                     
CREATE_IN_PROGRESS                                      AWS::Lambda::Permission                                 SendReminderFunctionSendReminderEventPermission         Resource creation Initiated                           
CREATE_COMPLETE                                         AWS::Lambda::Permission                                 SendReminderFunctionSendReminderEventPermission         -                                                     
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS                     AWS::CloudFormation::Stack                              aws-drill-reminder-bot                                  -                                                     
UPDATE_COMPLETE                                         AWS::CloudFormation::Stack                              aws-drill-reminder-bot                                  -                                                     
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - aws-drill-reminder-bot in ap-northeast-1

Lambda 関数の画面の上部にスクロールし、イベントトリガーが追加されていれば完了です。

毎日 12 時に「あとで読む」ツイートに対してメンションが届くはずです。毎日何かしらの記事を「あとで読む」していただき、しっかり Bot が動いているかご確認いただければと思います。

クリックすると拡大します

以上で、今回の AWS ドリルの実装は完了になります ! お疲れさまでした🎉


7. まとめ

「お役立ち Twitter Bot を作りながら学ぶ AWS ドリル」連載の第 9 弾として、シンプルなリマインダー Bot を作成しました。私と同じく怠惰な方がいましたら、きっとこのリマインダー Bot が技術者としての成長を支援してくれるはずです。また、新しい技術としては AWS SAM を用いてテンプレートから AWS のリソースを作成していただきました。次回はこのリマインダー Bot を育てながら、今回は使わなかった AWS SAM の他の機能も使っていきたいと考えています。

最後にいつものお願いです。皆さまのご感想・ご要望を #AWSウェブマガジン タグをつけてツイートしていただけたら嬉しいです🙏 この記事に +α して、こんなものを作ってみました ! という共有も大歓迎です。今後の連載の参考にさせてもらいたいと思っておりますので、ぜひよろしくお願いしますー !

それでは次回の記事でまたお会いしましょう !

この連載記事のその他の記事はこちら

選択
  • 選択
  • 第 1 回 おはよう Bot 編
  • 第 2 回 昔書いた記事の宣伝 Bot 編
  • 第 3 回 リファクタリング & 曜日ごとのツイート 編
  • 第 4 回 新章突入 ! 気になるワード検索 & 通知 Bot 編
  • 第 5 回 皆さまの代わりに英語でツイートしておくよ Bot 編
  • 第 6 回 AWS Step Functions を使って Well-being Bot を作ろう ! (前編)
  • 第 7 回 AWS Step Functions を使って Well-being Bot を作ろう ! (後編)
  • 第 8 回 - 総集編 & 夏休みの自由研究のすすめ
  • 第 9 回 - IaC 入門しながら作るリマインダー Bot (前編)
  • 第 10 回 - IaC 入門しながら作るリマインダー Bot (中編)
  • 完結回 - IaC & CI/CD 入門しながら作るリマインダー Bot (後編)

builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

金澤 圭 @ketancho
アマゾン ウェブ サービス ジャパン合同会社
技術統括本部 ソリューションアーキテクト

サーバーレスが好きなソリューションアーキテクト。業種業界問わず、お客様のプロダクト開発をサポートさせていただいています。オンデマンドで視聴できるハンズオン「AWS Hands-on for Beginners」、実際にものづくりをしながら AWS を学ぶ「AWS ドリルシリーズ」を企画・推進しており、楽しく学べるコンテンツを日々考えています。好きなサービスは AWS Lambda、AWS Step Functions、Amazon Personalize で、好きな休日の過ごし方は娘ふたりと川の字になって昼寝👧👧と赤ん坊を抱っこしながらの散歩です👶

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する