/ #cdk #python 

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 でやれという話しかも?)

今回のリポジトリはこちら

https://github.com/sisi100/cdk_bolt_hello_world

Author

Sisii

インフラが好きなエンジニアぶってるなにか