Google Cloud Functionを使ってSlack通知ツールを作ってみた

2023年1月27日掲載

キービジュアル_Google Cloud Function slack

サーバレスサービスは非常に便利です。

仮想コンピューティングを準備しなくても、開発者は好きな言語による関数コードを綴るだけで、サーバレスがHTTP Requestやタイマートリガー、APIアクセス等に応じて自動処理し、その結果を返答するため、仮想コンピューティングのランニングコストを削減しつつ、様々な組み合わせやシナリオを実現することができます。

今回はそのシナリオの一つとして、Google Cloudのサーバレスプロダクトサービス Cloud Functionsがタイマートリガーをベースに外部からJSONデータを取得、その結果をSlackへ通知する仕組みを作ってみます。

目次

1. 全体構成図

全体構成図は次の通りになります。ゴールは一定時刻になると天気予報を通知するものです。

Google Cloud Function slack_全体構成図

Cloud Functions単体にはタイマートリガーがないため、Cloud Functionsを予め指定した日時・時刻にてFunctions関数を定期実行するには、Cloud SchedulerおよびCloud Pub/Subと連携して実行する必要があります。

流れとして、Cloud SchedulerでCronスケジュールによる定期的な実行処理を行い、それをCloud Pub/Subが受け取って、Cloud Pub/SubをトリガーにCloud Functionsを実行します。

2. 参考:Slack - サーバレスでできることの例

上記は非常に簡単な例ですが、この流れら基本を抑えておけば、次のようなシナリオを実現することができます。

Stable Diffusionを使って、チャットでBotが画像を生成して返却するサービス

家計簿DWHへSQLクエリで取得、およびGoogle spreadsheetsと連携してChart自動作成・表示

レシートをGoogle スプレッドシートの家計簿へ自動反映の最中に異常検知アラート発信

クラウドサービス等の料金通知

Slackは対話型チャットベースでさまざまなサービスと連携できるため、上記を含め、さまざまなシナリオを簡単に実現することができます。コツは、Slack入力を検知するPythonスクリプト、およびSlackへ通知するPythonスクリプトを上手く生かすことです。今回はその一歩として、サーバレスからPythonスクリプトによって通知する簡単な仕組みを作ってみます。

3. Slackの設定

今回はSlack上にBotを作成しますので、Slackアカウント、利用したいサービスのワークスペース、およびslack連携には Slack AppとIncoming webhook URL の発行が必要です。

もし、Slackアカウント、利用したいサービスのワークスペース、Slack AppとIncoming webhook URLを持っている場合は、「4. Cloud Pub/Subサービスの準備」へお進みください。

3-1. Slackアカウント&ワークスペース作成

Slackアカウントを準備します。

https://slack.com/

Google Cloud Function_slack設定

Slackアカウントの準備ができたら以下のリンクを開き、ワークスペースを作成します。

https://slack.com/get-started#/createnew

Google Cloud Function_slack設定_1

今回はワークスペース名を「ServerlessToSlack」という名前にします。

Google Cloud Function_slack設定_2

表示された指示に従い、ワークスペースを作成し、起動します。

Google Cloud Function_slack設定_3

チャンネルを作成します。チャンネル名は何でも良いので、今回は「weatherchannel」にします。

Google Cloud Function_slack設定_4

3-2. Slackアプリ設定

ワークスペースが完成したら、今度はそのワークスペースとFunctionComputeを連携するための、Slackアプリ設定をします。

https://api.slack.com/apps にアクセスし、「Create an APP」をクリックしてSlackアプリを作成します。

Google Cloud Function_slack設定_5

「From scratch」をクリックします。

Google Cloud Function_slack設定_6

AppNameを設定し、ワークスペースを選択します。

Google Cloud Function_slack設定_7

「Incoming Webhooks」を選択します。

Google Cloud Function_slack設定_7

「Incoming Webhooks」をオンにします。

Google Cloud Function_slack設定_8

「Incoming Webhooks」をオンにすると、メニューの表示内容が変わります。

Google Cloud Function slack_2

Webhooksをワークスペースに追加します。

Google Cloud Function slack_1

チャンネルを選択し「許可する」ボタンをクリックして許可します。

Google Cloud Function_slack設定_8

Incoming Webhooksを保存します。これでSlack App設定は完了です。

Google Cloud Function_slack設定_9

最後に、Slack App設定にてWebhook URLがありますが、こちらはサーバレス側から通知するために必要なURLなので手元に置くようにします。

4. Cloud Pub/Subサービスの準備

Slack側の準備は完了したので、今度はサーバレス側の準備を進めます。

先述の通り Google Cloud Functions はタイマートリガーがないため、Cloud Scheduler および Cloud Pub/Subと連携して実行する必要があります。流れとして、Cloud SchedulerでCronスケジュールによる定期的な実行処理を行い、それを Cloud Pub/Subが受け取って、Cloud Pub/SubをトリガーにCloud Functionsを実行します。

まずは橋渡し役となる Cloud Pub/Sub を準備します。
Cloud Pub/sub画面にて「Create a topic」ボタンで、デフォルト設定(Add a default subscription)で新規Topicを作成します。

Google Cloud Function_設定_9

新規Topicが作成されたら、Cloud Pub/Sub画面では次のような画面になります。

Google Cloud Function_設定_10

5. Cloud Functionsサービスの準備

Cloud Pub/Subの準備ができたら、今度はCloud Functionsの準備をします。

