GKE試行（その4：「GKEデプロイ->サービス公開」

# お題
[前回](https://qiita.com/drafts/d3c28b67dbabf3df88be)、クラスタ作るところまでやったので、いよいよアプリをGKE上にデプロイする。

# 環境
[前回](https://qiita.com/sky0621/items/2faf4f7e6b2c9b269945#環境)と同じ。

<pre>
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.7", GitCommit:"dd5e1a2978fd0b97d9b78e1564398aeea7e7fe92", GitTreeState:"clean", BuildDate:"2018-04-19T00:05:56Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"9+", GitVersion:"v1.9.7-gke.6", GitCommit:"9b635efce81582e1da13b35a7aa539c0ccb32987", GitTreeState:"clean", BuildDate:"2018-08-16T21:33:47Z", GoVersion:"go1.9.3b4", Compiler:"gc", Platform:"linux/amd64"}
</pre>

# 前提
- 自前でGCPプロジェクトは契約済み
- gcloudをローカルで使える状態になっている

# 実践
## １）クラスタ作成
前回はクラウドコンソールで作成した。今回はgcloudコマンドで作成してみる。
<pre>
$ gcloud container clusters create go-webapi-for-gke-study-cluster-1 --zone asia-northeast1-a
WARNING: Starting in 1.12, new clusters will have basic authentication disabled by default. Basic authentication can be enabled (or disabled) manually using the `--[no-]enable-basic-auth` flag.
WARNING: Starting in 1.12, new clusters will not have a client certificate issued. You can manually enable (or disable) the issuance of the client certificate using the `--[no-]issue-client-certificate` flag.
WARNING: Currently VPC-native is not the default mode during cluster creation. In the future, this will become the default mode and can be disabled using `--no-enable-ip-alias` flag. Use `--[no-]enable-ip-alias` flag to suppress this warning.
This will enable the autorepair feature for nodes. Please see
https://cloud.google.com/kubernetes-engine/docs/node-auto-repair for more
information on node autorepairs.

WARNING: Starting in Kubernetes v1.10, new clusters will no longer get compute-rw and storage-ro scopes added to what is specified in --scopes (though the latter will remain included in the default --scopes). To use these scopes, add them explicitly to --scopes. To use the new behavior, set container/new_scopes_behavior property (gcloud config set container/new_scopes_behavior true).
Creating cluster go-webapi-for-gke-study-cluster-1...done.                                                                                                                                                 
Created [https://container.googleapis.com/v1/projects/【プロジェクトID】/zones/asia-northeast1-a/clusters/go-webapi-for-gke-study-cluster-1].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-northeast1-a/go-webapi-for-gke-study-cluster-1?project=【プロジェクトID】
kubeconfig entry generated for go-webapi-for-gke-study-cluster-1.
NAME                               LOCATION           MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
go-webapi-for-gke-study-cluster-1  asia-northeast1-a  1.9.7-gke.6     xxx.xxx.xxx.xxx n1-standard-1  1.9.7-gke.6   3          RUNNING
</pre>
できた。
![01.png](https://qiita-image-store.s3.amazonaws.com/0/180599/be25b123-4f8b-479e-0bb6-102293479efe.png)
以下は詳細。
![02.png](https://qiita-image-store.s3.amazonaws.com/0/180599/392715a9-4d3c-cc22-5eae-8e26b0fcf2a7.png)
![03.png](https://qiita-image-store.s3.amazonaws.com/0/180599/908ada7d-7bba-3328-9f7f-f709144f3c2f.png)
![04.png](https://qiita-image-store.s3.amazonaws.com/0/180599/55f7957d-8b2a-0d48-7e63-7b6cba1d04ab.png)

## ２）クラスタをミニマム仕様で再作成
作っておきながらなんだけど、勉強用途でn1-standard-1マシンを３台立ち上げ続けるのは避けたい（でも、いちいち落とすのは忘れそう）ので、無料枠内でできるミニマム仕様を探る。
当然、先人がいるので参考にする。
https://blog.a-know.me/entry/2018/06/17/220222

参考サイトのようにプリエンプティブVMを使い、スペックもf1-microのディスクサイズ10GBにしてトライ。
参考サイトではエラーになると書かれてあるノード数 1 も、あえて付けてみた。
<pre>
$ gcloud container clusters create go-webapi-for-gke-study-cluster-1-min --zone asia-northeast1-a --preemptible --machine-type=f1-micro --disk-size=10 --num-nodes=1
　　〜省略〜
ERROR: (gcloud.container.clusters.create) ResponseError: code=400, message=Clusters of f1-micro instances must contain at least 3 nodes. Please make the cluster larger or use a different machine type.
</pre>
怒られた。
おとなしくノード数 3 でリトライ。
<pre>
$ gcloud container clusters create go-webapi-for-gke-study-cluster-1-min --zone asia-northeast1-a --preemptible --machine-type=f1-micro --disk-size=10 --num-nodes=3
　　〜省略〜
Creating cluster go-webapi-for-gke-study-cluster-1-min...done.                                                                                                                                             
Created [https://container.googleapis.com/v1/projects/【プロジェクトID】/zones/asia-northeast1-a/clusters/go-webapi-for-gke-study-cluster-1-min].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-northeast1-a/go-webapi-for-gke-study-cluster-1-min?project=【プロジェクトID】
kubeconfig entry generated for go-webapi-for-gke-study-cluster-1-min.
NAME                                   LOCATION           MASTER_VERSION  MASTER_IP       MACHINE_TYPE  NODE_VERSION  NUM_NODES  STATUS
go-webapi-for-gke-study-cluster-1-min  asia-northeast1-a  1.9.7-gke.6     xxx.xxx.xxx.xxx f1-micro      1.9.7-gke.6   3          RUNNING
</pre>

ちなみに、gcloudコマンドで各種操作を行うやり方は以下に書いてある。
https://cloud.google.com/kubernetes-engine/docs/clusters/operations?hl=ja

クラウドコンソールで見てみる。
![05.png](https://qiita-image-store.s3.amazonaws.com/0/180599/06760e02-bbfe-1188-4696-ee9fb4e2395b.png)

できた後でノード数下げられないか確認。
![06.png](https://qiita-image-store.s3.amazonaws.com/0/180599/b6fb3b1a-36d7-e894-de4c-79a5d505f7bb.png)
ダメですね。

## ３）アプリをデプロイ
[公式のクイックスタート](https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja)に則るなら、以下のように kubectl コマンド一発でとりあえずデプロイはできるらしい。
<pre>
$ kubectl run go-webapi-for-gke-study-server --image gcr.io/【プロジェクトID】/go-webapi-for-gke-study@sha256:4d1897773110c4ed095fd43d6f08d946c2a9692245cbdf653a689c2dd64e3419 --port 80
deployment "go-webapi-for-gke-study-server" created
</pre>
「deployment」が作成されたとの簡素なメッセージ。
「デプロイメントが作られた」って、どういうことだ？？？
[公式の説明](https://cloud.google.com/kubernetes-engine/docs/concepts/deployment?hl=ja)によると、「**Deployment は複数の同じポッドのセットを表します。**」とのこと。
先ほどの kubectl コマンドにより『ポッドのセットが作られた（そして、その中に（すべてに？）Dockerコンテナがデプロイされた）』ということか。
（クラスタ内に特定のインスタンスとして？　クラスタ内の特定の（or すべての）ノード（＝GCEインスタンス）内に？）
　
次は、「ポッド」。
これは[公式の説明](https://cloud.google.com/kubernetes-engine/docs/concepts/pod?hl=ja)によると、
「**ポッドは、Kubernetes でデプロイできる最小かつ最も基本的なオブジェクトです。ポッドは、クラスタ内で実行されるプロセスの単一インスタンスを表します。**」とのこと。
「**ポッドは、クラスタ内のノードで実行されます。**」ともある。今時点の理解で登場人物を構造で表してみると、こんな感じか。
<pre>
／ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー＼
｜①クラスタ（＝GCEインスタンスグループ）　　　　　　　　　　　　　　｜
｜　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　｜
｜　／ーーーーーーーーーーーーーーーーーーーーーーーーーーー＼　　　　｜
｜　｜②ノード（＝GCEインスタンス）　　　　　　　　　　　　｜　　　　｜
｜　｜　　　　　　　　　　　　　　　　　　　　　　　　　　　｜　　　　｜  x Ｎ
｜　｜　／ーーーーーーーーーーーーーーーーーーーー＼　　　　｜　　　　｜
｜　｜　｜③ポッド（＝論理ホスト）　　　　　　　　｜　　　　｜  x Ｎ ｜
｜　｜　｜　　　　　　　　　　　　　　　　　　　　｜　　　　｜　　　　｜
｜　｜　｜　／ーーーーーーーーーーーーー＼　　　　｜  x Ｎ ｜　　　　｜
｜　｜　｜　｜④コンテナ　　　　　　　　｜　　　　｜　　　　｜　　　　｜
｜　｜　｜　｜　　　　　　　　　　　　　｜  x Ｎ ｜　　　　｜　　　　｜
｜　｜　｜　｜　／ーーーーーー＼　　　　｜　　　　｜　　　　｜　　　　｜
｜　｜　｜　｜　｜⑤アプリ　　｜  x Ｎ ｜　　　　｜　　　　｜　　　　｜
｜　｜　｜　｜　｜　　　　　　｜　　　　｜　　　　｜　　　　｜　　　　｜
｜　｜　｜　｜　＼ーーーーーー／　　　　｜　　　　｜　　　　｜　　　　｜
｜　｜　｜　＼ーーーーーーーーーーーーー／　　　　｜　　　　｜　　　　｜
｜　｜　＼ーーーーーーーーーーーーーーーーーーーー／　　　　｜　　　　｜
｜　＼ーーーーーーーーーーーーーーーーーーーーーーーーーーー／　　　　｜
＼ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー／
</pre>
「クラスタ」がGKEの領域で「ノード」と「ポッド」はk8s自体の概念。
各階層で配下に複数持てることを「x Ｎ」で表したけど、階層によって少し意味合いが違う。
②と③の「x Ｎ」はスケールする意味を表し、それ以外は複数の種類を持てることを表す。
　
先の kubectl コマンドにより、デプロイメント＝複数のポッドが作られた。
実際、クラウドコンソールで確認してみると、GKEの「ワークロード」（＝Dockerコンテナ）に「タイプ「Deployment」」で情報が載っていた。
https://cloud.google.com/kubernetes-engine/docs/concepts/kubernetes-engine-overview?hl=ja#workloads
![07.png](https://qiita-image-store.s3.amazonaws.com/0/180599/e8a82951-fb33-a5f5-6ee2-e132d836cc07.png)
詳細情報に飛ぶと以下のような感じ。
![08.png](https://qiita-image-store.s3.amazonaws.com/0/180599/278d2aee-88a0-14a0-3cd1-1a93d3d82999.png)
![09.png](https://qiita-image-store.s3.amazonaws.com/0/180599/76e00676-27bb-5932-af9f-e54c55455b52.png)

　
これで、アプリのGKEデプロイは完了しアクセスできるのか？　とクラスタのエンドポイントIPにアクセスしてみる。応答返ってこない。
いや、ダメだろうというのはわかる。一応ドキュメント読んでるので。インターネット上からアクセス可能な状態にするにはまた別の概念「サービス（＝要するにロードバランサのようだけど）」が必要。
実際、[公式のクイックスタート](https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja)にもデプロイした後に「Deployment を公開する」という手順がある。
上のデプロイメントの詳細画像の最下部に「Services　一致するサービスはありません」とあり、公開状態でないことが表されている。

## ４）アプリを公開
アプリの公開には Service を作成するとある。 kubectl コマンド使うと以下のようにする。
<pre>
$ kubectl expose deployment go-webapi-for-gke-study-server --type "LoadBalancer"
service "go-webapi-for-gke-study-server" exposed
</pre>
クラウドコンソールで確認してみると、今まで存在しなかったサービスが出来ている。
![10.png](https://qiita-image-store.s3.amazonaws.com/0/180599/ad608b0c-ad79-ae42-42f8-7fd422b912e4.png)
ワークロードでも「一致するサービスはありません」だった箇所で紐付けがされている。
![11.png](https://qiita-image-store.s3.amazonaws.com/0/180599/1858082d-2016-5296-fea9-50750678cbc1.png)

## ５）アクセス確認
サービスのエンドポイントに対してブラウザでアクセス
![13.png](https://qiita-image-store.s3.amazonaws.com/0/180599/d3c3f467-893f-9ef2-b5af-879a59525a55.png)
やった。
　
アプリ自体、ポート80で受け付けるように作り、Dockerコンテナでもポート80でExposeし、k8sのデプロイメント作成時もポート80でExposeしたなら、サービス公開にてインターネット上からアクセス可能になる。
　
ちなみに、GCPのダッシュボードを見てみると、GCEインスタンス３個とGCSバケット２個の記録があった。
GCEインスタンスの方は、GKEのクラスタ作成時にノードプールのサイズを「３」で定義しているから。
GCSバケットの方は、１つはGAEのだった。もう１つはCloud Build使ったことで作られたものの様子。ソースを固めたものか？
![14.png](https://qiita-image-store.s3.amazonaws.com/0/180599/ae1ba730-9dd7-5216-b91d-461614ba4a76.png)
![15.png](https://qiita-image-store.s3.amazonaws.com/0/180599/b07094bc-25ce-81c0-04d1-69a25c68923a.png)
　
あと、一応、StackdriverLoggingでもログを確認してみる。アプリでログ出力先を標準出力にしておくとGKEで勝手に拾ってSDLに流してくれるので楽。
![16.png](https://qiita-image-store.s3.amazonaws.com/0/180599/9d162658-a463-71ee-55e9-cfaf94ba6747.png)

# まとめ
[公式のクイックスタート](https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja)をやれば５分で終わったであろう内容を、わざわざ自前でしょうもないWebアプリを作ってDockerコンテナ化し、公式ドキュメントその他を読み込みながら、Cloud Source RepositoriesやらCloud Build、Container Registryを介して、GKEにデプロイするという手順を取った結果、０．５人日以上かけた気がする。
けど、５分じゃ、ただなんとなくわかった気になって終わってただろうから、よしとしよう。
ただ、当然、そもそもk8sの機能やGKEの機能としてもわかっていないことだらけなので、まだまだ勉強は必要。