フォーム読み込み中
サーバレスサービスは非常に便利です。
仮想コンピューティングを準備しなくても、開発者は好きな言語による関数コードを綴るだけで、サーバレスがHTTP Requestやタイマートリガー、APIアクセス等に応じて自動処理し、その結果を返答するため、仮想コンピューティングのランニングコストを削減しつつ、様々な組み合わせやシナリオを実現することができます。
今回はそのシナリオの一つとして、Google Cloudのサーバレスプロダクトサービス Cloud Functionsがタイマートリガーをベースに外部からJSONデータを取得、その結果をSlackへ通知する仕組みを作ってみます。
全体構成図は次の通りになります。ゴールは一定時刻になると天気予報を通知するものです。
Cloud Functions単体にはタイマートリガーがないため、Cloud Functionsを予め指定した日時・時刻にてFunctions関数を定期実行するには、Cloud SchedulerおよびCloud Pub/Subと連携して実行する必要があります。
流れとして、Cloud SchedulerでCronスケジュールによる定期的な実行処理を行い、それをCloud Pub/Subが受け取って、Cloud Pub/SubをトリガーにCloud Functionsを実行します。
上記は非常に簡単な例ですが、この流れら基本を抑えておけば、次のようなシナリオを実現することができます。
Slackは対話型チャットベースでさまざまなサービスと連携できるため、上記を含め、さまざまなシナリオを簡単に実現することができます。コツは、Slack入力を検知するPythonスクリプト、およびSlackへ通知するPythonスクリプトを上手く生かすことです。今回はその一歩として、サーバレスからPythonスクリプトによって通知する簡単な仕組みを作ってみます。
今回はSlack上にBotを作成しますので、Slackアカウント、利用したいサービスのワークスペース、およびslack連携には Slack AppとIncoming webhook URL の発行が必要です。
もし、Slackアカウント、利用したいサービスのワークスペース、Slack AppとIncoming webhook URLを持っている場合は、「4. Cloud Pub/Subサービスの準備」へお進みください。
Slackアカウントを準備します。
Slackアカウントの準備ができたら以下のリンクを開き、ワークスペースを作成します。
今回はワークスペース名を「ServerlessToSlack」という名前にします。
表示された指示に従い、ワークスペースを作成し、起動します。
チャンネルを作成します。チャンネル名は何でも良いので、今回は「weatherchannel」にします。
ワークスペースが完成したら、今度はそのワークスペースとFunctionComputeを連携するための、Slackアプリ設定をします。
https://api.slack.com/apps にアクセスし、「Create an APP」をクリックしてSlackアプリを作成します。
「From scratch」をクリックします。
AppNameを設定し、ワークスペースを選択します。
「Incoming Webhooks」を選択します。
「Incoming Webhooks」をオンにします。
「Incoming Webhooks」をオンにすると、メニューの表示内容が変わります。
Webhooksをワークスペースに追加します。
チャンネルを選択し「許可する」ボタンをクリックして許可します。
Incoming Webhooksを保存します。これでSlack App設定は完了です。
最後に、Slack App設定にてWebhook URLがありますが、こちらはサーバレス側から通知するために必要なURLなので手元に置くようにします。
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を作成します。
新規Topicが作成されたら、Cloud Pub/Sub画面では次のような画面になります。
Cloud Pub/Subの準備ができたら、今度はCloud Functionsの準備をします。
Cloud Functionsコンソール画面にて「Create Functions」ボタンをクリックすると、画面の通りに①Configuration画面が表示されます。そこにて新規Functions関数リソースの設定事項を入力します。Environmentはそのままにしつつ、Functions nameおよび対象Regionを入力します。
続いて、Trigger欄で今回はCloud Pub/Subをトリガーとしながら実行するため、Trigger Typeを「Cloud Pub/Sub」、Topicを先ほど作成したPub/Subリソースを選定し、「Save」をクリックして保存します。
①Configuration画面の入力が完了したら、[Next]をクリックし、②Code 画面へ遷移します。
今回はPythonを使うので、RuntiomeをPython3.9に選定し、コード環境を変えます。
コード環境を切り替えることができたら、コードを編集します。
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
ここまでの設定で問題なければ、テストとして手動実行用の「Deploy」ボタンをクリックします。
手動実行によるDeploy結果として、Slack側で天気予報が通知されるようになります。
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で天気情報のメッセージが届くようになりました。
SlackとGoogle Cloud Functionsの組み合わせにより、天気予報情報を自動で通知する方法をご紹介しました。Google Cloud Functionsのみ、タイマートリガーがなく、Cloud SchedulerとCloud Pub/Subで実現する必要がありますので、この勘所を押さえていただければ幸いです。
本記事は非常に簡単かつ、10分もしないで作り上げることができるので、サーバレスを始める方にはちょうど良いハンズオントレーニングかもしれません。
また、上記関数コードは天気予報情報を取得して通知する処理ですが、このコードをアレンジして、ニュースを通知したり、近所スーパーのセール情報を通知したり、クラウドの障害を通知したり、などなどさまざまなシナリオを満たすことができますので、ご参考になれば幸いです。
・サーバレスってなに?Alibaba Cloud, AWS, Azure, Google Cloud のサーバレスサービスを比べてみました
・クラウド利用料の削減方法とツールを紹介 (Alibaba/AWS/Azure/Google)
・サーバレスKubernetesを活用する理由ってなに?Alibaba, AWS, Azure, Google Cloudで比較してみました【前編】
・Google Cloud FunctionsにZIPファイル化したNode.jsおよびPythonのコードをデプロイしてみた(GUI編)
・Google Cloud FunctionsをGoogle Cloud CLIベースでNode.jsおよびPythonそれぞれをデプロイしてみた(CLI編)
条件に該当するページがございません