Serverless FrameworkでSlackアプリを作ってみる

はじめに

こんにちは。永和システムマネジメント FDPメンバの坂部です。

FDPでは、4月からSlackアプリの作成に取り組んでいます。

今回は、下記のツールセットでSlackアプリを作ってみます。

  • Bolt
  • Python
  • AWS Lambda
    • コンテナイメージ
    • AWS Lambda Function URLs
  • Serverless Framework
  • VS Code Remote Container

目指すのは、「hello」と発言すると、応答してくれるアプリです。

Boltのチュートリアルにあるやつです)

VS Code Remote Containerの設定

開発環境にはVS Code Remote Containerを使用します。

./devcontainer/devcontainer.json

{
  "name": "sample-serverless-slack-app",
  "dockerFile": "Dockerfile",
  // Lambdaコンテナイメージのデプロイで使うDocker
  "features": {
    "docker-in-docker": {
        "version": "latest",
        "moby": true,
        "dockerDashComposeVersion": "v1"
    }
  },
  // AWSのクレデンシャルはコンテナ外の環境変数に設定して、コンテナ内に渡す
  "containerEnv": {
    "AWS_ACCESS_KEY_ID": "${localEnv:AWS_ACCESS_KEY_ID}",
    "AWS_SECRET_ACCESS_KEY": "${localEnv:AWS_SECRET_ACCESS_KEY}"
  },
  "postCreateCommand": "pip install -r requirements.txt",
  "settings": {
    ...
  },
  "extensions": [
    ...
  ]
}

./devcontainer/Dockerfile

# Python3.10を試したかったが、Lambdaのコンテナイメージが3.9までしかサポートしていない
FROM python:3.9.11

# serverlessをインストール
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
RUN apt-get install -y nodejs
RUN npm install -g serverless@3.12.0

Serverless Frameworkの設定

serverless.yml

service: sample-serverless-slack-app

frameworkVersion: "3"

provider:
  name: aws
  region: ap-northeast-1
  ecr:
    images:
      appimage:
        path: ./ # 同じディレクトリのDockerfileを参照
  iamRoleStatements:
    - Effect: Allow
      Action:
        - secretsmanager:GetSecretValue
      Resource:
        - "*"  # よくない 😡

functions:
  app:
    image:
      name: appimage
    url: true # AWS Lambda Function URLsを使う
    events:
      - http:
          method: post
          path: /slack/events

Lambdaの設定

Dockerfile

FROM public.ecr.aws/lambda/python:3.9

COPY requirements.txt ./

RUN pip install -r requirements.txt

COPY app.py ./

CMD [ "app.handler" ]

requirements.txt

slack-bolt==1.13.0
boto3==1.12.42

app.py

import json
import logging
import os

import boto3
from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

logging.basicConfig(level=logging.DEBUG)

# SlackのクレデンシャルはSecrets Managerに格納している
# serverlessに環境変数として渡した方が良いかも 🤔
secretsmanager = boto3.client("secretsmanager", region_name=<your_region>)
secret_value = secretsmanager.get_secret_value(SecretId=<your_secret_id>)
secret = json.loads(secret_value["SecretString"])

os.environ["SLACK_BOT_TOKEN"] = secret["SLACK_BOT_TOKEN"]
os.environ["SLACK_SIGNING_SECRET"] = secret["SLACK_SIGNING_SECRET"]


app = App(process_before_response=True)


# 「hello」のメッセージに応答する
@app.message("hello")
def message_hello(message, say):
    say(f"Hey there <@{message['user']}>!")


def handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)

デプロイしてみる

コンテナ外でAWSのクレデンシャルを設定します。

export AWS_ACCESS_KEY_ID=<your access key>
export AWS_SECRET_ACCESS_KEY=<your secret access key>

あと、AWSコンソールでぽちぽちして、Secrets ManagerにSlackのクレデンシャルを登録しておきます。

デプロイします。

sls deploy
sls deploy

Deploying sample-serverless-slack-app to stage dev (ap-northeast-1)
Warning: Docker authentication token will be stored unencrypted in docker config. Configure Docker credential helper to remove this warning.

✔ Service deployed to stack sample-serverless-slack-app-dev (182s)

endpoints:
  POST - https://??????.execute-api.ap-northeast-1.amazonaws.com/dev/slack/events
  app: https://???????????????.lambda-url.ap-northeast-1.on.aws/
functions:
  app: sample-serverless-slack-app-dev-app

1 deprecation found: run 'serverless doctor' for more details

下記を参考に、Slackアプリを作成します。

slack.dev

https://slack.dev/bolt-python/ja-jp/tutorial/getting-started-http#httpを利用したイベントを設定する あたりを参考に、発行されたURLをSlackアプリに設定します。

「hello」と発言してみます。

f:id:sakabehiroki:20220416192806p:plain

無事、動作しました 🎉

余談

2022/04/16時点で、Serverless Frameworkでよく使われるプラグインの、serverless-offlineがLambdaのコンテナイメージに未対応なので、注意したほうが良いかもです。

github.com

参考

slack.dev

slack.dev

github.com

docs.aws.amazon.com

www.serverless.com