CloudRunとCloudRun on GKE でgolangのサンプルアプリを動かしてみる。

# 概要

- Kubernetes上にサーバーレス環境を提供するサービス
- Knative+Istioベース
- フルマネージドなCloudRunとGKE環境にアドオンするCloudRun on GKEがある
- CloudRunはもちろん、CloudRun on GKEもgcloudコマンドのみでデプロイ&サービス公開がされる（ココがすごい）

# 価格

### CloudRun

vCPU,Memory,Request,(Network)のトータルで決まる。
<img width="987" alt="スクリーンショット 2019-04-14 16.38.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306826/7a104719-9496-518b-8c83-9579faad64bf.png">

### CloudRun on GKE

今のところ、GKEの価格に含まれるっぽい。GA時には変わるかも。

# CloudRunとCloudRunOnGKEの機能差異

フルマネージドなCloudRunはvCPUは1つに限定（メモリは可変設定）、VPC内のサーバーにはアクセスできないなどいくつか制限がある。利用時はこの辺の制限が問題にならないかのチェックが必要。

<img width="1181" alt="スクリーンショット 2019-04-14 16.41.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306826/a28e86e0-aa23-b0ce-2f1c-add9314df1da.png">

## CloudRunでサンプルアプリを実行

ドキュメントを見ながらサンプルを実行する

参考：https://cloud.google.com/run/docs/quickstarts/build-and-deploy?hl=ja

CloudRunのAPIドキュメント：https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy?hl=ja

main.go

```
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func handler(w http.ResponseWriter, r *http.Request) {
	log.Print("Hello world received a request.")
	target := os.Getenv("TARGET")
	if target == "" {
		target = "World"
	}
	fmt.Fprintf(w, "Hello %s!\n", target)
}

func main() {
	log.Print("Hello world sample started.")

	http.HandleFunc("/", handler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
```

Dockerfile

```
FROM golang:1.12 as builder

WORKDIR /go/src/sample
COPY . .

RUN go install sample
ENTRYPOINT ["sample"]
```

上記２ファイルをSourceRepositoriesにコミットしておき、CloudBuildでビルドする。（ビルド結果がContainerRegistoryに登録される）

### gcloudコマンドでCloudRunにデプロイ

以下の条件でデプロイ
- 未認証での外部アクセス可
- メモリ：128M
- リージョン：us-central1　（今のところここしかない）
- タイムアウト：30s
- イメージ：ビルドした結果出来上がったコンテナへのURL（ContainerRegistoryからコピーする）

```
gcloud beta run deploy sample --allow-unauthenticated --memory 128Mi --region us-central1 --timeout 30 --image gcr.io/my-sample/sample@sha256:xxxxxxxxxx
```

デプロイに成功したら、コマンドの戻り値で公開URLが返ってきます。（ブラウザでCloudRunの画面を開いたらいつでも確認できます）

## CloudRun on GKEでサンプルアプリの実行

こちらもドキュメントを見ながら実行する

参考：https://cloud.google.com/run/docs/quickstarts/prebuilt-deploy-gke?hl=ja

### GKEクラスタ作成

- マシンタイプ：n1-standard-4
- ノード数：3
- プリエンティブVM（節約のため）

CloudRunを組み込む設定として、下記が必須となる

- gcloud betaコマンド（gcloud betaを利用可能＆最新にアップデートしておく）
- --enable-cloud-logging
- --enable-cloud-monitoring
- --enable-stackdriver-kubernetes
- --addons=Istio,CloudRun

サンプルのクラスタ作成コマンド

```
gcloud beta container clusters create sample-cluster --cluster-version=latest \
--machine-type=n1-standard-4 \
--num-nodes=1 --enable-autoscaling --min-nodes=1 --max-nodes=3 \
--disk-size=50GB \
--enable-autorepair \
--enable-cloud-logging \
--enable-cloud-monitoring \
--enable-stackdriver-kubernetes \
--zone=asia-northeast1-b \
--node-locations=asia-northeast1-a,asia-northeast1-b,asia-northeast1-c \
--addons=HttpLoadBalancing,HorizontalPodAutoscaling,Istio,CloudRun \
--preemptible
```

### アプリケーションのデプロイ

CloudRunにデプロイしたアプリをこちらにもデプロイ

CloudRunとの違いは以下の通り

- --allow-unauthenticatedは削除
- --namespeceにクラスタのどのnamespaceにデプロイするかを指定
- -- regionでクラスタのリージョンを指定
- --clusterでクラスタ名を指定
- --cluster-locationでクラスタのロケーション（クラスタ作成時のZone）を指定

```
gcloud beta run deploy sample-on-gke --namespace default --region asia-northeast1 --cluster sample-cluster --cluster-location asia-northeast1-b --memory 128Mi --timeout 30 --image gcr.io/my-sample/sample@sha256:xxxxx
```

デプロイが完了すると、ホスト名が返ってくる

```
Deploying container to Cloud Run on GKE service [sample-on-gke] in namespace [default] of cluster [sample-cluster]
✓ Deploying... Done.
  ✓ Creating Revision...
  - Routing traffic...
Done.
Service [sample-on-gke] revision [sample-on-gke-mdqb4] has been deployed and is serving traffic at sample-on-gke.default.example.com
```

### アプリの実行

ヘッダにHost:<ホスト名>をつけて、外部IPにアクセスすることで、デプロイしたコンテナにルーティングされる。

```
curl -v -H "Host: <ホスト名>" http://<EXTERNAL-IP>/
```
※ホスト名はgcloudコマンドでデプロイした時に返ってくる値、EXTERNAL-IPはクラスタの外部IP（GKEの画面か、LBの画面で確認）

# まとめ

- GKE上にアプリをデプロイして動作させるのにYAMLが一切出てこなくて、本当にserverlessアプリを作る感覚でデプロイできる。
- CloudRunもCloudRun on GKEもほぼ同じ操作で使用可能
- AppEngineやCloudFunctionsはフルマネージドなCloudRun、GKEはCloudRun on GKEに集約するとCloudRunに集約できるイメージになるのかな？
- CloudRunはまだ制約が多いので、早くもっと色々できるようになって欲しい。（東京にもきて欲しい）