【GCP】Cloud Run での Endpoints (API Gateway)

公式サイトのドキュメントは大変分かりにくいため、ここで必要なコマンドなどまとめて記載します。

## 事前準備
- Cloud Shell
- Service API の有効化
    - Cloud Enpoints API
    - Cloud Run API

## バックエンドサービスのデポロイ
```
$ gcloud beta run deploy backend \
    --image="gcr.io/cloudrun/hello" \
    --project=$GOOGLE_CLOUD_PROJECT \
    --allow-unauthenticated \
    --platform managed \
    --region asia-northeast1

Deploying container to Cloud Run service [backend] in project [9999999999] region [asia-northeast1]
✓ Deploying new service... Done.                                                           
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [backend] revision [backend-00001-kam] has been deployed and is serving 100 percent of traffic at https://backend-3iegrzpgpa-an.a.run.app
```

### デポロイ結果の確認
最後に表示されてる、**https://backend-3iegrzpgpa-an.a.run.app** にアクセスすると、テスト用の画面が見れます。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/0013d0d8-7bca-65ee-45a4-26f92a06e34d.png)

## Cloud Enpoints の初期化
```shell:環境変数の設定
export CLOUD_RUN_SERVICE_NAME=endpoint
```

[https://gcr.io/endpoints-release/endpoints-runtime-serverless](gcr.io/endpoints-release/endpoints-runtime-serverless) から最新の **ESP** (Extensible Service Proxy) が確認できます。

```shell
$ gcloud beta run deploy $CLOUD_RUN_SERVICE_NAME \
    --image="gcr.io/endpoints-release/endpoints-runtime-serverless:2.14" \
    --memory=2Gi \
    --project=$GOOGLE_CLOUD_PROJECT \
    --allow-unauthenticated \
    --platform managed \
    --region asia-northeast1

Deploying container to Cloud Run service [endpoint] in project [9999999999] region [asia-northeast1]
✓ Deploying new service... Done.                                                           
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [endpoint] revision [endpoint-00001-dim] has been deployed and is serving 100 percent of traffic at https://endpoint-3iegrzpgpa-an.a.run.app
```

### APIs Deploy
`host` と `x-google-backend/address` は **Backend と Endpoint それぞれのアドレス**になるので、ご注意ください 

```yaml:api.yaml
swagger: '2.0'
info:
  title: APIGateway
  description: APIGateway for endpoints
  version: 1.0.0
host: endpoint-3iegrzpgpa-an.a.run.app
schemes:
  - https
produces:
  - application/json
x-google-backend:
  address: https://backend-3iegrzpgpa-an.a.run.app
paths:
  /:
    get:
      summary: hello
      operationId: root
      responses:
        '200':
          description: A successful response
          schema:
            type: string
```

```shell:api-deploy
$ gcloud endpoints services deploy api.yaml

Waiting for async operation operations/services.endpoint-3iegrzpgpa-an.a.run.app-0 to complete...
Waiting for async operation operations/serviceConfigs.endpoint-3iegrzpgpa-an.a.run.app:e8dd17df-d4e2-4e11-a2a4-63d961f813e1 to complete...
Operation finished successfully. The following command can describe the Operation details:
 gcloud endpoints operations describe operations/serviceConfigs.endpoint-3iegrzpgpa-an.a.run.app:e8dd17df-d4e2-4e11-a2a4-63d961f813e1
WARNING: api.yaml: Operation 'get' in path '/': Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all
 the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one Sec
urityDefinition of type : 'apiKey'.
Waiting for async operation operations/rollouts.endpoint-3iegrzpgpa-an.a.run.app:f1146c2f-e5d8-464a-8d0f-47121dc6b00c to complete...
Operation finished successfully. The following command can describe the Operation details:
 gcloud endpoints operations describe operations/rollouts.endpoint-3iegrzpgpa-an.a.run.app:f1146c2f-e5d8-464a-8d0f-47121dc6b00c
Enabling service [endpoint-3iegrzpgpa-an.a.run.app] on project [pocketcards]...
Operation "operations/acf.a9afc803-80b3-4acd-bb52-a984439b9b49" finished successfully.
Service Configuration [2020-07-30r0] uploaded for service [endpoint-3iegrzpgpa-an.a.run.app]
To manage your API, go to: https://console.cloud.google.com/endpoints/api/endpoint-3iegrzpgpa-an.a.run.app/overview?project=pocketcards
```

## Cloud Enpoints の権限設定
そのまま使えませんので、 Cloud Endpoints から Cloud Run 呼び出せる権限を付ける必要があります。

```shell:環境変数
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format json | jq ".projectNumber | tonumber")
export CLOUD_RUN_ENDPOINT=endpoint-3iegrzpgpa-an.a.run.app
export CLOUD_RUN_BACKEND=backend
```

```shell:権限設定
// Cloud Enpoints 環境変数の設定
$ gcloud beta run services update $CLOUD_RUN_SERVICE_NAME \
  --set-env-vars="^|^ENDPOINTS_SERVICE_NAME=$CLOUD_RUN_ENDPOINT|ESPv2_ARGS=^++^--cors_preset=basic++--cors_allow_origin=*" \
  --platform managed \
  --region asia-northeast1

✓ Deploying... Done.                                         
  ✓ Creating Revision...
  ✓ Routing traffic...
Done.
Service [endpoint] revision [endpoint-00002-pos] has been deployed and is serving 100 percent of traffic at https://endpoint-3iegrzpgpa-an.a.run.app

// Invoke 権限の設定
$ gcloud beta run services add-iam-policy-binding $CLOUD_RUN_SERVICE_NAME \
    --member "serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
    --role "roles/run.invoker" \
    --platform managed \
    --region asia-northeast1

Updated IAM policy for service [endpoint].
bindings:
- members:
  - allUsers
  - serviceAccount:9999999999-compute@developer.gserviceaccount.com
  role: roles/run.invoker
etag: BwWrnw7w_u4=
version: 1
```

## Cloud Enpoints の設定確認
**https://endpoint-3iegrzpgpa-an.a.run.app** アクセスしてみると、画面は出てきましたが、画像が表示されません。まぁ、API 用なので、画像表示されないのは、想定通りです。

## バックエンドの保護
`allow-unauthenticated` の設定を外せば、バックエンドの一般公開を無効にできます。

```shell:no-allow-unauthenticated
$ gcloud beta run deploy backend \
    --image="gcr.io/cloudrun/hello" \
    --project=$GOOGLE_CLOUD_PROJECT \
    --no-allow-unauthenticated \
    --platform managed \
    --region asia-northeast1

Deploying container to Cloud Run service [backend] in project [xxxxxxxxx] region [asia-northeast1]
✓ Deploying... Done.                                                           
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [backend] revision [backend-00004-vov] has been deployed and is serving 100 percent of traffic at https://backend-3iegrzpgpa-an.a.run.app
```

### 最終確認

バックエンドの **https://backend-3iegrzpgpa-an.a.run.app** アクセスすると、下記のようなエラー画面が表示されます

```html:403_Forbidden
Error: Forbidden
Your client does not have permission to get URL / from this server.
```

Cloud Endpoints の **https://endpoint-3iegrzpgpa-an.a.run.app** からアクセスすると、下記のような画面が表示されます
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/3182fb7b-328b-92f5-c2ed-9ec6c83ace2e.png)

## 最後のひと言
Cloud Run は **コールドスタート** の場合ありますので、Cloud Scheduler など Health check の実装を行いましょう

## 参考資料
[Cloud Run での Endpoints スタートガイド](https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-run?hl=ja)