LoginSignup
1

More than 1 year has passed since last update.

【AWS Lambda】Slackに通知を送信する

Posted at

今回はCloudFormationでLambdaを触ってみるということで、Slackに通知を送信するLambda関数を構築していきたいと思います。

調べてみたところ、Lambdaを構築する場合はCloudFormationの AWS::Serverless というマクロ機能を利用するみたいです。
AWS::Serverless変換

マクロを利用すると「AWS SAM 構文」なるものでLambdaを定義できるようになり、 aws cloudformation package コマンド実行時に、通常のCloudFormationテンプレートに展開されます。

マクロ機能を利用するには、テンプレート内で下記のように宣言します。

template.yml
Transform: AWS::Serverless-2016-10-31

SlackのWebhook URLを取得する

Slack通知を行うためのWebhookURLを取得します。
Slack での Incoming Webhook の利用

1. 「アプリを追加する」から Incoming Webhookを追加

スクリーンショット 2021-10-05 233317.png

スクリーンショット 2021-10-05 233201.png

2. 投稿したいチャンネルを選択し、インテグレーションの追加をクリック

スクリーンショット 2021-10-05 234312.png

3. Webhook URLをコピー

スクリーンショット 2021-10-05 234335.png

テンプレートの実装

ディレクトリ構成

- project-notify-slack.yml
- src/
   - lambda_function.py

1. CloudFormationテンプレート実装

下記3つのリソースを作成します

  • Lambda発火の起点となるトピック
  • LambdaのDLQ用トピック
  • Slackに通知を送信するLambda
    AWS::Serverless::Function
project-notify-slack.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Slack notification app

Parameters:
  SlackWebhookUrl:
    Type: String
  SlackChannel:
    Type: String
  Email:
    Type: String

Outputs:
  SlackNotifySnsTopicArn:
    Value: !Ref SlackNotifyTopic

Resources:
  # Lambda発火の起点となるトピック
  # https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html
  SlackNotifyTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub ${AWS::StackName}-topic-notify

  # lambdaのDLQ用トピック
  # https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html
  DlqTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Sub ${AWS::StackName}-topic-dlq
      # https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html
      Subscription:
        - Endpoint: !Ref Email
          Protocol: email

  # Slackに通知を送信するLambda
  # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html
  SlackNotifyFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub ${AWS::StackName}-function
      CodeUri: ./src
      # lambdaのエントリーポイント(ファイル名.関数名)
      Handler: lambda_function.lambda_handler
      Runtime: python3.8
      MemorySize: 128
      Timeout: 180
      # 環境変数
      Environment:
        Variables:
          SLACK_WEBHOOK_URL: !Ref SlackWebhookUrl
          SLACK_CHANNEL: !Ref SlackChannel
      # Lambdaの処理が規定回数以上失敗した場合の通知先
      # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-deadletterqueue.html
      DeadLetterQueue:
        Type: SNS
        TargetArn: !Ref DlqTopic
      # 関数実行の起点となるイベントソースを定義
      # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-eventsource.html
      Events:
        Rule:
          Type: SNS
          Properties:
            Topic: !Ref SlackNotifyTopic

2. Lambda関数の実装

Slackに通知を送信する関数を実装します。(公式のコピペです)

/src/lambda_function.py
#!/usr/bin/python3.8

import urllib3
import json
import os

http = urllib3.PoolManager()

def lambda_handler(event, context):
    url = os.getenv("SLACK_WEBHOOK_URL")
    channel = os.getenv("SLACK_CHANNEL")
    print("url={}, channel={}".format(url, channel))
    msg = {
        "channel": channel,
        "text": event['Records'][0]['Sns']['Message'],
        "icon_emoji": ""
    }
    encoded_msg = json.dumps(msg).encode('utf-8')
    resp = http.request('POST',url, body=encoded_msg)
    print({
        "message": event['Records'][0]['Sns']['Message'],
        "status_code": resp.status,
        "response": resp.data
    })

デプロイ

aws cloudformation package コマンドで、AWS SAM形式のテンプレート(マクロ)を展開します。
デプロイに必要な資材をs3にアップロードする必要があるので、適当なバケットを作ってオプションに渡します。

# lambdaのデプロイ資材をアップロードするバケット
S3_BUCKET="sample-bucket"
# デプロイ資材の格納パス
S3_PREFIX="path/to/package"

# lambda関数をパッケージ
# --output-template-file に指定したファイル名に展開後のテンプレートが保存されます。
aws cloudformation package \
  --region "ap-northeast-1" \
  --profile "default" \
  --template-file "project-notify-slack.yml" \
  --output-template-file "project-notify-slack-package.yml" \
  --s3-bucket "${S3_BUCKET}" \
  --s3-prefix "${S3_PREFIX}"

展開されたテンプレートをデプロイします。

# スタック名任意
STACK_NAME="sample-stack"
# 先ほど取得したWebhook URLを定義
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxxxxxxxx/YYYYYYYYYYY/ZZZZZZZZZZZ"
# 通知を飛ばしたいチャンネル名を指定
SLACK_CHANNEL="#test-midorikawa"
# lambda処理失敗時に通知を飛ばすメールアドレスを指定
EMAIL="hogehoge@example.com"

# デプロイ
aws cloudformation deploy \
  --region "ap-northeast-1" \
  --profile "default" \
  --stack-name "${STACK_NAME}" \
  --template-file "project-notify-slack-package.yml" \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides \
    SlackWebhookUrl="${SLACK_WEBHOOK_URL}" \
    SlackChannel="${SLACK_CHANNEL}" \
    Email="${EMAIL}"

動作確認

CLIからトピックにpublishしてSlackに通知が送信されるか確認します。

# TopicArnを確認
TOPIC_ARN=$(aws cloudformation describe-stacks --stack-name $STACK_NAME | jq '.Stacks[].Outputs[]')

# メッセージを送信
aws sns publish --topic-arn "${TOPIC_ARN}" --subject testSubject --message testMessage

参考

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
1