[3章] AWS ECRへのPUSH内容を、Slackへ通知する
目次
- はじめに
- 概要
- Slack Appの設定
- AWS Lambdaの設定
- AWS SNSの設定
- AWS EventBridgeの設定
- アプリの作成
- Lambdaへの紐付け
- おわりに
1. はじめに
こんにちは、ネクストビートの富永です。
本ブログでは、前回の2章で作成した構成の続きを行います。
これから作成を行う構成の概要を知りたい方は、前回の1章と2章を先に読むことをおすすめします。
2. 概要
今回は、以下の項目を行っていき、タイトルにあるようにAWS ECRへのPUSH内容を、Slackへ通知する処理の実装を行います。
- Slackの設定
- AWS Lambdaの設定
- AWS SNSの設定
- AWS EventBridgeの設定
- アプリの作成
- Lambdaへの紐付け
構成図
3. Slack Appの設定
Slackへメッセージを送信できるように設定を行っていきます。
まずは、Slack Appを作成するページへいきます。
次に「Create New App」を選択します。
下記画像のような画面が表示されますので、以下項目を設定します。
- アプリ名の入力
- アプリを作成するSlack Workspaceの選択
設定後「Create App」を選択しアプリケーションの作成を行います。
作成したSlack Appをボットとして、Slackのチャンネルに招待します。
OAuth & Permissionsタブを選択し下記画像の「Install to Workspace」を選択します。
次の画面では、「Allow」を選択します。
紐付け完了後以下画像のように、Bot User OAuth Access Tokenが生成されているのを確認できれば成功です。
作成されたBotに書き込み権限を付与します。
同ページScopesの項目で、「Add an OAuth Scope」を選択します。
権限の一覧から「chat:write」を選択し付与します。
付与後以下のように表示されていれば成功です。
最後にSlack Appを発言させたいチャンネルに参加させます。
これをやらないで処理を行うと、not_in_channelというエラーが返ってきます。
Slack Appを招待したいチャンネルへ行き、「More」選択後以下画像の「Add apps」を選択します。
選択後以下画像のように、作成したSlack Appの「Add」を選択し、チャンネルへ招待します。
これでSlackの設定は完了です。
4. AWS Lambdaの設定
次はLambda関数の作成を行います。
※今回作成するLambda関数は、テスト用です。最終的にはCDK for Terraformで作成したものを使用します。
Lambdaの設定を行うページで、「関数の作成」を選択します。
以下画像のように「一から作成」を選択します。
以下項目を設定します。
- 関数名
- ランタイム
今回はTypeScriptを使用するので、Node.jsを選択 - 実行ロール
テストなので、新しいロールを作ってしまいましょう。
設定完了後「関数の作成」を選択します。
作成完了後、以下のように表示されていればLambda関数の作成は完了です。
次は、作成したLambdaに環境変数を設定します。
以下画像の「設定」タブを選択し、「環境変数」を選択します。
「環境変数の追加」を選択し、新しく環境変数の登録を行います。
今回作成する環境変数は以下の2つです。
- SLACK_API_TOKEN
- SLACK_CHANNEL
SLACK_API_TOKENは、先ほどSlack Appの設定で作成したBot User OAuth Access Tokenの値を設定します。
SLACK_CHANNELは、今回メッセージを送信したいSlackのチャンネルIDを設定します。
チャンネルIDの取得は、以下方法で取得できます。
まず、チャンネル名を右クリックして、下記画像の「Copy link」を選択します。
すると下記のようなリンクをコピーできます。
リンクのxxxxxxxxxの部分が、チャンネルIDになります。
https://nb-learning.slack.com/archives/xxxxxxxxxx
Lambdaに環境変数を追加したら、完了です。
5. AWS SNSの設定
次は、SNSの設定を行っていきます。
※こちらも作成するのはテスト用です。最終的にはCDK for Terraformで作成したものを使用します。
SNSの設定ページへいき「トピックの作成」を選択します。
トピックのタイプはスタンダードを選択します。
SNSの名前を入力後「トピックの作成」を選択します。
以下画像のように作成完了後、先ほど作成したLambdaとの紐付けを行います。
「サブスクリプション」タブを選択後、「サブスクリプションの作成」を選択します。
トピックは先ほど作成したSNSトピックを選択します。
プロトコルは、今回Lambdaを使用するので、AWS Lambdaを選択します。
エンドポイントは、先ほど作成したLambdaのエンドポイントを選択します。
設定後「サブスクリプションの作成」を選択します。
設定完了後、先ほど作成したLambdaのページへ行き、以下画像のようにSNSが紐づいていれば完了です。
6. AWS EventBridgeの設定
次は、ECRのPUSHをトリガーとするAWS EventBrigeの設定を行います。
※こちらも同様に、最終的にはCDK for Terraformで作成したものを使用します。
まずは、EventBridgeの設定ページへいきます。
「ルールを作成」を選択します。
次に、ルールの名前と説明を設定します。
次は、EventBridgeの設定を行います。
まずは、パターン定義でイベントパターンを選択します。
次に、イベント一致パターンの種類を「サービスごとの事前定義パターン」を選択します。
サービスプロバイダーは、AWSを選択します。
サービス名は、今回ECRをトリガーとするので、ECRを選択します。
イベントタイプは、ECR Image Actionを選択します。
アクションタイプは特定のアクションを選択し、種類はPUSHを選択します。
結果も特定の結果を選択し、種類はSUCCESSを選択します
その他は、初期設定のままで大丈夫です。
設定完了後は、以下のようになっているはずです。
次にトリガー検知時に実行するターゲットを選択します。
ターゲットはSNSトピックを選択し、トピックは先ほど作成したトピックを選択します。
その他の設定は、何も行わなくても大丈夫です。
上記設定完了後、「作成」を選択し設定を完了させます。
作成完了後以下画像のように、ステータスが「Enabled」になっていれば、Event Bridgeの設定は完了です。
7. アプリの作成
ここまででSlackへの通知を行うための設定は、完了しました。
残りは、実際にSlackへ通知を行うためのアプリを作成していきます。
アプリの設定
今回は、TypeScriptを使用して実装を行います。
以下コマンドで、アプリの初期化を行います。
$ mkdir notification-to-Slack // アプリ名
$ cd notification-to-Slack
$ yarn init
$ yarn add typescript
$ tsc — init
次は、Slackへ通知するために、以下プラグインをインストールします。
$ yarn add @slack/web-api
tsconfig.jsonの設定を変更します。
※デフォルトでは、コメントアウトされています。
{
"compilerOptions": {
...
"outDir": "./dist",
...
"baseUrl": "./src",
...
}
}
実装
まずはindex.tsファイルを作成します。
$ mkdir src
$ touch index.ts
作成したindex.tsファイルに以下を追記します。
import { WebClient } from '@slack/web-api';
exports.handler = async(event: any) => {
}
ここから追記するコードは、全てexports.handlerの中に記載していきます。
まずは、以下を追記します。AWS SNSから送られてくる内容をJSONオブジェクトに変換を行います。
※JSON変換処理を複数回行わないと、取得したいデータを上手く取得できませんでした。
const message = JSON.parse(JSON.parse(JSON.stringify(event.Records[0].Sns.Message)))
次は、以下を追記しWebClientの初期化を行います。
Slack用のトークンは、先ほど登録したLambdaの環境変数から取得します。
const web = new WebClient(process.env.SLACK_API_TOKEN);
次は、Slackへ送るメッセージの作成を行います。
メッセージは、Slack Block kitを使えば簡単に作成することができます。
まずは、以下を追記します。
const params: any = {
channel: process.env.SLACK_CHANNEL!,
blocks: [],
attachments: []
}
設定項目の内容は、以下です。
- channel: どのチャンネルにメッセージを送信するか
- block: メッセージの内容を記載
- attachments: ボタンの設定を記載
次は、blocksの中にSlackへ送信する内容を記載していきます。
今回表示させる項目は、以下です。
- リポジトリの名前
- 更新された日時
- アクションの種類
- 結果
- PUSHされたECRのタグ
各項目は、先ほどJSONオブジェクトに変換したSNSのメッセージから取得します。
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repository Name:*"
},
{
"type": "mrkdwn",
"text": message['detail']['repository-name']
},
{
"type": "mrkdwn",
"text": "*Time*:"
},
{
"type": "mrkdwn",
"text": message['time']
},
{
"type": "mrkdwn",
"text": "*Action Type:*"
},
{
"type": "mrkdwn",
"text": message['detail']['action-type']
},
{
"type": "mrkdwn",
"text": "*Result:*"
},
{
"type": "mrkdwn",
"text": message['detail']['result']
},
{
"type": "mrkdwn",
"text": "*Version:*"
},
{
"type": "mrkdwn",
"text": message['detail']['image-tag']
}
]
}
次はSlackへ表示させるボタンを作成します。
今回作成するボタンは2種類です。
- Deployボタン: アプリのデプロイを行う用
- Cancelボタン: アプリの更新をキャンセルする用
attachments: [
{
"callback_id": 'deploy_action',
"text": "Can be reflected in the production",
"actions": [
{
"name": "Deploy",
"text": "Deploy",
"type": "button",
"value": message['detail']['image-tag']
},
{
"name": "Cancel",
"text": "Cancel",
"type": "button",
"value": "cancel_action"
}
]
}
]
Deployボタンのvalueに、イメージタグを渡していますが、これはこのタグに該当するECRで新しくECSタスクを作成するために使用します。
※後々使用するものです。今回は使用しません。
最後に作成したメッセージをSlackへ送信する処理を追記します。
メッセージの生成が完了してから送信を行わせるため、awaitを設定しておきます。
await web.chat.postMessage(params)
全て追記し終わると、以下のようになっていると思います。
import { WebClient } from '@slack/web-api';
exports.handler = async(event: any) => {
const message = JSON.parse(JSON.parse(JSON.stringify(event.Records[0].Sns.Message)))
const web = new WebClient(process.env.SLACK_API_TOKEN);
const params: any = {
channel: process.env.SLACK_CHANNEL!,
text: 'The image shown below has been uploaded',
blocks: [
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Repository Name:*"
},
{
"type": "mrkdwn",
"text": message['detail']['repository-name']
},
{
"type": "mrkdwn",
"text": "*Time*:"
},
{
"type": "mrkdwn",
"text": message['time']
},
{
"type": "mrkdwn",
"text": "*Action Type:*"
},
{
"type": "mrkdwn",
"text": message['detail']['action-type']
},
{
"type": "mrkdwn",
"text": "*Result:*"
},
{
"type": "mrkdwn",
"text": message['detail']['result']
},
{
"type": "mrkdwn",
"text": "*Version:*"
},
{
"type": "mrkdwn",
"text": message['detail']['image-tag']
}
]
},
],
attachments: [
{
"callback_id": 'deploy_action',
"text": "Can be reflected in the production",
"actions": [
{
"name": "Deploy",
"text": "Deploy",
"type": "button",
"value": message['detail']['image-tag']
},
{
"name": "Cancel",
"text": "Cancel",
"type": "button",
"value": "cancel_action"
}
]
}
]
}
await web.chat.postMessage(params).catch(console.error)
}
これで、Slackへ送信する処理の作成は完了です。
8. Lambda への紐付け
作成したアプリをLambdaに紐付けていきます。
今回は、S3オブジェクトをLambdaに紐づけるようにします。
そのためにまずは、作成したアプリをzipファイルにし、S3へアップロードします。
ビルド処理
今回は、シェルスクリプトを作成し、作成したスクリプトでzipファイルを作成します。
まずは、以下コマンドでカレントディレクトリ以下にスクリプト用ファイルを作成します。
$ cd notification-to-Slack
$ touch build.sh
作成したbuild.shに以下処理を記載します。
#!/bin/shecho remove dir and zip
rm -rf notification-to-Slack-dist/
echo compile ts
tsc -p tsconfig.json
echo copy package.json
cp -f ./package.json ./notification-to-Slack-dist
echo install module
cd notification-to-Slack-dist
yarn install
echo zip
zip -r notification-to-Slack-dist.zip ./
build.shでは、以下の処理を行っています。
- 既存のdistファイルを削除
- tsconfigのコンパイル
- ビルド先にpackage.jsonをコピー
- ビルド先にyarnで、node_moduleのインストール
- zipファイルの作成
追記完了後、以下コマンドを実行し、build.shに実行権限を付与します。
$ chmod 777 build.sh
次にpackage.jsonにbuild.shの処理を行うスクリプトを追記します。
{
"name": "update-image-of-ecr",
...
"scripts": {
"build": "sh ./build.sh"
},
...
}
早速スクリプトを実行して、zipファイルが生成されているかを確認しましょう。
$ yarn build
以下のようにzipファイルが生成されていれば成功です。
$ cd notification-to-Slack-dist
$ ls
... notification-to-Slack-dist.zip ...
zipファイルの生成を確認したら、次はこのzipファイルをS3へ保存します。
適当なバケットを作成して、そこにアップロードを行いましょう。
アップロード完了後、今回作成したLambdaのページへ行きLambdaにファイルをアップロードします。
S3のオブジェクトURLを入力して、「保存」を選択します。
これで、全ての設定が完了しました。
早速前回の2章で作成したアプリで、ECRへPUSHを行ってみましょう。
PUSH完了後、Slackに以下のようなメッセージが送信されていれば成功です。
今回、タグ付きとLatestの2つを生成する用にしているので、メッセージは2つ来ます。
今は、ボタンを押しても何も動作しませんが全ての章完了後は、「Deploy」ボタンを押すとECSの更新を行えるようになります。
今回の作業はこれで、全て完了です。
9. おわりに
今回も長くなりましたが、最後まで読んでいただき、ありがとうございます。
今回Slackへのメッセージ送信を行いましたが、完成させると意外と簡単でしたね。
Slackには、他にも面白そうな設定ができそうなので色々カスタマイズするのもおもしろそうです。
次は、いよいよCDK for Terraformを使用してAWSの環境構築を行って行きます。
次の章は、全ての章で一番ボリュームが大きいものになると思いますが、最後まで読んでいただけると嬉しいです。
それでは、次の4章でお会いしましょう。
参考文献
Amazon ECRでAmazon EventBridgeのサポートが追加されましたっ!!
SNSでSlackにメッセージ送信する #slack
Slack api Block kit
We are hiring!
「人口減少社会において必要とされるインターネット事業を創造し、ニッポンを元気にする。」
を理念に掲げ一緒に働く仲間を募集しております。