GitHub Actions (deploy-cloud-functions)を使ってpython関数をGoogle Cloud Functionsにデプロイする

## TL;DR;

- クラウド上でスクレイピングを定期的に実行したかった
- Google Cloud FunctionsとSchedulerを使えば行けそうだった（[お金もかからなさそう](https://cloud.google.com/functions/pricing?hl=ja)）
- Google Cloud Functionsのデプロイが面倒だったので、GitHub Actionsで自動化したかった
- GCP初心者なもので、特に認証周りで引っかかったので、ここを中心に流れをまとめる(GCPに詳しい方は他の方の良い記事(例えば[こちら](https://zenn.dev/himara2/articles/1fb5f955d15679))があります)
- [google-github-actions/deploy-cloud-functions](https://github.com/google-github-actions/deploy-cloud-functions)を使ってみる。

(GitHub Actionsでもcron実行できるみたいだったけど、規約的にいいのかコワかったのでやめました…）

## 大体の流れ

1. GCPにプロジェクト作成
1. 必用な物(Compute Engine API, Cloud Build)を有効化
1. (Cloud Functions 管理者権限付）サービスアカウントを追加
1. ロールの追加。[(参考)](https://qiita.com/gimKondo/items/0c367c093d5dc8694dc6)
1. 鍵の設定
1. GitHub Actionsの設定
1. コードをPush!!

以下、上記それぞれを詳しく書きます


### 1. GCPにプロジェクト作成

[GCP](https://console.cloud.google.com/home/)にアクセスし，下図のような手順で新しいプロジェクトを作成します．

とりあえずプロジェクト名は"My Project"としました．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/b1c01609-a746-135c-2d02-ed23a92592f1.png)

すると作成したプロジェクトを選択できるようになります。

### 2. 必要なものを有効化

2.1 Compute　Engine API：

[ここ](https://console.cloud.google.com/apis/api/compute.googleapis.com/overview?hl=ja&_ga=2.107264834.1538790787.1619702173-475187704.1619697609)にアクセスして、有効化する。結構時間かかる。

2.1 Cloud Build：
[ここ](https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview)にアクセスして有効化。

 
### 3. (Cloud Functions 管理者権限付）サービスアカウントを追加
　1．で作成したGCPプロジェクトにアクセスした後、

**ナビゲーションメニュー(左上) ---> IAMと管理 ---> サービスアカウント**

にアクセスするとこんな感じの画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/2e692634-a900-b947-5975-98792c4a3e6c.png)

1. サービスアカウント名を入力し作成をクリック(gcf-deployとしました)
1. すると、下図のような画面になるので、***Cloud Functions 管理者*** を選択し、一番下の完了ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/21ea1da3-693a-9304-8ab5-ac9a3fb695e6.png)


**ナビゲーションメニュー ---> IAMと管理 ---> IAM**にアクセスする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/e458f88d-1412-6983-4d7f-a5cb808c7874.png)

gcf-deploy@xxxxxxx.iam.gserviceaccont.comが今回作成したサービスアカウントです。
また、xxxxxxxの部分はプロジェクトIDで、xxxxxxx@iam.gserviceaccont.comは自動で作られているメインのアカウントです。
次のステップではこのメインアカウントにロールを一つ追加します。

### 4. ロールの追加

ひとつ前のステップで確認した、メインアカウントにロールを一つ追加しないと、下記の様なエラーが出ます。

> Missing necessary permission iam.serviceAccounts.actAs for $MEMBER on the service account ***@appspot.gserviceaccount.com.

ロールの追加はCloud shellで実行します。
先ほどのページの右上にあるボタンをクリックすると、shellがページ下部に現れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/95d47cf8-3eed-c476-f192-9912ed9a7fde.png)

ターミナルで下記コマンドを実行します。
(*) xxxxxxxの部分は、1つ前の手順で確認したプロジェクトIDに置き換えてください。
また、サービスアカウント名はgcf-deployとしていますが、違う名前を付けた場合は、適宜置き換えてください。

```shell-session
gcloud iam service-accounts add-iam-policy-binding xxxxxxx@appspot.gserviceaccount.com \
  --member='serviceAccount:gcf-deploy@xxxxxxx.iam.gserviceaccount.com' \
  --role=roles/iam.serviceAccountUser
```

### 5.鍵とプロジェクトIDをリポジトリに登録

#### 5.1. まずは、GCPプロジェクトの鍵を生成しましょう。

再び **ナビゲーションメニュー ---> IAMと管理 ---> サービスアカウント**にアクセスする。

先に作成していたサービスアカウントの操作列のボタンをクリックし、***鍵を管理***を選択します。

***鍵を追加 ---> 新しいカギを生成***を選択すると、鍵情報が詰まったjsonファイルのダウンロードが始まります。
GCP上での作業は以上です！

GitHubでの作業にうつります。

#### 5.2. ダウンロードした鍵をリポジトリに登録する。
まずは新しいリポジトリを作成しましょう。

そして、***Settingsタブ ---> Secrets***にいきます。
New project secretを押して、下記の2つのsecretを新たに追加します

```yml
名前：GCP_CREDENTIALS
内容：ダウンロードしたjsonの中身をコピペ

名前：GCP_PROJECT_ID
内容：jsonの中にあるproject_idをコピペ
```




### 6. GitHub Actionsの設定
やっとGitHub Actions用の設定です。

リポジトリのActionsタブに行くと　***set up a workflow yourself***　とあるのでクリックします。

下記をコピペします。

(\*)discord webhookを使いたかったので、Functions側に渡す新たな環境変数を設定しています。
何か設定したい環境変数があったらここで定義しておくといいです。
(\*)複数ある場合はカンマ[区切りで書けるようです](https://github.com/google-github-actions/deploy-cloud-functions)

```yml
name: Deploy Cloud Functions
on:
  # Push時に実行
  workflow_dispatch:
  push:
    branches: [master]

jobs:
  deploy:
    name: Deploy Functions
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - id: deploy
        uses: google-github-actions/deploy-cloud-functions@main
        with:
          ## Google Cloud Functions上での名前
          name: gcf_actions_template 

          ## runtimeの設定．今回はpythonを指定
          runtime: python39 

          ## GCPの鍵．
          credentials: ${{ secrets.gcp_credentials }}　

          ## Functionsにデプロイする関数名
          entry_point: hello_pubsub

          ## Regionの指定．指定しないとエラーが出るかも?
          region: asia-northeast1

          ## Schedulerと組み合わせたいので、FunctionsのトリガータイプをPub/Subにする
          event_trigger_type: providers/cloud.pubsub/eventTypes/topic.publish
          event_trigger_resource: projects/${{ secrets.gcp_project_id }}/topics/my-pubsub-topic

          ## Functions上の環境変数を指定．
          ## Discordにメッセージを送りたいのでWebhookを設定。
          env_vars: DISCORD_WEBHOOK_URL=${{ secrets.discord }}
```

[指定できるruntime一覧](https://cloud.google.com/sdk/gcloud/reference/functions/deploy#--runtime)

[指定できるregion一覧](https://cloud.google.com/functions/docs/locations)

[トリガータイプ指定法](https://cloud.google.com/blog/ja/products/serverless/deploying-serverless-platforms-github-actions)

右上にあるボタンをクリックして設定ファイルをコミット＆プッシュ！


### 7. コードをPush!!

準備は整いました、上記設定ファイル*entry_point*で指定した関数（ここではhello_pubsub）を作成・デバッグして、pushしましょう！

push後リポジトリActionsタブに行くとデプロイが成功したかどうか出ます。

成功していたら、Google Cloud Functionsにアクセスしましょう
(*ナビゲーションメニュー ---> Cloud Functions*)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138642/e87cb381-79c6-d0b7-3225-31c6a29bf0be.png)


いけてる！！