Cloud Functionsコンソール画面にて「Create Functions」ボタンをクリックすると、画面の通りに①Configuration画面が表示されます。そこにて新規Functions関数リソースの設定事項を入力します。Environmentはそのままにしつつ、Functions nameおよび対象Regionを入力します。

Google Cloud Function_設定_11

続いて、Trigger欄で今回はCloud Pub/Subをトリガーとしながら実行するため、Trigger Typeを「Cloud Pub/Sub」、Topicを先ほど作成したPub/Subリソースを選定し、「Save」をクリックして保存します。

Google Cloud Function_設定12

①Configuration画面の入力が完了したら、[Next]をクリックし、②Code 画面へ遷移します。

Google Cloud Function_設定13

今回はPythonを使うので、RuntiomeをPython3.9に選定し、コード環境を変えます。

コード環境を切り替えることができたら、コードを編集します。

Google Cloud Function_設定_14

main.pyは以下のコードへ入れ替えます。なおslack_endpointはwebhook URLに設定します。

import base64
import urllib3
import json
 
http = urllib3.PoolManager()
 
slack_endpoint = ""
weather_endpoint = "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/130000.json"
 
 
def hello_pubsub(event, context):
    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    print(pubsub_message)
    message = "test message: {0}".format(pubsub_message)
    weather_result = get_weather()
    if weather_result["success"]:
        weather_msg = compose_weather_message(weather_result["data"])
        forward_slack_message(weather_msg)
    else:
        weather_msg = weather_result["error_message"]
    forward_slack_message(weather_msg)
 
 
def forward_slack_message(message_content):
    msg = {
        "channel": "#weatherchannel",
        "username": "nancy",
        "text": message_content,
        "icon_emoji": ""
    }
    encoded_msg = json.dumps(msg).encode('utf-8')
    resp = http.request('POST', slack_endpoint, body=encoded_msg)
    print({
        "message": "test message: {0}".format(message_content),
        "status_code": resp.status,
        "response": resp.data
    })
 
 
def compose_weather_message(weather):
    return "*{0}  _{1}_  {2} 地域の天気情報です*\n{3}\n{4}".format(
        weather['publishingOffice'],
        weather['reportDatetime'],
        weather['targetArea'],
        weather['headlineText'],
        weather['text']
    )
 
 
def get_weather():
    result = {"success": True, "error_message": "OK"}
    try:
        resp = http.request(method="GET", url=weather_endpoint, headers={"Content-Type": "application/json"})
        if resp.status == 200 and resp.data:
            weather = json.loads(resp.data)
            print(weather)
            result["data"] = weather
        else:
            msg = "Failed get weather, response code: {0}, response: {1}".format(resp.status, resp)
            print(msg)
            result["success"] = False
            result["error_message"] = msg
        return result
    except Exception as e:
        result["success"] = False
        result["error_message"] = str(e)
        print("Failed getting weather information.")
    return result
 

続いて、requirements.txt では、Google Cloud Functionsに入れておきたい依存関係を指定します。今回のソースコードではHTTP通信を行うためのurllib3パッケージが必要なので、urllib3を入れるようにします。

urllib3=1.26.11
Google Cloud Function_設定_15

ここまでの設定で問題なければ、テストとして手動実行用の「Deploy」ボタンをクリックします。

Google Cloud Function_設定_16

手動実行によるDeploy結果として、Slack側で天気予報が通知されるようになります。

6. Cloud Schedulerの準備

Cloud Functionsで手動による天気予報をslack通知が出来るようになったので、今度はCloud SchedulerでCronによる定例ジョブの設定をします。

コンソール画面からCloud Scheduler画面へ遷移します。

Schedule a Jobボタンをクリックし、新しくスケジュールを作成します。
この「Define the schedule」画面にて、Name、Region、Timezon、Frequencyを入力します。Frequencyは「頻度」のことで、cron形式で指定する必要があります。ここでは毎朝9時おきに実行されるように設定します。

設定が完了したら「CREATE」ボタンをクリックし、スケジュール設定を完了します。

これで指定したタイミングでタスク(Job)が実行されます。
この設定によって日本時間の毎日9時に天気情報を自動的に発信できます。

テスト用に手動で「今すぐ実行」で任意のタイミングでのタスク(Job)実行をすることもできます。Jobバー側のActionタブから、Force a job runをクリックし、タスク(Job)を手動実行します。

手動実行ステータスを確認します。

Slackで天気情報のメッセージが届くようになりました。

7. さいごに

SlackとGoogle Cloud Functionsの組み合わせにより、天気予報情報を自動で通知する方法をご紹介しました。Google Cloud Functionsのみ、タイマートリガーがなく、Cloud SchedulerとCloud Pub/Subで実現する必要がありますので、この勘所を押さえていただければ幸いです。

本記事は非常に簡単かつ、10分もしないで作り上げることができるので、サーバレスを始める方にはちょうど良いハンズオントレーニングかもしれません。

また、上記関数コードは天気予報情報を取得して通知する処理ですが、このコードをアレンジして、ニュースを通知したり、近所スーパーのセール情報を通知したり、クラウドの障害を通知したり、などなどさまざまなシナリオを満たすことができますので、ご参考になれば幸いです。

参考記事

関連サービス

Google Cloud

Google サービスを支える、信頼性に富んだクラウドサービスです。お客さまのニーズにあわせて利用可能なコンピューティングサービスに始まり、データから価値を導き出す情報分析や、最先端の機械学習技術が搭載されています。

MSPサービス

MSP(Managed Service Provider)サービスは、お客さまのパブリッククラウドの導入から運用までをトータルでご提供するマネージドサービスです。

おすすめの記事

条件に該当するページがございません