[GCP] CloudFunctionsを使って指定日にLINE送信する仕組みを作ってみた [無料]

こんにちは、毎週火曜日の夕方にオンラインサロンのslackを確認をしないといけない用事があるけど忘れちゃうのでLINE(こちらもGoogleじゃな以下略)に通知したいな〜、お手軽に無料でできないかな〜ということで、
**GCPとLINEmessagingAPIを使って無料で定時にLINE送信するシステム**を、ちゃんと**GCPのベストプラクティス**に沿って作っていくよ！
# アーキテクチャ
アーキテクチャはこんな感じ
![スクリーンショット 2022-03-20 20.11.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/d34e9e58-e30e-69d7-9939-024cd3973524.png)
## アーキテクチャのポイント
### 1. CloudPubSubトリガーで起動
CloudFunctionsはhttpアクセスをトリガーにして実行することもできますが、賢い人たちにはURLを容易に特定されてしまいます。意図せぬ大量アクセスによる課金を防ぐため、PubSubをトリガーにした安心な構成にしています。
### 2. 秘密情報はSecretManagerで管理
LINEmessagingAPIのtokenなどの、流出すると困る大事な情報は**SecretManager**に登録して、CloudFUnctionsで呼び出すのがベストプラクティス！
バージョン管理にも対応してるので、定期的にローテーションして保守性を高めることもできます。
[SecretManagerのベストプラクティス詳細](https://cloud.google.com/secret-manager/docs/best-practices?hl=ja "タイトル")
# LINE系設定
まずLineのアカウントを作成します。
## 1. Line Developersに登録
LineでPush通知を行うためにはLine Developersへの登録が必要です。
以下から登録してください。
https://developers.line.biz/
## 2. Lineチャネルの作成
新しいチャネルの作成から「Messaging API」をクリックしてチャネルを作成してください。
![スクリーンショット 2022-03-20 12.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/cdbf4480-ac7e-fc0d-d29f-a8357ea27402.png)
「Messaging API」タブの中にあるQRコードを読んで、おともだちになってください。
同じページの最下部にtoken発行ボタンがあるので、tokenを発行してください。
![スクリーンショット 2022-03-20 12.44.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/1f4fa6a9-b50a-9687-8c42-8af016b96088.png)
**※tokenは流出させないように気をつけてね！！**
#### 無料枠：月１０００通まで無料
2022年3月現在、月１０００通まで無料で送信することができます。
個人の通知用で使う分には十分かな。
https://at.line.me/jp/plan

# GCPの設定
ここからはGCPで設定をしていきます。
アカウントを持っていない人は作成してね。
## 1. Pub/Subでtopicの作成
サイドメニューからPub/Sub画面に遷移します。
適当な名前をつけて「トピックを作成」をクリックすると、topicが作成されます。
![スクリーンショット 2022-03-20 13.15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/419b22dd-022c-e047-1aba-7f03641b7dba.png)
#### 無料枠：月１０GBのメッセージ送信まで無料
https://cloud.google.com/free/docs/gcp-free-tier/#pub-sub
10GBと言われても全然ピンとこない情報処理弱者な私なので、ちょっと計算してみた。
「UTF-8で日本語はだいたい1文字3バイト！」とどこかの[ブログ](https://xn--tech-fm4cpn7b.sanwasystem.com/entry/2017/11/13/102531)で言っていたので
1GB は 1e+10バイトで、1e+10は100億だから、
100億➗3 = 33.3億文字送信できます！！
![スクリーンショット 2022-03-20 20.48.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/c0bbe5af-f11c-4a33-440b-4b286b7996f2.png)

## 2. Cloud Schedulerでジョブの作成
サイドメニューからCloud Scheduler画面に遷移します。
画面上部の「ジョブを作成」から先ほど作成したPub/Subトピックを呼び出すジョブを作成します。
毎週火曜日の１８時にLINEを送信したいので、このように設定しました。
![スクリーンショット 2022-03-20 13.26.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/66309530-b85b-792d-d463-c1d877b7b30b.png)
#### 無料枠：月3ジョブまで無料
こちらはちょっと数が少ないので、有効に使わないとですね。
https://cloud.google.com/scheduler?hl=ja
## 3. Secret Managerでシークレットの作成
先ほど作成したLINE Messaging APIのtokenを登録します。
サイドメニューからSecret Manager画面に遷移します。
画面上部の「シークレットを作成」から適当な名前をつけて「シークレットの値」にtokenを入力して「シークレットを作成」をクリックします。
![スクリーンショット 2022-03-20 13.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/be58796d-6a40-0e00-91b0-4eb8c7d0aca1.png)
#### 無料枠：月6個のアクティブシークレットバージョンまで無料
正確にはこんな感じ
> 6 個のアクティブ シークレット バージョン（1 か月あたり）
> 10,000 回のアクセス オペレーション（1 か月あたり）
> シークレット ローテーション通知: 1 か月あたり 3 回
https://cloud.google.com/free/docs/gcp-free-tier/#secret-manager
## 4. サービスアカウントの作成
CloudFunctionsからSecretManagerにアクセスするための、サービスアカウントを作成します。
左メニューの「IAMと管理」内の「サービスアカウント」に遷移します。
画面上部の「サービスアカウントを作成」をクリックし、ロールに「Secret Managerのシークレットアクセサー」を付与します。
![スクリーンショット 2022-03-20 15.52.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/62aa60be-f091-87dd-6020-f1ead1f1d9e8.png)
## 5. Cloud Functionsの作成
サイドメニューからCloudFunctions画面に遷移します。
上部の「関数を作成」をクリックします。
### 5.1. トリガー設定
適当な関数名をつけて、トリガーに先ほど作成したPub/Subを設定します。
![スクリーンショット 2022-03-20 19.17.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/5a0619f1-0132-14c9-44b8-a4bde7af318d.png)
### 5.2. ランタイムサービスアカウント設定
ランタイムサービスアカウントに先ほど作成したSecretManagerへのアクセス権限を付与したサービスアカウントを設定します。
![スクリーンショット 2022-03-20 19.15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/c99744aa-bfeb-6071-e82f-6492d63d9518.png)
### 5.3. 処理の設定
ソースはこんな感じ
```python:main.py
import base64
import json
import requests
from google.cloud import secretmanager

def hello_pubsub(event, context):
    # pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    # print(pubsub_message)

    # secretmanagerからtoken取得
    token = access_secret_version()

    # LINE送信
    send_line(token)


def access_secret_version():
    # Create the Secret Manager client.
    client = secretmanager.SecretManagerServiceClient()

    # Build the resource name of the secret version.
    name = f"projects/{プロジェクト番号}/secrets/token_line_notice/versions/latest"

    # Access the secret version.
    response = client.access_secret_version(request={"name": name})

    # Print the secret payload.
    payload = response.payload.data.decode("UTF-8")

    return payload

def send_line(token):
    # header
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer ' + token
    }

    # message
    message = {
        'messages':[
            {
                'type': 'text',
                'text': 'サロンのSlackをチェックしてね！'
            }
        ]
    }
                
    # LINE API アクセス
    requests.post('https://api.line.me/v2/bot/message/broadcast', headers=headers, data=json.dumps(message))
```
※「{プロジェクト番号}」には皆さんのGCPのプロジェクト番号を入力してください。
ライブラリの読み込みはこんな感じ
```python:requirements.txt
google-cloud-secret-manager>=2.7.2
```
#### 無料枠：月200万回の呼び出しまで無料
正確にはこんな感じですが、週１回の呼び出しなので、余裕ですね！
> 200 万回の呼び出し（1 か月あたり、バックグラウンド呼び出しと HTTP 呼び出しを含む）
> 400,000 GB 秒、200,000 GHz 秒のコンピューティング時間
> 5 GB の下り（外向き）ネットワーク（1 か月あたり）
https://cloud.google.com/free/docs/gcp-free-tier/#cloud-functions
# 実際に動かしてみる
サイドメニューからCloud Scheduler画面に遷移して「今すぐ実行」をクリック
![スクリーンショット 2022-03-20 13.56.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/77201cc9-b632-09e1-5a88-91697bf7877a.png)
## LINEが送信されればOK
![スクリーンショット 2022-03-20 20.13.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2548921/91874c1a-c7cf-985c-8943-4a2f5d57c98e.png)


以上！

GCPを使えば無料で簡単にLINE通知システムが作れちゃうので、
みんなもGoogleを活用してみましょう！