げっとシステムログ

WEB開発メモ

Slack Bot でデプロイする

Slack Bot にデプロイを頼めるようにしたい。

CONTENTS
  1. できあがったもの
  2. デプロイ
  3. 実装詳細
  4. まとめ
  5. 参考資料

できあがったもの

Slack Bot 用エンドポイント

Slack イベントを受け取ってイベントに応じたアクションをする。

  • 「リリース」、「release」を含む mention を受け取った場合、対応する GitLab trigger を POST
  • 「よろ」を含む mention を受け取った場合、Slack に返信
  • その他の mention を受け取った場合、Slack に返信

デプロイ完了通知エンドポイント

独自のイベントを受け取ってイベントに応じたアクションをする。

  • source=gitlab で result=[success|failure] を受け取った場合、Slack に返信

TOP

デプロイ

  • Slack channel に Bot User を招待
  • シークレットの slack-bot-token に Slack Bot トークンを保存
  • シークレットの gitlab-trigger-tokens に GitLab のトリガートークンを保存
  • .gitlab-ci のワークフローに deploynotify を追加

GitLab のトリガートークンは以下のような json で保存する。

{
  "TEAM-ID": {
    "CHANNEL-ID": {
      "PROJECT": { "project_id": "PROJECT-ID", "token": "TRIGGER-TOKEN" }
    }
  }
}

.gitlab-ci.yml は以下のようにする。

stages:
  - deploy
  - notify

deploy:
  stage: deploy
  only:
    refs:
      - triggers
    variables:
      - $RELEASE

  image: buildpack-deps:disco-scm

  script:
    - ./bin/deploy.sh

deploy_success:
  stage: notify
  only:
    refs:
      - triggers
    variables:
      - $RELEASE
  when: on_success

  image: buildpack-deps:disco-curl

  script:
    - ./bin/notify.sh success

deploy_failure:
  stage: notify
  only:
    refs:
      - triggers
    variables:
      - $RELEASE
  when: on_failure

  image: buildpack-deps:disco-curl

  script:
    - ./bin/notify.sh failure

notify.sh は以下のようなスクリプトを用意する。

#!/bin/bash

result=$1

echo "$result : $channel / $timestamp"
curl "$NOTIFY_URL?$NOTIFY_TOKEN=true&source=gitlab&result=$result&channel=$channel&timestamp=$timestamp"
  • $NOTIFY_URL : デプロイ完了通知エンドポイントの URL を指定する
  • $NOTIFY_TOKEN : API Gateway で設定したパラメータを指定する

それぞれ、GitLab の Variables で設定できる。

deploy.sh でデプロイを実行することで Slack Bot への mention でデプロイできるようになる。

TOP

実装詳細

handler

slack_bot_event に応じて conversation を行う。 typemention の場合は handlers/mention.js がハンドリングする。

会話を行うには message.channels 用のハンドラを用意する必要がある。 このハンドラでは、なんらかの状態を保存してリクエストを直列化する必要があるはず。 スレッドを使用することでそれほど複雑にしないで実装できる可能性はある。

slack_bot_event

aws lambda から渡された生の json をハンドリングしやすいように加工したイベントオブジェクト。

conversation

イベントオブジェクトから情報を取り出して会話を行う。

実際の処理は progressjobreplyer に委譲する。

progress

会話の処理がすでに開始されているかどうかを session に問い合わせることで判定する。 mention は1回でも、Slack からの通知が複数回飛んでくることがあるため、すでに開始した処理については無視する。

おそらく、レスポンスステータスが 200 でなかった場合に Slack が同じ内容でエンドポイントを叩くのだと考えている。 もう少し丁寧なエラー処理が必要なのだろう。

job

deployment からデプロイする対象を取得できた場合、pipeline にデプロイの実行を依頼する。

replyer

メッセージや絵文字のリアクションを stream に返信する。

repository

session

uuid_store から uuid を取得し、document_store に会話を登録する。 この時、会話の ID (team, channel, timestamp) がすでに登録されていた場合は uuid の登録は行わない。

document_store から uuid を再取得することで、すでに処理が開始されていないことを確認する。

deployment

secret_store に登録されている token から、デプロイ可能な対象を取得する。

pipeline

指定された対象のデプロイを job_store に依頼する。 デプロイ用のトークンは secret_store から取得する。

stream

指定されたメッセージを message_store に流す。 投稿用のトークンは secret_store から取得する。

infra

  • uuid_store : uuid を生成
  • document_store : AWS DynamoDB から会話データを取得
  • secret_store : AWS Secrets からトークンを取得
  • job_store : GitLab API を通じてデプロイ job を開始
  • message_store : Slack API を通じてメッセージを投稿

TOP

まとめ

Slack Bot に mention を飛ばすことでデプロイできるようにしてみた。

これまでは shell スクリプトでデプロイしていたので、開発者がスクリプトを叩く必要があった。 また、デプロイするブランチを master 以外にしてしまうことも不可能ではなかった。

Slack Bot の mention でデプロイすることで、master からのデプロイを強制できるようになった。

TOP

参考資料

TOP