GCPのCloud Run 関数でシンプルなAPIを作成してみた

# 概要

初めてGoogleの`Cloud Run`でAPIを作成したので備忘録として手順をまとめます。

個人的にサイボウズ社のkintoneで、JavaScriptの埋め込みやプラグインだけでは実現が難しい、自社事業に特化した機能を取り入れたかったため、Cloud Runを利用して自分の要件に合ったAPIを作成することにしました。

今回はテストとしシンプルなAPIとして、特定の指定したIPからリクエストを受け取ると「こんにちは」と返すものをテスト的に作ってみました。作りながら調べた内容も載せていきます。

## その前に、Cloud Runとは？
Cloud Runは、コンテナベースのアプリケーションをサーバーの設定や管理を意識することなくデプロイし、スケーリングを自動で行ってくれるサービスです。**リクエストがあった場合にだけ処理を行うため、無駄なリソースを消費せず、コスト効率が良い**のが特徴です。

`AWS`でも似たようなサービスとして`Lambda`や`Fargate`があります。

| サービス        | アプローチ              | 特徴・違い                                                                                                   |
|-----------------|-------------------------|--------------------------------------------------------------------------------------------------------------|
| **Cloud Run**   | コンテナベース、サーバーレス | 簡単にコンテナをデプロイ可能。サーバーの管理やスケーリングが不要で、リクエストがある時のみ処理するため、コスト効率が高い。 |
| **AWS Lambda**  | 関数ベース、サーバーレス  | 関数実行に特化し、短い処理時間に適しているが、コンテナベースのアプリケーション実行には不向き。                  |
| **AWS Fargate** | コンテナオーケストレーション | コンテナを実行可能だが、インフラ管理やタスクの設定が複雑。Cloud Runに比べて導入コストが高く、管理負担が大きい。 |

つまり、Cloud Runは簡単にデプロイできる点でサーバー管理の負担を減らしたい開発者に適しています。

例えば、次のようなAPIを簡単に作成できます。
- Webサイトのバックエンドで動作するAPI
- データ処理や計算を行うバックグラウンド処理
- IoTデバイスのデータ送信先

## Cloud Run API構築の手順

### 1: 新しいCloud Runサービスを作成
- GCPコンソールにアクセスし、Cloud Runのダッシュボードに移動します。
    - https://console.cloud.google.com/functions/list
- 上から「ファンクションを作成」をクリック。
-  構成を設定していきます
-  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/e75b4e56-ceeb-c139-8af3-fcdf5dc3cba6.png)
    -  関数名を設定します（例：respondToAuthorizedIP）
    -  リージョンを選択します（例:asia-northeast1（東京））
    -  トリガーの種類を選択します（例:HTTPS）
        -  HTTPを選ぶと、外部からのHTTPリクエストに応じて関数が呼び出されます。
    - 認証の設定をします（例:未認証の呼び出しを許可）
        - 未認証の呼び出しを許可
            - 誰でも関数を呼び出せるようにします。テストや一般公開のAPIなどには便利ですが、セキュリティリスクがあります。
        - 認証が必要
            - 呼び出す際に認証を必要とします。APIを特定のユーザーやサービスアカウントに制限する場合に選択します。セキュリティのために、可能であればこちらが推奨されます。
- 次にランタイムやビルドの設定をします
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/2752c1a6-0d3a-d4aa-8c92-c0ffb70f610d.png)
    - 今回はテストのためデフォルトにしていますが、実際は用途に応じたリソース設定をする必要があります。


### 2: コードの設定
次にコードを書いていきます。
ソースコードをインラインエディタで直接書く設定にします。
今回のコードは、指定されたIPアドレスのみ「こんにちは」と返す簡単なAPIです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/0eb3b907-3ad0-72ea-ce73-fd1c6049ca72.png)

```javascript:index.js
exports.helloFunction = (req, res) => {
  // 許可するIPアドレス
  const allowedIP = 'your-ip'; // ここに許可するIPを入力

  // リクエスト元のIPアドレスを取得
  const requestIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

  // IPアドレスを確認して、一致する場合のみ「こんにちは」と返す
  if (requestIP === allowedIP) {
    res.status(200).send('こんにちは');
  } else {
    res.status(403).send('アクセス拒否');
  }
};
```

エントリポイントをコードで用いた関数名にすることに注意。

### 3: APIのデプロイ
コード設定ができたらデプロイします。
・・・しばらく待ちます。
リソースの規模が大きいほど、デプロイに時間がかかることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/7db1fd2f-1caa-2e6a-8455-e7900c366916.png)

こうなればぶじに完了です。

### 4: テスト
デプロイが完了したら、提供されたURLに対してリクエストを送信して動作を確認します。
以下のように、ターミナルから`curl` コマンドを使ってテストできます。

```bash
curl -X GET https://your-region-your-project-id.cloudfunctions.net/respondToAuthorizedIP
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/4ee37292-2f6c-1add-cf99-ca11e18e2687.png)

ぶじに確認できました。
許可されたIPからのリクエストであれば「こんにちは」が返され、
それ以外のIPからのアクセスは「アクセス拒否」が返されました。

なお、もし認証が必要な場合、以下のように`Authorizationヘッダー`を追加することができます。
ここでは`YOUR_ACCESS_TOKEN`を適切なトークンに置き換えてください。

```bash
curl -X GET https://your-region-your-project-id.cloudfunctions.net/respondToAuthorizedIP \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

### 5: アクセスログの確認


タブの「ログ」からアクセスログも確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/f8129658-dbd2-e644-7d54-1662b0a67637.png)

curlコマンドで通信があったことがわかりますね。
ログビューアでは、フィルターを使って特定のリクエストを絞り込んだり、
検索ボックスを使って特定のメッセージを探したりも可能です。

## まとめ
今回、Google Cloud Runを使って、非常に簡単なAPIを作成してみました。

Cloud Runは、サーバーのスケーリングや管理を気にせずにコンテナベースのアプリケーションを動かせるため、手軽にAPIを作成したい場合に最適です。

特に、サイボウズのkintoneのような環境では、埋め込みJavaScriptだけでは難しい機能をAPIを介して実現できるのが魅力です。ただし実際に利用する際は、**クラウド破産しないよう**、コストやセキュリティに注意しながら、運用していく必要があると感じました。