CDKとPythonを使って、SlackBotをBoltで作る(ハロワまで)
オリンピックですねー!
さてさて
今回はSlack の公式フレームワークの Bolt と CDK を使ってハロワまで作ってみます!
今回作るのはこんな感じです!
事前に SSM の ParameterStore に SlackBot の認証情報を渡しておき(この辺は一応ベストプラクティスに従っておいた)、 CDK でアプリケーションをデプロイして ParameterStore から認証キーを引っ張ってきて Slack とメッセージのやり取りをします!
Lambda の中がやや複雑で、Bolt が一筋縄で動いてくれないのでやや工夫してます。
以上!
2021/09/27
この記事は古いです。
awsgiもFlaskも使わないで作れたのでStack周りを下記を参照ください!
もっとシンプルにBolt+CDK+PythonでSlackBotを作る
何がしたいの?
CDK で Bolt を管理したいという強い意思
前提
- AWS のアカウント持っている
- Slack を使える
では 作っていきましょう 👻
Slack にアプリを用意する
まぁ、詳しくはここ(↓)を読んでくれ!という感じですので、紙芝居的にペタペタ貼る程度流します
https://slack.dev/bolt-js/ja-jp/tutorial/getting-started
まず下記にアクセスして、
https://api.slack.com/apps?new_app=1
下記ピンク丸をクリック
アプリ名を入力して、チャンネルを選択してピンク丸をクリック
下にスクロールし、、、
ピンク丸の Signing Secret をコピー(どこかに貼り付けておく)しておく。
次にピンク丸をクリックして
スクロールし、、
ピンク丸クリックして
下記の通り文字入力して、出てきた項目選択し、、
一番上までスクロールして、ピンク丸クリックして、
ワークスペースにアクセス許可して、
ピンク丸クリックして、トークンをコピーしておく
完了!!
ParameterStore に登録する
下記コマンド叩く
# Signing Secretを登録する
$ SLACK_SIGNING_SECRET=ここに一番初めにコピーした(Signing Secret)を貼り付ける
$ aws ssm put-parameter --name "/cdk_bolt_hello_world/slack_signing_secret" --value $SLACK_SIGNING_SECRET --type SecureString
# トークンを登録する
$ SLACK_BOT_TOKEN=ここにトークンを貼り付ける!
$ aws ssm put-parameter --name "/cdk_bolt_hello_world/slack_bot_token" --value $SLACK_BOT_TOKEN --type SecureString
念の為登録できてるか確認してみる
$ aws ssm get-parameters-by-path --path "/cdk_bolt_hello_world" --query 'Parameters[*].Name'
# ↓下記のように指定した階層の登録済みのキーが取得されるので、2つあればOK!
[
"/cdk_bolt_hello_world/slack_bot_token",
"/cdk_bolt_hello_world/slack_signing_secret"
]
完了 ❗
インフラを用意する
ここまで長かったですねー(汗)
では CDK を使って新規にインフラ+アプリを作っていきます!
まず CDK の準備ですが、このあたりの詳細は以前の記事を参照ください!
なのでここは、コマンドだけ列挙していきます
$ mkdir cdk_bolt_hello_world
$ cd cdk_bolt_hello_world
$ cdk init sample-app --language python
# 使わないファイルの削除
$ rm -rf cdk_bolt_hello_world tests setup.py source.bat
$ source .venv/bin/activate
requirements.txt
を今回使うリソースで更新します
aws-cdk.core==1.91.0
aws-cdk.aws-lambda==1.91.0
aws_cdk.aws_lambda_python==1.91.0
aws-cdk.aws_apigateway==1.91.0
aws_cdk.aws_ssm==1.91.0
からのインストール(↓)
$ pip install -r requirements.txt
そして CDK を実装します!
import os
from aws_cdk import core
from aws_cdk.aws_apigateway import LambdaRestApi
from aws_cdk.aws_lambda import Runtime
from aws_cdk.aws_lambda_python import PythonFunction
from aws_cdk.aws_ssm import StringListParameter
APP_NAME = "CdkBoltHelloWorld"
SSM_PARAMETER_NAMES = ["/cdk_bolt_hello_world/slack_bot_token", "/cdk_bolt_hello_world/slack_signing_secret"]
class CdkBoltHelloWorldStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
lambda_ = PythonFunction(
self,
f"{APP_NAME}Lambda",
entry="cdk_bolt_hello_world", # <- この辺はまだディレクトリないので、この後作る予定
handler="bolt_handler", # <- ここも
runtime=Runtime.PYTHON_3_8,
)
# RestApiでAPI Gatewayを作成する
LambdaRestApi(self, f"{APP_NAME}Gateway", handler=lambda_)
# パラメーターストアから読み取れるように、Lambdaに権限をあげる
for param_name in SSM_PARAMETER_NAMES:
StringListParameter.from_string_list_parameter_name(
self, f"{APP_NAME}-{param_name}", param_name
).grant_read(lambda_)
app = core.App()
env = core.Environment(account=os.getenv("CDK_DEFAULT_ACCOUNT"), region=os.getenv("CDK_DEFAULT_REGION"))
CdkBoltHelloWorldStack(app, APP_NAME, env=env)
app.synth()
これでインフラは完成です!
アプリを作る ❗
はい、アプリを作っていきます。
ここで注意ですが、Bolt は一筋縄では Lambda に上がってくれません。
なのでちょっと遠回りな方法で動かしますのでご容赦ください!
# アプリ用のディレクトリ用意
$ mkdir cdk_bolt_hello_world
CDK で PythonFunction を使っているので、requirements.txt
が使えるので必要なライブラリーを書きます
slack-bolt==1.7.0
aws-wsgi==0.2.6
Flask==1.1.1
はい。Bolt 以外にもなにかいますね(笑)
aws-wsgi
は API Gateway で Flask とか Django とか使えるとても便利なライブラリーです ❗
流れとしては API Gateway からaws-wsgi
を使ってflask
に流して、そこから更にslack-bolt
へリクエストを投げると、、、そんな動きです ❗
では実装してみます ❗
まず ParameterStore からトークンとか取ってきます
こんな感じ!
import boto3
SSM_PARAMETER_NAMES = ["/cdk_bolt_hello_world/slack_bot_token", "/cdk_bolt_hello_world/slack_signing_secret"]
SLACK_BOT_TOKEN = ""
SLACK_SIGNING_SECRET = ""
ssm = boto3.client("ssm")
# CDKだと`get_parameters_by_path`非推奨っぽいので1つづつ取得する
for param_name in SSM_PARAMETER_NAMES:
parameter = ssm.get_parameter(Name=param_name, WithDecryption=True)["Parameter"]
if "slack_bot_token" in parameter["Name"]:
SLACK_BOT_TOKEN = parameter["Value"]
if "slack_signing_secret" in parameter["Name"]:
SLACK_SIGNING_SECRET = parameter["Value"]
デバックをしてみたければ$ pip install boto3
で boto3 を入れた後に
$ python -m cdk_bolt_hello_world.settings
とでも打てば動きますので、あとはブレイクポイント(import pdb; pdb.set_trace()
)でも入れてご確認ください!
BoltApp を作る!
次に認証情報を使って BoltApp を作ります!
といっても公式の Demo そのままですが、、、
from settings import SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET
from slack_bolt import App
app = App(signing_secret=SLACK_SIGNING_SECRET, token=SLACK_BOT_TOKEN, process_before_response=True)
@app.message("hello")
def message_hello(message, say):
say(f"Hey there <@{message['user']}>!")
特にコメントないですね。次行きましょう
エントリーポイントを作る
最後に API Gateway から叩かれるエントリーポイントを作ります
import awsgi
from bolt_app import app
from flask import Flask, request
from slack_bolt.adapter.flask import SlackRequestHandler
flask_app = Flask(__name__)
slack_handler = SlackRequestHandler(app)
@flask_app.route("/slack/events", methods=["POST"])
def slack_events():
return slack_handler.handle(request)
def handler(event, context):
return awsgi.response(flask_app, event, context)
完成 ❗
CDK デプロイする
$ cd ../
$ cdk deploy
これ Terminal が微動だにしないまま、結構時間かかります。
コーヒでも飲みながら待ちましょう!
デプロイが完了すると、Terminal に API Gateway の URL が返ってくるのでそれを コピーしておきましょう!!
URL を Slack に登録、、、とかする
最後の手順です(汗)、、、長い
slack のページに戻りまして、下記ピンク丸クリック
下記ピンク丸クリック
API Gateway の URL を下記に貼り付けて末尾に/slack/events
を追加する。確認に少しかかるので暫く待つ。
無事終わったら、下記のピンク丸クリック
下記の通り入力したら、ピンク丸クリックして権限を付与する。
※スクショでは写ってないけれども右下のSave Changes
的なボタンをクリック
上にアプリをインストールして!的な文章がでてくるので、ピンク丸クリック
→ その後アプリインストールの画面にいくけれども、指示通り進む
動作確認
slack にhello
と打ち込むと、返答が返ってくる!
以上!!
あとしまつ
# スタックの削除
$ cdk destroy
# ParameterStoreのお掃除
$ aws ssm delete-parameters --names $(aws ssm get-parameters-by-path --path "/cdk_bolt_hello_world" --query 'Parameters[*].Name' --output text)
# ↓成功するとこんな感じ
{
"DeletedParameters": [
"/cdk_bolt_hello_world/slack_bot_token",
"/cdk_bolt_hello_world/slack_signing_secret"
],
"InvalidParameters": []
}
まとめ
Bolt を cdk 経由でデプロイしてハロワをしてみました!
一筋縄で Bolt を使えないので、やや回りくどい方法になりましたが、
もっとシンプルな方法あったら教えてくださいませー!
(公式にある通り sls + Node.js でやれという話しかも?)