Cloud Functionsに独自ドメインを設定する

前置き
=====

Google が提供している[CloudFunctions](https://cloud.google.com/functions/?hl=ja)は、ちゃちゃっとAPIなどを書くときにとっても便利です。

ただ、作ったAPIを外部に公開しようとしたときに、URLが `https://リージョン名-プロジェクト名.cloudfunctions.net/関数名` みたいなのになるのはちょっとダサい。独自ドメインを割り付けたい気持ちになります。

[Apigee](https://cloud.google.com/apigee/?hl=ja)というAPI Gatewayサービスを使えばぱぱっとできる(ように見える)のですが、こいつはちょっとお値段がアレ。

そこで、[Cloud Endpoints](https://cloud.google.com/endpoints/docs/openapi/about-cloud-endpoints?hl=ja)を使うのが常套手段っぽいのですが、「Cloud Functions + Cloud Endpoints + 独自(カスタム)ドメイン」みたいなドンピシャなサンプルがなくて少しハマりました。

最終的に

**Cloud Endpoints + Docker Run (with Extensible Service Proxy) => Cloud Functions**

という構成でCloud Functionsに独自ドメインを設定できたのでメモを公開します。

やったこととしては、以下の２つのチュートリアルの合わせ技です。

* [Cloud Functions 用 Endpoints のスタートガイド](https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions?hl=ja)
* [独自のドメイン名から API を提供する](https://cloud.google.com/endpoints/docs/openapi/serving-apis-from-domains?hl=ja)

手順
====

1. Cloud Functionsに適当な関数をデプロイする
----

`Hello World` でも返す適当な関数をCloud Functionsにデプロイしましょう。デプロイした際にそのエンドポイントのURLが取得できますのでそのURLをコピーしておきます。ここでは仮に `https://cloudfunctions.example.com/hello` としておきます。

2.割り当てたい独自ドメインの所有権を確認しておく
-------

GCPで独自ドメインを利用する場合、ドメインの所有権を確認するという作業が必要となります。手順に従ってドメインの所有権の確認を行いましょう。ここでは仮に、Cloud Functionsに割り当てるドメイン名を `mydomain.example.com` とします。

https://cloud.google.com/endpoints/docs/openapi/verify-domain-name?hl=ja

3.Cloud Endpointsに設定するswaggerファイルを書く
----

Cloud EndpointsはAPI Gatewayサービスです。認可やら、APIドキュメントやらも提供してくれることができますが、今回はとにかく独自ドメインをCloudFunctionsに割り当てたいだけなので難しいことはなにも考えません( ˘ω˘)ｽﾔｧ

[こちらのドキュメントの「Endpointsを構成する」](https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions?hl=ja#endpoints_configure) を参考に

```yaml

swagger: '2.0'
info:
  title: How to apply custom domain name to cloud functions
  description: :-)
  version: 1.0.0
host: mydomain.example.com
schemes:
  - https
produces:
  - application/json
paths:
  /hello:
    get:
      summary: Greet a user
      operationId: hello
      x-google-backend:
        address: https://cloudfunctions.example.com/hello
      responses:
        '200':
          description: A successful response
          schema:
            type: string
```

ここで重要なのは **hostに割り当てたい独自ドメイン名を**、 **x-google-backendのaddressにCloud Functionsのエンドポイントを** 書くことです。

このファイルを `swagger.yaml` とでもして保存しておきましょう。

4. Endpointsをデプロイする
----------------

まず、利用するのに必要なサービス群を有効にします。以下のコマンドを叩いて有効化しましょう。

```
gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com
gcloud services enable endpoints.googleapis.com
```

次に[ここを参考](https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions?hl=ja#deploy_configuration)にEndpointsをデプロイします。

ドキュメントでは `openapi-functions.yaml` となっている部分を `swagger.yaml` とするのを忘れずに

5. Cloud RunにESPをデプロイして、各種権限の設定を行う
----------

Extensible Service Proxy(ESP)をデプロイします。App EngineやCompute Engineにデプロイする方法もあるのですが、先日GAになったCloud Runにデプロイするのが一番楽そうなので、これを利用します。

ESPはNGINXベースのProxyサーバで、API Gatewayの機能を提供します。詳しくはこちらを参照 => https://cloud.google.com/endpoints/docs/openapi/architecture-overview?hl=ja

ここがわりと混乱ポイントなのですが、API Gatewayの機能はあくまで ESPであり、そのための定義のswaggerファイルなんかをマネージするのがCloud Endpointsということみたいです。

### CloudRunで使用するServiceAccountを作っておく

以下の権限をもったServiceAccountを作っておきます。このServiceAccountでCloudRunを動かすんじゃい。

* roles/cloudtrace.agent
* roles/run.serviceAgent
* roles/servicemanagement.serviceController
* roles/cloudfunctions.invoker


### Cloud RunにESPをデプロイする

さて、ドキュメントに従ってESPをCloudRunにデプロイしましょう。最近GAとなったKnativeのマネージドサービスですが、要するに `dockerが動くcloud functions` くらいのイメージでOKです。

https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions?hl=ja#deploy_endpoints_proxy

ESPの本体のdockerimageはすでにGoogle Cloud Registry 上で提供されているので、↑のドキュメントに従ってデプロイすればOKです。

続いて Endpointの構成を行います。 https://cloud.google.com/endpoints/docs/openapi/get-started-cloud-functions?hl=ja#configure_esp
脳死でドキュメントに従いましょう。

6.Cloud Runに独自ドメインを割り当てる
-----------

ここにもハマりポイントがあります。 GCP Consoleの `APIとサービス` => `ドメインの確認` => `ドメインを追加`　でCloud Runに割り当てたいドメイン名を登録しておかないと動きません。 

さて、上記の登録を行ったらドキュメントに従って設定しましょう。

https://cloud.google.com/run/docs/mapping-custom-domains?hl=ja

7. 以上
------

これでCloud Functionに独自ドメインが割り付けられました。よかったですね。 :tada: 

雑記
===

うちのインフラボーイズに2ヶ月前くらいにコレに取り組んでもらっていたのですが、チュートリを進めているとどうも「GCRのESPコンテナのURLが間違っていて詰む」と言っていて、一回詰んだんですよね。

しかし、Cloud RunがGAになり、ふとドキュメントをみてみると以前みたのと随分ドキュメントの雰囲気が違っていたので、試してみたら行けたって感じです。めでたしめでたし。

インフラボーイズの頑張りに圧倒的感謝……っ!!
Thanks @natsuo @nagashi_ma_w !