Google Cloud Run を使うまで

# はじめに

先日 Google Cloud Next で発表された Cloud Run を動かしてみました。実際にやってみて、想像と違ったところもあるのでまとめておきます。

参考にしたサイト

- [Cloud Run を最速で触ってみる](https://medium.com/google-cloud-jp/cloud-run-%E3%82%92%E6%9C%80%E9%80%9F%E3%81%A7%E8%A7%A6%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B-6e42021307d4)
- [Cloud Run documentation](https://cloud.google.com/run/docs/)


# Cloud Run とは
Cloud Run は自分で作ったコンテナを、Googleが用意したサーバー環境上で動かすことができます。http(s) の口を持ったWebサイト/Web APIサーバーを手軽に作れて、スケーリングも勝手に面倒見てくれます。
一方、コンテナを使っているからと言っても何でもできるのでなく、Webサーバー以外のサービス（RDBや、ストレージサービスなど）を動かすのには適していません。

Cloud Run を使うには、次のステップを踏む必要があります。

- 準備
- コンテナのビルド
- コンテナのデプロイ

# 準備

## Cloud SDKのインストール（と更新）

初めて Google Cloud を使う場合は、こちらの手順に従って、自分の環境にあった SDK をインストールします。

- Cloud SDK のインストール[（Google Cloud のドキュメント）](https://cloud.google.com/sdk/downloads?hl=JA)

インストール後（あるいはインストール済の場合）、コンポーネントのアップデート、β版コンポーネントの追加インストールを行います。

```
$ sudo gcloud components update
$ sudo gcloud components install beta
```

## GCPのサインアップ

Cloud Run は Google Cloud Platform (GCP)のサービスなので、まず[GCPにサインアップ](https://cloud.google.com/)してください。

さらに利用量に応じて費用が発生するため、請求先（クレジットカード情報）を登録しておく必要があります。初めて利用する場合は、今なら$300の無料クレジットが付くようです。そちら使えば当面は費用発生せずに利用できます。

## GCP上のプロジェクトの準備

Google Cloud Console から、新しくプロジェクトを作成します。作成方法は「プロジェクトの作成と管理 」を参照ください。またプロジェクトを、先ほど用意した請求先に紐づけておきます。

ここで今回作ったプロジェクトIDを、 仮に _cloud-run-0001_ とします。

## Cloud Build を有効化

[Google Cloud Console](https://console.cloud.google.com/) の左のメニューから「Cloud Build」を選択して、APIを有効にします。
![cloud_build_menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/2d1ab830-9f6e-8bb9-a09c-4c580c190b4f.png)
（この先でAPIを有効化）

## Cloud Run を有効化
同じく[Google Cloud Console](https://console.cloud.google.com/) の左のメニューから、「Cloud Run」を選択して、APIを有効にします。
![cloud_run_menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/47f059e6-36ee-75f1-eca5-fc0e072e92a2.png)
（この先でAPIを有効化）

## デフォルトのプロジェクトとリージョンの設定

今後 Cloud Run をコマンドラインツールから使うにあたって、デフォルトのプロジェクトとリージョンを指定します。ここで _cloud-run-0001_ はプロジェクトIDです。自分のものに適宜置き換えてください。

```
$ gcloud config set project cloud-run-0001
$ gcloud config set run/region us-central1
```

今のところ Cloud Run は us-central1 でしか使えないので、そこを選択しておきます。
また初めて gcloud を利用する場合には、認証が必要になる場合があります。こちらもやっておきましょう。

```
$ gcloud auth login
```

ブラウザが起動するので、認証しておきます。

# コンテナのビルド

## 実行対象の準備

Cloud Run は httpサーバーのための仕組になります。Webサーバーや自分のプログラムを、httpリクエストに対して応答するように準備します。通信に使うポートは自分では選べず、外部から環境変数PORTで渡されたポート番号を利用する必要があります。

## ローカル環境でコンテナの確認

いきなりクラウドで試すこともできますが、まずはローカル環境で確認しておくのが安心です。Dockerをインストールして起動しておいてください。

用意したプログラムをセットアップ、起動するDockerfileを用意して、コンテナをビルドします。ビルドができたらコンテナを実行して、指定したポートでつながることを確認します。
例えば次のような例で実行してみます。

-  _me/imagename_ ... イメージ名（適宜置き換えてください）
-  ホスト側のポート番号 8002
-  コンテナ側のポート番号 1323

```
$ docker build -t me/imagename
$ docker run --init -d -e PORT=1323 -p 8002:1323 me/imagename
```

ここではPORT環境変数で1323番を指定し、さらにホスト側の8002ポートをコンテナの1323ポートに接続しています。ブラウザで http://localhost:8002/ にアクセスして、想定したページが見られればOKです。

## Cloud Build でのコンテナビルド

作成したプロジェクトID（ここでは cloud-run-0001）と、今回作るアプリ（サービス）の名前（ここでは helloworld）を使って、次のようにビルドします。

```
$ gcloud builds submit --project cloud-run-0001 --tag gcr.io/cloud-run-0001/helloworld
```

認証が終わっていなかったり、APIが有効になっていなかったりするとエラーになります。上記準備の部分を参考に設定してから、再トライしてください。

ビルドは数分～数十分かかります。成功すると、次のようなメッセージが表示されるはずです。

```
PUSH
Pushing gcr.io/cloud-run-0001/helloworld
The push refers to repository [gcr.io/cloud-run-0001/helloworld]
... 省略 ...
DONE
```

ここで示される「gcr.io/cloud-run-0001/helloworld」のようなコンテナイメージのURLが後で必要になります。

# コンテナのデプロイ

## コマンドラインからのデプロイ

先ほどのコンテナイメージのURLを使って、コマンドラインからCloud Runにデプロイします。

```
$ gcloud beta run deploy --project cloud-run-0001 --image gcr.io/cloud-run-0001/helloworld
```

初めてデプロイする場合は、サービス名を質問されますので、適宜名前を入力します。

```
Service Name を問われるので入力 (helloworldなど）
```

また認証の有無を問われたら、Webサイトの場合は y を、認証ありのWebAPIの場合は N を指定してください。

```
Allow unauthenticated invocations to new service [helloworld]? (y/N)? ←未認証の実行を許可するかの選択。Webサイトの場合はy（認証付きWebAPIの場合はN）
```

上手くいけば、次のようにURLが表示されてデプロイが完了します。

```
Service [helloworld] revision [helloworld-00001] has been deployed and is serving traffic at https://helloworld-xxxxxxxx-uc.a.run.app/
```

ここでブラウザで表示されたURLを開くと、自分が用意したページが表示されるはずです。（初回はコンテナが立ち上がるまでに10秒前後かかります）

## コンソール画面からのデプロイ

ブラウザを使ってコンソール画面からデプロイすることもできます。「DEPLOY NEW REVISION」から

![cloud_run_deploy_b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/81b7eb53-b753-3c82-55bd-0bf3acf2cec4.png)

コンテナのイメージを指定してデプロイします。

![cloud_run_deploy2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/04abe2bf-2616-f373-04a1-884aaac0251b.png)

オプションを指定することもできます。

![cloud_run_deploy3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/b13d4edd-5041-5e68-3080-44e03004b040.png)

- 割り当てメモリ
- 最大リクエスト（超えたら新しいコンテナを起動する）
- タイムアウト（超えたらタイムアウト扱いとする）
- 環境変数（PORT以外にも指定できる）

## 外部のコンテナイメージのデプロイ

Cloud Build ではなく、Docker Hub のようなコンテナイメージを管理する外部サービスに登録したイメージを使って Cloud Run にデプロイできるのかどうか試してみました。残念ながら UR Lが gcr.io で始まっていないとエラーになります。どうやら Cloud Build とセットで利用するのが前提のようです。

# その他

## 他のGCPサービスとの比較

Google Cloud Platform には、似たようなサービスが複数存在します。個人的に App Engine SE (Standard Environment), App Engine FE(Flexible Environment), Cloud Run を使ってみて、ざっくりした位置づけを図にプロットしてみました。

![GCPK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19403/86d947fc-f3fa-07e1-7fdc-9d92b4d33b33.png)

お手軽さを取るか自由度を取るかで適切なサービスが変わってきます。個人的な印象では、従来のApp Engine や Conpute Engine (GCE) よりも、Cloud Run は少し高いレベルでバランスが取られているように思いました。

## Cloud Run の制約

こちらの公式ドキュメントに制約事項が記載されています。

[Container runtime contract](https://cloud.google.com/run/docs/reference/container-contract?hl=ja)

- コンテナは PORT環境変数で指定されるポートを待ち受ける必要がある
    - PORTは現在 8080番固定だが、将来変更される可能性がある
- コンテナが起動してから4分以内に、HTTPリクエストに応答する必要がある
- コンテナはアクセスが増えると自動でスケールアウトする
    - ※同時リクエスト数を1にすると、別コンテナが起動していることが観測できました
- コンテナはアクセスが無いと、自動で停止する（ゼロになる）
    - ※が、2019年5月現在、8時間放置してもコンテナは起動されたままでした
- ファイルに書き込むことができるが、メモリ上の一時的なもののため、停止すると失われる

また、http 以外の通信は許可されていないようです。WebSocket 通信を試みましが、遮断されました。

※こちらの 2021.01.22のエントリーにある通り、CloudRunがWebSocketやHTTP/2, gRPCをサポートしました。(2021.02.07追記）

- [Introducing WebSockets, HTTP/2 and gRPC bidirectional streams for Cloud Run](https://cloud.google.com/blog/products/serverless/cloud-run-gets-websockets-http-2-and-grpc-bidirectional-streams)