皆さんCloudRunを使っていますか?
素早くDocker環境に秒単位でデプロイができるこのサービスに私はメロメロです。
で本日はCloudRunを使ってSlackBot (Bolt)を導入して簡単なスラッシュコマンドを作成してみたい。と思います。
完成品は /ping
コマンドを発行したらbotから pong
が返ってくるものを作成します
事前に必要なもの
- GCPのアカウント及び下記サービスのPermissionが必要になります
- Slack Appsを作成できるPermission
使うもの
SlackBotにかかる料金についての試算目安
- Cloud Run
- Cloud Build
について説明します。この他にStorageの料金等細かい部分が発生しますが、省略させていただきます。
CloudRunの料金について
料金はシンプルです。
公式 GCP CloudRun 料金より
課金はメモリ(GB)秒単位で課金されていきますが、無料枠(月あたり)が
最初の 180,000 vCPU 秒は無料
ありますので50時間分は無料枠になります。
GB 秒単位が用いられています。GB 秒とは、たとえば 1 GB のインスタンスを 1 秒間実行することです。これは 256 MB のインスタンスを 4 秒間実行することとも言い換えられます。vCPU 秒 単位にも、同じ原則が当てはまります。
なので例えば256MBのメモリで平均で1秒でレスポンスを返すCloudRunを実行する場合は
180000(秒) / (256MB) * 4 / 60(分) / 60(時間) = 12.5(時間)
約12.5時間分の無料枠が使えます。
SlackBotでこの位の時間を使い切るのはeventなどで発言をpollingしない限りは難しいとおもいますのでほぼ無料枠で収まると思います。
Cloud Buildの料金について
CloudRunのコンテナイメージをBuildする時に使用します。
使わなくてもCloudRun自体は使えますが、便利なので是非使って下さい。
デフォルトのマシンタイプ(n1-standard-1 1vCPU, 3.75Memory)ならば
公式 GCP Cloud Build 料金より
1 日あたり最初の 120 ビルド分は無料です。
なので超頻繁にデプロイしない限りは無料でいけそうです。
SlackBotを作成する手順
ではSlackBotを作成してみましょう。
Slack Appsを作成する
- アプリを作成する
- トークンとアプリのインストール
迄を済まして下さい。
後で
export SLACK_SIGNING_SECRET=<your-signing-secret>
と
export SLACK_BOT_TOKEN=xoxb-<your-bot-token>
を使います。
Slack Bolt(ローカルを)動かすまで
とりあえずdocker-composeでBoltが動くところまでやります
Dockerfileを作成する
FROM node:10.22.0-stretch
WORKDIR /app
ARG STAGE
ENV STAGE=${STAGE}
COPY package.json /app/package.json
COPY package-lock.json /app/package-lock.json
COPY tsconfig.json /app/tsconfig.json
COPY envs/.env.$STAGE /app/envs/.env.$STAGE
COPY src/ /app/src
RUN mkdir dest/ && npm i && npm run build
CMD ["npm", "start"]
続いてdocker-compose.yaml
(注意事項としてCloudRunのデフォルトのポート待受は8080です)
version: '3'
services:
app:
container_name: "bot"
build:
dockerfile: Dockerfile
context: ./
args:
STAGE: dev
volumes:
- ./:/app
ports:
- "8080:8080"
tty: true
stdin_open: true
NodeJSの設定
pakage.jsonを作成します(TypeScriptで動作させるのでこんな感じで)
{
"name": "{app name}",
"version": "1.0.0",
"description": "",
"main": "dest/index.js",
"scripts": {
"start": "node dest/index.js",
"build": "tsc",
"build:watch": "tsc --watch"
},
.
.
"devDependencies": {
"@types/node": "^13.11.1"
},
"dependencies": {
"@slack/bolt": "^2.1.1",
"dotenv": "^8.2.0",
"typescript": "^3.8.3"
},
...
}
インストール
$ npm i
続いてtsconfig.json(お好みがあると思うのでよしなに)
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"sourceMap": true,
"outDir": "./dest",
"strict": true,
"moduleResolution": "node",
"noUnusedLocals": true
},
"typeRoots": [
"node_modules/@types"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modeles"
],
"compileOnSave": true,
"types": [
"src/types/*"
],
"rules": {
"eofline": true
}
}
ディレクトリを作成する
$ mkdir dest src envs
SlackBotのSecret情報をdotenvに記載する
$ touch envs/.env.dev .gitignore
# secret情報なのでコミットしないためのおまじない
$ echo "envs/.env.dev" >> .gitignore
SLACK_SIGNING_SECRETとSLACK_BOT_TOKENはSlack Appページから取得できます。
SLACK_SIGNING_SECRET=<your-signing-secret>
SLACK_BOT_TOKEN=<your-bot-token>
APP_LISTEN_PORT=8080
src/index.tsを書く
import { App } from "@slack/bolt";
import * as dotenv from 'dotenv';
dotenv.config({ path: `envs/.env.${process.env.STAGE}` });
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
(async () => {
// Start your app
await app.start(process.env.APP_LISTEN_PORT);
console.log('⚡️ Bolt app is running!');
app.command('/ping', async ({ command, ack, say, respond }) => {
console.log(command);
// コマンドリクエストを確認
await ack();
await say(`pong`);
});
})();
ここまででこんな感じのディレクトリになっていると思います。
$ tree -L 2 -I 'node_modules'
.
├── Dockerfile
├── dest
├── docker-compose.yaml
├── envs
│ └── .env.dev
├── package.json
├── src
│ └── index.ts
└── tsconfig.json
Docker Build && Up
下記の様なメッセージが出ればOKです。
$ docker-compose build
$ docker-compose up
> node dest/index.js
⚡️ Bolt app is running!
Cloud Runにデプロイする
GCRにDocker Imageをpushする
Cloud Buildの設定を書いていきます。
<your app name>
の部分はGCRのリポジトリになりますのでよしなに書き換えて下さい。
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-f', 'Dockerfile',
'-t','gcr.io/$PROJECT_ID/vqbot/${_STAGE}',
'--build-arg', 'STAGE=${_STAGE}',
'.'
]
substitutions:
_STAGE: dev
images:
- 'gcr.io/$PROJECT_ID/<your app name>/dev'
GCRにpush
-
<your GCP project>
は自分のGCP projectを指定して下さい
export STAGE=dev
export PROJECT=<your GCP project>
gcloud builds submit \
--project="$PROJECT" \
--config cloudbuild.yaml
コンソールからCloud Buildの経過が出力されるので終了するのをお待ち下さい。
Cloud Runにデプロイ
-
<your GCP project>
は自分のGCP projectを指定して下さい -
<your service name>
は Cloud Runの名前になります -
--allow-unauthenticated
はCloud RunのURLが公開されるオプションです
export STAGE=dev
export SERVICE_NAME=<your service name>
export PROJECT=<your GCP project>
gcloud run deploy $SERVICE_NAME \
--project="$PROJECT" \
--image="gcr.io/$PROJECT/$SERVICE_NAME/$STAGE" \
--platform=managed \
--region=asia-northeast1 \
--allow-unauthenticated
GCP Console Cloud Runのページへいく
open https://console.cloud.google.com/run?hl=ja&project=$PROJECT
こんな感じの結果になります。
デプロイされたURLにアクセスして Cannot GET /
が表示されることを確認してください(Slack BotのコマンドはPostで受け付けるのでboltの内部で動いているexrepssがレスポンスを返してくれれば良いです)
SlackAppsでSlashCommandを作成する
これでやっと外部に公開されているURLが生成できたのでSlashCommandの設定ができます。
Slack Apps ページに再びいき Create New Command
でコマンドを新規作成します
Request URLに関する注意点
SlackBoltはデフォルトで https://{ドメイン}/slack/events
というpathでSlackからの応答を待ちますので
{Cloud RunのURL}/slack/events
という形式で入力してください。
Botをチャンネルにinviteする
Botを実行したいチャンネルにinviteしないとレスポンスを返してくれませんのでBotを動作させたいSlack チャンネルで
/invite @{botの名前}
でinviteして下さい。
動作確認
スラッシュコマンドを実際に動かしてみたい。と思います
/ping
お疲れ様でした。
最後に
Boltのチュートリアルですとglitch等の紹介方法があるかと思いますが、CloudRunでもかなり高速に動作確認をすることができると思います。
Cloud Functionsに比べて自由度が高いCloud Runで素敵なBot生活をお楽しみいただけたら。と思っています。