Cloud Run on GKEに覗くKnative

## 概要

* Cloud Run on GKEでKnativeがどう使われているのかを調べたい
* Cloud Run on GKEの挙動と仕様をなんとなく理解した気になりたい

現在Cloud Run on GKEはCloud Run for Anthosになっている

## 環境構築

公式ドキュメントにCloud Run on GKE関連のチュートリアルベースにGoogle Cloud Shellで準備していきます。

* [Cloud Run on GKEが使えるクラスタの準備](https://cloud.google.com/run/docs/gke/setup)
* Knativeでオートスケールを試すための[Dockerイメージ利用](https://console.cloud.google.com/gcr/images/knative-samples/GLOBAL/autoscale-go?gcrImageListsize=30)
  * ソースコード: [autoscale.go](https://github.com/knative/docs/blob/master/docs/serving/samples/autoscale-go/autoscale.go)

この記事では一からKnative自体の説明はしないので、[公式ドキュメント](https://github.com/knative/docs)や拙著『[Knativeの歩き方 KubernetesからServerlessを訪ねて](https://booth.pm/ja/items/1309468)』、[登壇資料](https://speakerdeck.com/toshi0607/getting-started-with-knative-90ff6190-1251-4b7b-ada9-bbba5a8ca4b8)などを参考にしてください。

ここからGoogle Cloud Shellを使って準備していきます。ローカル環境のターミナルは利用しません。

### Google Cloud Shell準備

GKEでクラスタを準備し、Cloud Runを実行するGCPプロジェクトに移動してください。

Cloud Shellは別ウィンドウで開くと便利です。

<img width="272" alt="newwindow_color.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/8e83a702-cbea-aaf1-366e-f236757b230d.png">

### Kubernetesクラスタ準備

利用するAPIを有効化し、c-runという名前のクラスタを作成します。

```console
# APIの有効化
$ gcloud services enable container.googleapis.com containerregistry.googleapis.com cloudbuild.googleapis.com

# 環境変数設定
$ export VERSION=latest
$ export ZONE=us-central1-a
$ export CLUSTER_NAME=c-run

# 環境変数を利用してクラスタ作成
$ gcloud beta container clusters create ${CLUSTER_NAME} \
  --addons=HorizontalPodAutoscaling,HttpLoadBalancing,Istio,CloudRun \
  --machine-type=n1-standard-4 \
  --cluster-version=${VERSION} --zone=${ZONE} \
  --enable-stackdriver-kubernetes --enable-ip-alias \
  --scopes cloud-platform

```

ここではc-runという名前で作成します。

作成には少し時間がかかります。つぎのURLから作成状況が確認できます。

https://console.cloud.google.com/kubernetes/list

つぎのコマンドを実行してノードの準備ができていることを確認してください。

```console
$ kubectl get nodes
NAME                                   STATUS   ROLES    AGE    VERSION
gke-c-run-default-pool-8d7008c0-0vz9   Ready    <none>   2d5h   v1.12.7-gke.10
gke-c-run-default-pool-8d7008c0-j05x   Ready    <none>   2d5h   v1.12.7-gke.10
gke-c-run-default-pool-8d7008c0-j15b   Ready    <none>   2d5h   v1.12.7-gke.10
```

正常に作成が完了していれば3のノードのステータスが*Ready*になっているはずです。

## Knative関連のコンポーネント確認

ここまでの準備でどのNamespaceに何が準備されたのでしょうか。*kubectl*で確認してみましょう。

```console
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   6m54s
istio-system      Active   6m13s
knative-serving   Active   6m19s
kube-public       Active   6m54s
kube-system       Active   6m54s
```

*default*や*kube-public*、*kube-system*に加えて*knative-serving*と*istio-system*のネームスペースが存在します。

KnativeのコンポーネントのServing、Build、Eventingの中でServingだけが利用されている雰囲気です。

この記事では後ほどKnativeが依存しているIstioのistio-ingressgatewayからエンドポイントを取得します。

```console
$ kubectl get pod -n istio-system
NAME                                     READY   STATUS      RESTARTS   AGE
istio-citadel-7cbd68dc58-65kg5           1/1     Running     0          6m47s
istio-cleanup-secrets-msjn6              0/1     Completed   0          6m51s
istio-egressgateway-76bd65699f-fmrd2     1/1     Running     0          6m48s
istio-galley-848d6b698c-tv5nz            1/1     Running     0          6m48s
istio-ingressgateway-64d6cfc6cb-729cd    1/1     Running     0          6m48s
istio-pilot-57c9ff7496-jlhk5             2/2     Running     0          6m47s
istio-policy-57bf7c4984-dd7tw            2/2     Running     0          6m48s
istio-sidecar-injector-9db9b45f5-62cmr   1/1     Running     0          6m46s
istio-telemetry-bf847c494-pklss          2/2     Running     0          6m47s
promsd-8cc5d455b-xtvw8                   2/2     Running     1          6m45s

```

knative-servingのPodを確認してみると、*cloudrun-controller*という見慣れないコントローラーが存在しています。

```console
$ kubectl get pod -n knative-serving
NAME                                   READY   STATUS    RESTARTS   AGE
activator-7d7b59bd6c-xctcg             1/1     Running   1          5m28s
autoscaler-84cc7b78c4-bqvg6            1/1     Running   0          5m27s
cloudrun-controller-5859fbcc44-2cxht   1/1     Running   0          5m24s
controller-db5bbf4b9-sfb9n             1/1     Running   0          5m26s
webhook-85ddccf9c6-dmgg8               1/1     Running   0          5m25s
```

後ほどどういう役割を果たしていそうか仕様に照らし合わせて確認してみましょう。

その他はServingをインストールするときに含まれるものと変わらないですね。

Knative Serving関連のリソースはこの段階ではまだ存在していません。


```console
$ kubectl get ksvc,configuration,route,revision
No resources found.
```

## Cloud Run on GKEのデプロイ

```console
# デフォルトの実行環境設定
$ export CLUSTER_NAME=c-run
$ export ZONE=us-central1-a
$ gcloud config set run/cluster ${CLUSTER_NAME}
$ gcloud config set run/cluster_location ${ZONE}

# Cloud Runのデプロイ
# デフォルト設定なしでデプロイする場合、GKE上にデプロイしたい場合は
# --cluster と --cluster-location オプションが必要です。
# 省いた場合はon GKEでない方にデプロイされます。
$ export SERVICE_NAME=autoscale-go
$ gcloud beta run deploy ${SERVICE_NAME} --image gcr.io/knative-samples/autoscale-go:0.1

# デプロイに成功するとつぎのようにサービス名、Namespace、クラスター名、Revision名、エンドポイントが表示されます。
# Namespaceも--namespaceで指定できます。
# その他オプションはgcloud beta run deploy --help で確認してみてください。
# あとは[このドキュメント https://cloud.google.com/sdk/gcloud/reference/beta/run/
Deploying container to Cloud Run on GKE service [autoscale-go] in namespace [default] of cluster [c-run]
✓ Deploying new service... Done.                                                                  
  ✓ Creating Revision...
  - Routing traffic...
Done.
Service [autoscale-go] revision [autoscale-go-h425w] has been deployed and is serving traffic at autoscale-go.default.example.com

```

Knativeのリソースが登録された雰囲気があるので確認してみましょう。

```console
$ kubectl get ksvc,configuration,route,revision
NAME DOMAIN LATESTCREATED LATESTREADY READY REASON
service.serving.knative.dev/autoscale-go autoscale-go.default.example.com autoscale-go-h425w autoscale-go-h425w True

NAME LATESTCREATED LATESTREADY READY REASON
configuration.serving.knative.dev/autoscale-go autoscale-go-h425w autoscale-go-h425w True

NAME DOMAIN READY REASON
route.serving.knative.dev/autoscale-go autoscale-go.default.example.com True

NAME SERVICE NAME GENERATION READY REASON
revision.serving.knative.dev/autoscale-go-h425w autoscale-go-h425w-service 1 True

```

Knative Serving関連のリソースが一通り登録されていることが確認できました。

それぞれ図のような関係にあります。

![serving.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/af5ba2e5-dc0a-dce0-2425-72e4ff0771ca.jpeg)

## オートスケールアウト・インを観察する

Cloud Runではコンテナあたりのリクエスト数を設定できます。

Cloud Run on GKE上のコンテナにリクエストするにあたっては[rakyll/hey](https://github.com/rakyll/hey)を使うことで並列リクエスト数を指定します。

```console
$ go get github.com/rakyll/hey
```

`istio-ingressgateway`からエンドポイントを取得し、リクエストします。

リクエストを処理するサーバーの実装は[これ](https://github.com/knative/docs/blob/master/docs/serving/samples/autoscale-go/autoscale.go)で、リクエストパラメタで各リクエストでsleepする時間を指定できます。今回は1秒です。

```console
$ IP_ADDRESS="$(kubectl get service istio-ingressgateway --namespace istio-system --output jsonpath="{.status.loadBalancer.ingress[*].ip}")"

# 500並列で150000リクエストする
$ hey -host autoscale-go.default.example.com -c 500 -n 150000 \
  "http://${IP_ADDRESS?}?sleep=1000"
```

別セッションでPodの様子を見てみます。

```console
$ kubectl get pods -w
NAME                                            READY   STATUS    RESTARTS   AGE
autoscale-go-k7nxb-deployment-7cc8f74b4-5snjn   3/3     Running   0          9s
autoscale-go-k7nxb-deployment-7cc8f74b4-hm2zz   3/3     Running   0          22s
autoscale-go-k7nxb-deployment-7cc8f74b4-hvh9j   3/3     Running   0          19s
autoscale-go-k7nxb-deployment-7cc8f74b4-j6s4p   3/3     Running   0          19s
autoscale-go-k7nxb-deployment-7cc8f74b4-r6kd6   3/3     Running   0          17s
autoscale-go-k7nxb-deployment-7cc8f74b4-rv29q   3/3     Running   0          17s
autoscale-go-k7nxb-deployment-7cc8f74b4-rv29q   3/3   Terminating   0     68s
autoscale-go-k7nxb-deployment-7cc8f74b4-r6kd6   3/3   Terminating   0     68s
autoscale-go-k7nxb-deployment-7cc8f74b4-hvh9j   3/3   Terminating   0     70s
autoscale-go-k7nxb-deployment-7cc8f74b4-5snjn   3/3   Terminating   0     60s
autoscale-go-k7nxb-deployment-7cc8f74b4-j6s4p   3/3   Terminating   0     72s
autoscale-go-k7nxb-deployment-7cc8f74b4-5snjn   2/3   Terminating   0     63s
autoscale-go-k7nxb-deployment-7cc8f74b4-rv29q   2/3   Terminating   0     71s
autoscale-go-k7nxb-deployment-7cc8f74b4-hvh9j   2/3   Terminating   0     73s
autoscale-go-k7nxb-deployment-7cc8f74b4-r6kd6   2/3   Terminating   0     72s
autoscale-go-k7nxb-deployment-7cc8f74b4-j6s4p   2/3   Terminating   0     74s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   0/3   Init:0/1   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   0/3   Init:0/1   0     1s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   0/3   PodInitializing   0     2s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   0/3   PodInitializing   0     2s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   2/3   Running   0     3s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   2/3   Running   0     3s
autoscale-go-k7nxb-deployment-7cc8f74b4-bpdkg   3/3   Running   0     4s
autoscale-go-k7nxb-deployment-7cc8f74b4-z9h9l   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-z9h9l   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-z9h9l   0/3   Init:0/1   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-98db2   3/3   Running   0     4s
autoscale-go-k7nxb-deployment-7cc8f74b4-bq7wl   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-bq7wl   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-f682w   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-bq7wl   0/3   Init:0/1   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-f682w   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-8s4hg   0/3   Pending   0     0s
autoscale-go-k7nxb-deployment-7cc8f74b4-z9h9l   0/3   PodInitializing   0     2s
autoscale-go-k7nxb-deployment-7cc8f74b4-8s4hg   0/3   Pending   0     0s
...
```

Deploymentも見てましょう。

```console
$ kubectl get deployment -w
NAME                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
autoscale-go-h425w-deployment   0         0         0            0           7d6h
autoscale-go-k7nxb-deployment   5         5         5            5           16h
autoscale-go-k7nxb-deployment   4     5     5     5     16h
autoscale-go-k7nxb-deployment   4     5     5     5     16h
autoscale-go-k7nxb-deployment   4     4     4     4     16h
autoscale-go-k7nxb-deployment   3     4     4     4     16h
autoscale-go-k7nxb-deployment   3     4     4     4     16h
autoscale-go-k7nxb-deployment   3     3     3     3     16h
autoscale-go-k7nxb-deployment   2     3     3     3     16h
autoscale-go-k7nxb-deployment   2     3     3     3     16h
autoscale-go-k7nxb-deployment   2     2     2     2     16h
autoscale-go-k7nxb-deployment   1     2     2     2     16h
autoscale-go-k7nxb-deployment   1     2     2     2     16h
autoscale-go-k7nxb-deployment   1     1     1     1     16h
autoscale-go-k7nxb-deployment   0     1     1     1     17h
autoscale-go-k7nxb-deployment   0     1     1     1     17h
autoscale-go-k7nxb-deployment   0     0     0     0     17h
```

heyでリクエストしたセッションに戻ると、統計情報が表示されています。

```console
$ hey -host autoscale-go.default.example.com -c 500 -n 150000   "http://${IP_ADDRESS?}?sleep=1000"
Summary:
  Total:        361.7094 secs
  Slowest:      6.9157 secs
  Fastest:      1.1585 secs
  Average:      1.1942 secs
  Requests/sec: 414.6975
  Total data:   4800000 bytes
  Size/request: 32 bytes

Response time histogram:
  1.159 [1]     |
  1.734 [149499]        |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  2.310 [0]     |
  2.886 [0]     |
  3.461 [0]     |
  4.037 [0]     |
  4.613 [0]     |
  5.189 [19]    |
  5.764 [47]    |
  6.340 [117]   |
  6.916 [317]   |

Latency distribution:
  10% in 1.1599 secs
  25% in 1.1609 secs
  50% in 1.1639 secs
  75% in 1.1746 secs
  90% in 1.2061 secs
  95% in 1.2439 secs
  99% in 1.3797 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0006 secs, 1.1585 secs, 6.9157 secs
  DNS-lookup:   0.0000 secs, 0.0000 secs, 0.0000 secs
  req write:    0.0001 secs, 0.0000 secs, 0.0369 secs
  resp wait:    1.1935 secs, 1.1584 secs, 6.7449 secs
  resp read:    0.0000 secs, 0.0000 secs, 0.0125 secs

Status code distribution:
  [200] 150000 responses
```

可視化した方がわかりやすいですが、リクエスト数見合いでDeployment（ReplicaSet）のdesiredが増え、Podが増えていく様子が確認できます。リクエストが止んだらPodは全て無くなります。

レイテンシーはほぼ1.159〜1.734の階級に集中しており、単にリクエストを返す以上に時間がかかるもの（コールドスタートを待っているもの）もちょうど500（0.3%）ほどあります。

今度はコンテナあたりの並列リクエスト数をデフォルトの半分の40にして試してみます。

```console
# 並列実行数設定の更新
$ gcloud beta run services update ${SERVICE_NAME} --concurrency=40
✓ Deploying... Done.
  ✓ Creating Revision...
  - Routing traffic...
Done.
Service [autoscale-go] revision [autoscale-go-vks24] is active and serving traffic at autoscale-go.default.example.com
```

```console
$ hey -host autoscale-go.default.example.com -c 500 -n 150000   "http://${IP_ADDRESS?}?sleep=1000"

Summary:
  Total:        506.9715 secs
  Slowest:      19.9889 secs
  Fastest:      0.1576 secs
  Average:      1.4615 secs
  Requests/sec: 295.8746

  Total data:   4678992 bytes
  Size/request: 31 bytes

Response time histogram:
  0.158 [1]     |
  2.141 [146098]        |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  4.124 [756]   |
  6.107 [313]   |
  8.090 [776]   |
  10.073 [605]  |
  12.056 [121]  |
  14.039 [98]   |
  16.023 [112]  |
  18.006 [127]  |
  19.989 [121]  |


Latency distribution:
  10% in 1.1602 secs
  25% in 1.1673 secs
  50% in 1.3392 secs
  75% in 1.5084 secs
  90% in 1.6149 secs
  95% in 1.7162 secs
  99% in 7.4334 secs

Details (average, fastest, slowest):
  DNS+dialup:   0.0006 secs, 0.1576 secs, 19.9889 secs
  DNS-lookup:   0.0000 secs, 0.0000 secs, 0.0000 secs
  req write:    0.0000 secs, 0.0000 secs, 0.0193 secs
  resp wait:    1.4607 secs, 0.1575 secs, 19.9888 secs
  resp read:    0.0001 secs, 0.0000 secs, 0.0189 secs

Status code distribution:
  [200] 145080 responses
  [503] 4048 responses

Error distribution:
  [872] Get http://xx.xx.xx.xx?sleep=1000: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
```

それなりにエラー出てますね…

```console
$ kubectl get deployment -w
NAME                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
autoscale-go-h425w-deployment   0         0         0            0           7d7h
autoscale-go-k7nxb-deployment   0         0         0            0           17h
autoscale-go-vks24-deployment   0         0         0            0           9m23s
autoscale-go-vks24-deployment   1     0     0     0     9m33s
autoscale-go-vks24-deployment   1     0     0     0     9m33s
autoscale-go-vks24-deployment   1     0     0     0     9m33s
autoscale-go-vks24-deployment   1     1     1     0     9m34s
autoscale-go-vks24-deployment   7     1     1     0     9m34s
autoscale-go-vks24-deployment   7     1     1     0     9m34s
autoscale-go-vks24-deployment   7     1     1     0     9m34s
autoscale-go-vks24-deployment   7     7     7     0     9m35s
autoscale-go-vks24-deployment   10    7     7     0     9m36s
autoscale-go-vks24-deployment   10    7     7     0     9m36s
autoscale-go-vks24-deployment   10    7     7     0     9m36s
autoscale-go-vks24-deployment   10    10    10    0     9m37s
autoscale-go-vks24-deployment   10    10    10    1     9m38s
autoscale-go-vks24-deployment   10    10    10    2     9m39s
autoscale-go-vks24-deployment   13    10    10    2     9m40s
autoscale-go-vks24-deployment   13    10    10    2     9m40s
autoscale-go-vks24-deployment   13    10    10    2     9m40s
autoscale-go-vks24-deployment   13    13    13    2     9m41s
autoscale-go-vks24-deployment   13    13    13    3     9m44s
autoscale-go-vks24-deployment   13    13    13    4     9m44s
autoscale-go-vks24-deployment   13    13    13    5     9m44s
autoscale-go-vks24-deployment   13    13    13    6     9m45s
autoscale-go-vks24-deployment   13    13    13    7     9m46s
autoscale-go-vks24-deployment   13    13    13    8     9m46s
autoscale-go-vks24-deployment   13    13    13    9     9m47s
autoscale-go-vks24-deployment   12    13    13    9     10m
autoscale-go-vks24-deployment   12    13    13    9     10m
autoscale-go-vks24-deployment   12    13    13    9     10m
autoscale-go-vks24-deployment   12    12    12    9     10m
autoscale-go-vks24-deployment   11    12    12    9     10m
autoscale-go-vks24-deployment   11    12    12    9     10m
autoscale-go-vks24-deployment   11    12    12    9     10m
autoscale-go-vks24-deployment   11    11    11    9     10m
autoscale-go-vks24-deployment   12    11    11    9     11m
autoscale-go-vks24-deployment   12    11    11    9     11m
autoscale-go-vks24-deployment   12    11    11    9     11m
autoscale-go-vks24-deployment   12    12    12    9     11m
autoscale-go-vks24-deployment   12    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    11    11    10    11m
autoscale-go-vks24-deployment   12    11    11    10    11m
autoscale-go-vks24-deployment   12    11    11    10    11m
autoscale-go-vks24-deployment   12    11    11    10    11m
autoscale-go-vks24-deployment   12    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    12    12    10    11m
autoscale-go-vks24-deployment   11    11    11    10    11m
autoscale-go-vks24-deployment   10    11    11    10    12m
autoscale-go-vks24-deployment   10    11    11    10    12m
autoscale-go-vks24-deployment   10    11    11    10    12m
autoscale-go-vks24-deployment   10    10    10    10    12m
autoscale-go-vks24-deployment   9     10    10    10    12m
autoscale-go-vks24-deployment   9     10    10    10    12m
autoscale-go-vks24-deployment   9     9     9     9     12m
autoscale-go-vks24-deployment   10    9     9     9     13m
autoscale-go-vks24-deployment   10    9     9     9     13m
autoscale-go-vks24-deployment   10    9     9     9     13m
autoscale-go-vks24-deployment   10    10    10    9     13m
autoscale-go-vks24-deployment   10    10    10    10    13m
autoscale-go-vks24-deployment   9     10    10    10    13m
autoscale-go-vks24-deployment   9     10    10    10    13m
autoscale-go-vks24-deployment   9     9     9     9     13m
autoscale-go-vks24-deployment   8     9     9     9     13m
autoscale-go-vks24-deployment   8     9     9     9     13m
autoscale-go-vks24-deployment   8     8     8     8     13m
autoscale-go-vks24-deployment   9     8     8     8     14m
autoscale-go-vks24-deployment   9     8     8     8     14m
autoscale-go-vks24-deployment   9     8     8     8     14m
autoscale-go-vks24-deployment   9     9     9     8     14m
autoscale-go-vks24-deployment   9     9     9     9     14m
autoscale-go-vks24-deployment   10    9     9     9     14m
autoscale-go-vks24-deployment   10    9     9     9     14m
autoscale-go-vks24-deployment   10    9     9     9     14m
autoscale-go-vks24-deployment   10    10    10    9     14m
autoscale-go-vks24-deployment   10    10    10    10    14m
autoscale-go-vks24-deployment   11    10    10    10    14m
autoscale-go-vks24-deployment   11    10    10    10    14m
autoscale-go-vks24-deployment   11    10    10    10    14m
autoscale-go-vks24-deployment   11    11    11    10    14m
autoscale-go-vks24-deployment   10    11    11    10    14m
autoscale-go-vks24-deployment   10    11    11    10    14m
autoscale-go-vks24-deployment   10    11    11    10    14m
autoscale-go-vks24-deployment   10    10    10    10    14m
autoscale-go-vks24-deployment   9     10    10    10    15m
autoscale-go-vks24-deployment   9     10    10    10    15m
autoscale-go-vks24-deployment   9     9     9     9     15m
autoscale-go-vks24-deployment   8     9     9     9     15m
autoscale-go-vks24-deployment   8     9     9     9     15m
autoscale-go-vks24-deployment   8     8     8     8     15m
autoscale-go-vks24-deployment   9     8     8     8     15m
autoscale-go-vks24-deployment   9     8     8     8     15m
autoscale-go-vks24-deployment   9     8     8     8     15m
autoscale-go-vks24-deployment   9     9     9     8     15m
autoscale-go-vks24-deployment   9     9     9     9     15m
autoscale-go-vks24-deployment   10    9     9     9     15m
autoscale-go-vks24-deployment   10    9     9     9     15m
autoscale-go-vks24-deployment   10    9     9     9     15m
autoscale-go-vks24-deployment   10    10    10    9     15m
autoscale-go-vks24-deployment   10    10    10    9     15m
autoscale-go-vks24-deployment   10    10    10    10    15m
autoscale-go-vks24-deployment   11    10    10    10    16m
autoscale-go-vks24-deployment   11    10    10    10    16m
autoscale-go-vks24-deployment   11    10    10    10    16m
autoscale-go-vks24-deployment   11    11    11    10    16m
autoscale-go-vks24-deployment   11    11    11    11    16m
autoscale-go-vks24-deployment   10    11    11    11    16m
autoscale-go-vks24-deployment   10    11    11    11    16m
autoscale-go-vks24-deployment   10    10    10    10    16m
autoscale-go-vks24-deployment   9     10    10    10    16m
autoscale-go-vks24-deployment   9     10    10    10    16m
autoscale-go-vks24-deployment   9     9     9     9     16m
autoscale-go-vks24-deployment   8     9     9     9     16m
autoscale-go-vks24-deployment   8     9     9     9     16m
autoscale-go-vks24-deployment   8     8     8     8     16m
autoscale-go-vks24-deployment   9     8     8     8     17m
autoscale-go-vks24-deployment   9     8     8     8     17m
autoscale-go-vks24-deployment   9     8     8     8     17m
autoscale-go-vks24-deployment   9     9     9     8     17m
autoscale-go-vks24-deployment   9     9     9     9     17m
autoscale-go-vks24-deployment   10    9     9     9     17m
autoscale-go-vks24-deployment   10    9     9     9     17m
autoscale-go-vks24-deployment   10    9     9     9     17m
autoscale-go-vks24-deployment   10    10    10    9     17m
autoscale-go-vks24-deployment   10    10    10    10    17m
autoscale-go-vks24-deployment   9     10    10    10    17m
autoscale-go-vks24-deployment   9     10    10    10    17m
autoscale-go-vks24-deployment   9     9     9     9     17m
autoscale-go-vks24-deployment   8     9     9     9     17m
autoscale-go-vks24-deployment   8     9     9     9     17m
autoscale-go-vks24-deployment   8     8     8     8     17m
autoscale-go-vks24-deployment   7     8     8     8     17m
autoscale-go-vks24-deployment   7     8     8     8     17m
autoscale-go-vks24-deployment   7     7     7     7     17m
autoscale-go-vks24-deployment   6     7     7     7     17m
autoscale-go-vks24-deployment   6     7     7     7     17m
autoscale-go-vks24-deployment   6     6     6     6     17m
autoscale-go-vks24-deployment   5     6     6     6     17m
autoscale-go-vks24-deployment   5     6     6     6     17m
autoscale-go-vks24-deployment   5     5     5     5     17m
autoscale-go-vks24-deployment   4     5     5     5     18m
autoscale-go-vks24-deployment   4     5     5     5     18m
autoscale-go-vks24-deployment   4     4     4     4     18m
autoscale-go-vks24-deployment   3     4     4     4     18m
autoscale-go-vks24-deployment   3     4     4     4     18m
autoscale-go-vks24-deployment   3     3     3     3     18m
autoscale-go-vks24-deployment   2     3     3     3     18m
autoscale-go-vks24-deployment   2     3     3     3     18m
autoscale-go-vks24-deployment   2     2     2     2     18m
autoscale-go-vks24-deployment   1     2     2     2     18m
autoscale-go-vks24-deployment   1     2     2     2     18m
autoscale-go-vks24-deployment   1     1     1     1     18m
```

DESIREDがMAX13になり、AVAILABLEもMAX11と、--concurrency=80（デフォルト）のときのほぼ倍です。（503何でしょう気になります。）

Knative的にトラフィック制御してるなら、先ほど確認した`knative-serving`Namespace内にあるactivatorとautoscalerを使ってリクエスト数を計測し、Deploymentを調整しているはずですね。

Knativeではリクエストを処理するPod内の`queue-proxy`コンテナでRevision毎の同時リクエスト数を計測します。`queue-proxy`は`Autoscaler`に1秒毎に計測データを送信し、`Autoscaler`は2秒毎に計測データを評価します。その評価に基づき、`Autoscaler`はPod毎のリクエストが100回/秒になるように調整します。（デフォルトで）

Podの中身を見てみます。

```console
$ kubectl get pod -oyaml autoscale-go-xxxxx-deployment-yyyyyyyyyyyyyy
```

Cloud Run on GKEで実行するPodにおいてもPod内の`queue-proxy`コンテナが入っています。

また、`queue-proxy`はつぎのイメージを利用しており、Knative Servingの仕組みがそのまま当てはまりそうな雰囲気があります。

`image: gcr.io/knative-releases/github.com/knative/serving/cmd/queue@sha256:b5c759e4ea6f36ae4498c1ec794653920345b9ad7492731fb1d6087e3b95dc43`

さらに、環境変数`SERVING_AUTOSCALER`には`autoslacer`がセットされています。

`CONTAINER_CONCURRENCY`は`40`となっていて、`gcloud`コマンド経由で設定した同時リクエスト数が反映されていることがわかります。

つぎの図そのままに動いていそうです。

![autoscale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/46f70976-043c-15dd-378f-ee5960508eee.png)

`knative-serving` NamespaceのPodはKnativeの仕様通りの使われ方がしているとすると、`cloudrun-controller`って何者なんでしょうか？

```console
$ kubectl get pod cloudrun-controller-5859fbcc44-2cxht  -n knative-serving -oyaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    sidecar.istio.io/inject: "false"
  creationTimestamp: 2019-05-04T09:00:34Z
  generateName: cloudrun-controller-5859fbcc44-
  labels:
    app: cloudrun-controller
    pod-template-hash: 5859fbcc44
  name: cloudrun-controller-5859fbcc44-2cxht
  namespace: knative-serving
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: cloudrun-controller-5859fbcc44
    uid: 138094bd-6e4b-11e9-98c9-42010a80013f
  resourceVersion: "1165"
  selfLink: /api/v1/namespaces/knative-serving/pods/cloudrun-controller-5859fbcc44-2cxht
  uid: 13c4b9c5-6e4b-11e9-98c9-42010a80013f
spec:
  containers:
  - args:
    - -logtostderr=true
    - -stderrthreshold=INFO
    image: gcr.io/gke-release/knative/gke-internal/knative/cloudrun/cmd/controller@sha256:c0a1c84ee39176a0ecefb16e058de25e5168eea7e4927e9e558c59c2c5f1bfd7
    imagePullPolicy: IfNotPresent
    name: cloudrun-controller
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: cloudrun-controller-token-hpzk9
      readOnly: true
  dnsPolicy: ClusterFirst
  nodeName: gke-c-run-default-pool-8d7008c0-0vz9
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: cloudrun-controller
  serviceAccountName: cloudrun-controller
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: cloudrun-controller-token-hpzk9
    secret:
      defaultMode: 420
      secretName: cloudrun-controller-token-hpzk9
status:
  conditions:
（略）
```

中身を見てみると、使っているイメージは`gcr.io/gke-release/knative/gke-internal/knative/cloudrun/cmd/controller@sha256:xxxx`です。

[Quotas and Limits](https://cloud.google.com/run/quotas)を見る限り、Knativeのスコープ外の項目も多いので、そういうのを管理してたりするんでしょうか。



## Revisionの確認

これまで何度か（記事に書いてないのも含め）設定を変更してきましたが、Revisionは残っているのでしょうか？みてみましょう。

```console
$ kubectl get revision
NAME                 SERVICE NAME                 GENERATION   READY   REASON
autoscale-go-h425w   autoscale-go-h425w-service   1            True
autoscale-go-k7nxb   autoscale-go-k7nxb-service   2            True
autoscale-go-vks24   autoscale-go-vks24-service   3            True
```

それぞれの管理下にあるDeploymentも確認できます。

```console
$ kubectl get deployment
NAME                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
autoscale-go-h425w-deployment   0         0         0            0           7d9h
autoscale-go-k7nxb-deployment   0         0         0            0           19h
autoscale-go-vks24-deployment   0         0         0            0           158m
```

こんなイメージです。

![background.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/2ffacaa1-3514-a751-6d62-ea6057ac2d29.png)


Knativeの方のServiceを見てみると、リクエストはすべてGENERATION 3で受けるものとして保存されていることがわかります。

```console
$ kubectl get ksvc autoscale-go
NAME           DOMAIN                             LATESTCREATED        LATESTREADY          READY   REASON
autoscale-go   autoscale-go.default.example.com   autoscale-go-vks24   autoscale-go-vks24   True

$ kubectl get ksvc autoscale-go -oyaml
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
  annotations:
    client.knative.dev/user-image: gcr.io/knative-samples/autoscale-go:0.1
    serving.knative.dev/creator: toshi0607@mercari.com
    serving.knative.dev/lastModifier: toshi0607@mercari.com
  creationTimestamp: 2019-05-05T02:36:29Z
  generation: 3
  name: autoscale-go
  namespace: default
  resourceVersion: "2222578"
  selfLink: /apis/serving.knative.dev/v1alpha1/namespaces/default/services/autoscale-go
  uid: 9615e4f5-6ede-11e9-98c9-42010a80013f
spec:
  runLatest:
    configuration:
      revisionTemplate:
        metadata:
          creationTimestamp: null
          initializers:
            pending: null
          labels:
            client.knative.dev/nonce: ifwrwzlhkh
        spec:
          container:
            image: gcr.io/knative-samples/autoscale-go@sha256:e5e89c5fd57c717b49d41be89faebc526bdcda017e898ae86c2bf20f5cd339b5
            name: ""
            resources:
              requests:
                cpu: 400m
          containerConcurrency: 40
          timeoutSeconds: 300
status:
  address:
    hostname: autoscale-go.default.svc.cluster.local
  conditions:
  - lastTransitionTime: 2019-05-12T09:27:32Z
    status: "True"
    type: ConfigurationsReady
  - lastTransitionTime: 2019-05-12T09:27:32Z
    status: "True"
    type: Ready
  - lastTransitionTime: 2019-05-12T09:27:32Z
    status: "True"
    type: RoutesReady
  domain: autoscale-go.default.example.com
  domainInternal: autoscale-go.default.svc.cluster.local
  latestCreatedRevisionName: autoscale-go-vks24
  latestReadyRevisionName: autoscale-go-vks24
  observedGeneration: 3
  traffic:
  - percent: 100
    revisionName: autoscale-go-vks24
```

GKE上にデプロイしたCloud Runであっても、そうでないものと同様にコンソール上でステータスを確認できます。

<img width="1130" alt="console.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/4d830c7e-06b7-c24a-bc84-1e88a6184d62.png">


autoscale-goを見てみると、現在指しているRevisionのYAMLファイルも確認できます。`kubectl describe revision`や`gcloud beta revisions describe`で表示されるものとほぼ同じです。

<img width="1245" alt="run_detail.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46547/a2242ede-c8fc-895b-b731-47996eccf9cd.png">


コマンドの方はそれぞれ`Log URL`分が多く、`gcloud`はさらにannotationとして`creator`や`lastModifier`のアカウント情報が付加されます。

## 今後追加されるかもしれない機能

ここまで見てきたとおり、Cloud Run（少なくともon GKE）ではKnative Servingの機能がほとんど利用できます。

`gcloud`コマンドやCloud RunのUI上ではトラフィックの分割（によるブルーグリーンデプロイメントやカナリアリリース）はできませんが、直接Knativeのリソースをいじれば利用できるのかもしれません。

コンソールではRevisionへ流すトラフィック比率の表示については実装されています。

コマンドやUIから利用できる日もそう遠くはないのではないかなと思っています。

[Build](https://github.com/knative/build)はGCRとより密な感じで組み込めるかもしれません。

今回コンテナのイメージはすでに登録されているものを使いましたが、コードからそんなに体験を損なわずにシュッとデプロイされた状態にできる日はこれまた遠くないと思っています。

[Eventing](https://github.com/knative/eventing)については[v0.5](https://medium.com/knative/announcing-knative-v0-5-release-cfe646ca8e30)でまた実装が激しく変化したり、Knativeを利用したriffというプロダクトで[Eventingへの依存を切った](https://github.com/projectriff/riff/pull/1237)り、Eventing自体がどういう方向に進むかわからないですね。

## 参考資料

* [Concepts（Cloud Run）](https://cloud.google.com/run/docs/concepts)
* [Concurrency（Cloud Run）](https://cloud.google.com/run/docs/about-concurrency)
* [steren/awesome-cloudrun](https://github.com/steren/awesome-cloudrun)
* [Knative on GitHub](https://github.com/knative)
* [https://knative.dev](https://knative.dev/)
* [Knativeの歩き方 KubernetesからServerlessを訪ねて（PDF、ePubセット版） #技術書典](https://booth.pm/ja/items/1309468)（手前味噌）
* [入門 Knative 〜KubernetesとServerlessとの出会い〜](https://speakerdeck.com/toshi0607/getting-started-with-knative-90ff6190-1251-4b7b-ada9-bbba5a8ca4b8)（手前味噌）

## 余談

* Servingのリポジトリにある[モニタリング系のリソース](https://github.com/knative/serving/tree/master/config/monitoring
)でリクエスト数とPod数の推移を可視化したかったがうまくいかなかった
  * `iptables v1.6.0: can't initialize iptables table 'nat': Permission denied (you must be root)
`については`securityContext`を場当たり的にいじった[yaml](https://github.com/toshi0607/monitor-for-Cloud-Run-on-GKE)を準備して適用し、Grafanaが表示され一部のメトリクスが送信されたが、肝心のメトリクスはほとんど送信されてなさそう（少なくとも表示はされない）