Google Kubernetes Engine Quickstart++


[Google Kubernetes Engine > Quickstart](https://cloud.google.com/kubernetes-engine/docs/quickstart) の私的メモです。

Google Cloud Platform 特有のサービス体系を知るためのもので、Kubernetes については詳しく触れていません。以下に該当する場合は Kubernetes がどのような経緯で生まれたのか？をまず知ることをお勧めします。

* 仮想マシンとコンテナの区別がつかない。
* Server = Machine の発想が抜けていない。
* Service Discovery の存在意義がよくわからない。

>Machines can run any server, so we don’t dedicate specific machines to specific server programs. There’s no specific machine that runs our mail server, for example. Instead, resource allocation is handled by our cluster operating system, **Borg**.
- [Goole SRE Book > The Production Environment at Google, from the Viewpoint of an SRE
](https://landing.google.com/sre/book/chapters/production-environment.html)

* [Kubernetes Up And Running](
https://www.safaribooksonline.com/library/view/kubernetes-up-and/9781491935668/)
* [Kubernetes > Concepts](https://kubernetes.io/docs/concepts/)

## Before you begin

### Google Cloud Platform

#### Project

Google Cloud Platform のリソース管理は Organization > Folders > Projects > Resources という階層構造になっています。それぞれのレイヤーでアクセス権限を設定することができるため、どのように Project を配置するかが運用の肝になります。

* [Google Cloud > Resource Manager > Resource Hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy)

例では Folders に Department > Team > Product という階層を作り、Product の下に環境(本番/検証/開発)ごとの Project を持つ方法が紹介されています。

Google Kubernetes Engine を運用する上で、この Project の分け方がベストプラクティスかはまだ見えていませんが、Google でのアクセス制限の流儀なのかと思います。AWS の IAM のようにロール/グループ/インラインポリシーで設定する方法では、ユーザに対して何が許可されているのかが俯瞰しづらいですが、この階層型のリソース管理方法なら、階層の位置によってどこまでのリソースが扱えるのかが把握しやすそうです。

一つのアカウントで作成可能な Project 数は制限されており、上限数はアカウントの利用実績によって異なるようで明記されていません。制限にかかった場合は、フォームより申請する必要があります。

* [Project Quota Request FAQ's page](https://support.google.com/cloud/answer/6330231)

Google Cloud Platform を利用するには Project が必要で、請求アカウントと紐付けておく必要があります。

* [Cloud Billing > Modify a Project's Billing Settings
](https://cloud.google.com/billing/docs/how-to/modify-project)

#### Free Tier

Google Cloud Platform では、初回に12ヶ月間を試用期間とみなし、試用期間のみ有効な $300 のクレジットが付与されます。永年無料の利用枠もあります。

* [Google Cloud Plafform Free Tier](https://cloud.google.com/free/)

試用期間中の利用制限もあります。試用期間中は上限緩和の申請ができず [SLA](https://cloud.google.com/terms/sla/) も適用されません。この場合は、通常アカウントへ更新することが必要になります。試用期間中のクレジット $300 は使えるようです。

* [Supplemental Terms and Conditions For Google Cloud Platform Free Trial](https://cloud.google.com/terms/free-trial/)

#### Regions ans Zones

Google Compute Engine は、日本国内の Tokyo リージョン `asia-northeast1` に3つのゾーン `asia-northeast1-(a|b|c)` があります。(2018/07時点)

Amazon Web Services のゾーン `ap-northeast-1(a|b|c|d)` に慣れていると `asia-northeast-1(a|b|c)` と間違えやすいので注意してください。

* [Compute Engine > Documentation > Regions and Zones](https://cloud.google.com/compute/docs/regions-zones/)

## Choosing a shell

### Google Cloud Shell vs. Local Shell

[Google Cloud Shell](https://cloud.google.com/shell/docs/quickstart) により 5GB の永続ストレージを持つ仮想マシンが提供され GCP コンソール上からシェル操作が可能です。ローカル PC に環境を準備しなくても Web ブラウザ上で [gcloud](https://cloud.google.com/sdk/gcloud/reference/) コマンドを実行することができます。docker / git などの主要なコマンドもインストールされているので、ほとんどの運用作業は Cloud Shell で完結します。[利用制限](https://cloud.google.com/shell/docs/limitations)はありますが、[無料](https://cloud.google.com/shell/pricing)で使えます。

Local PC 上のシェルで実行したい場合は gcloud および kubectl コマンドをインストールします。Python 2.7 が必要です。

```
$ gcloud components install kubectl
```

* [Cloud SDK > Quickstarts](https://cloud.google.com/sdk/docs/quickstarts)

## Configuring Default Settings for gcloud

#### compute/zone

多くのコマンドでは `--zone` オプションでゾーン指定を行います。毎回指定しなくても済むように `config` コマンドで`compute/zone` を設定しておくことで、デフォルト値として採用されます。

```shell
$ gcloud config set compute/zone asia-northeast1-a
$ gcloud config list
...
[compute]
...
zone = asia-northeast1-a
...
```

#### container/new_scopes_behavior

`--enable-cloud-endpoints` オプションは deprecated となっており、cluster-version v1.10 から使えなくなる WARNING が出力されます。

>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).

`container/new_scopes_behavior` を有効にしておきます。

```
$ gcloud config set container/new_scopes_behavior true
```

## Creating a Kubernetes Engine cluster

Google Kubernetes Engine 上にクラスタを作成します。

```
$ gcloud container clusters create <CLUSTER_NAME> \
  --zone=asia-northeast1-a \
  --machine-type=n1-standard-1 \
  --num-nodes=3
```

2017年11月28日以降、ノード数や構成によってクラスタ管理料金が課金されることはありません。ノードとして生成される Compute Engine の仮想マシンの料金のみになります。

>Effective 28 November 2017, Kubernetes Engine no longer charges the flat fee per hour per cluster for cluster management, regardless of cluster size.
- [Kubernetes Engine > Pricing](https://cloud.google.com/kubernetes-engine/pricing)

* [Google Cloud Platform Blog - Cutting cluster management fees on Google Kubernetes Engine](https://cloudplatform.googleblog.com/2017/11/Cutting-Cluster-Management-Fees-on-Google-Kubernetes-Engine.html)

デフォルトの n1-starndard-1 (1vCPU / 3.75GB Memory) の場合、[継続利用割引](https://cloud.google.com/compute/pricing#sustained_use)が適用されるとして 3,500 円/月が目安です。デフォルトのノード数 3 のままであれば、約 10,500 円/月が課金されます。 

* [Google Cloud Platform Pricing Calculator](https://cloud.google.com/products/calculator/#tab=container)

共有 vCPU タイプの f1-micro も選べますが、ノード数は 3 以上とする必要があります。そもそも、割り当てたリソース通りの性能を求めるならば、共有 vCPU タイプの f1-micro / g1-small を使うことは適切ではないと思われます。

[GCP Console > Compute Engine > VM Instances](https://console.cloud.google.com/compute/instances) を確認すると `gke-<CLUSTER_NAME>-pool-*` としてクラスタが作成されていることがわかります。

クラスタが起動したら `kubectl` の設定 `~/.kube/config` を生成します。`current-context` も切り替わります。

```
$ gcloud container clusters get-credentials <CLUSTER_NAME>

$ kubectl config view
...
$ kubectl config current-context
...
```
* [Configuring Cluster Access for kubectl](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl)

## Deploying an application to the cluster

### Creating the Deployment

[Google Container Registry](https://cloud.google.com/container-registry/) にデプロイしたいイメージを push しておきます。

```javascript:main.js
var http = require('http');

var handleRequest = function(request, response) {
  console.log(request.url);
  response.writeHead(200);
  response.end('Hello World!');
};
var server = http.createServer(handleRequest);
server.listen(8080);
```
```dockerfile:Dockerfile
FROM node:6.9.2
EXPOSE 8080
COPY main.js .
CMD node main.js
```
```shell
$ ls
Dockerfile main.js
$ export PROJECT_ID=$(gcloud config get-value project -q)
$ docker build -t gcr.io/${PROJECT_ID}/hello-app:v1 .
$ gcloud docker -- push gcr.io/${PROJECT_ID}/hello-app:v1
```

[gcloud docker](https://cloud.google.com/sdk/gcloud/reference/docker) コマンドは Docker v18.03 以上からは使えません。[Docker credential helper](https://github.com/GoogleCloudPlatform/docker-credential-gcr) を設定して `docker` コマンドを使います。

```
$ gcloud auth configure-docker
$ docker push gcr.io/${PROJECT_ID}/hello-app:v1
``` 

ただし、それ以前のバージョンの docker コマンドでは、バグにより credential helper の設定がされていると `docker build` に非常に時間がかかります。

>If you use a credential helper (that is, docker-credential-gcr or docker-credential-gcloud via gcloud auth configure-docker), you should upgrade your Docker clients to 18.03 or above. A bug in earlier versions of the Docker client slows down docker builds dramatically when credential helpers are configured.
- [Deprecation Notice > gcloud docker and Docker clients above version 18.03](https://cloud.google.com/container-registry/docs/support/deprecation-notices#wzxhzdk4wzxhzdk5_gcloud_docker_and_docker_clients_above_version_1803
)

2018/07 時点で Google Cloud Shell にインストールされているバージョンは v17.06 のため、記載の通り `docker build` 時に、ほぼフリーズ状態となりました。この場合は `~/.docker/config.json` の `credHelpers` の設定を削除して `gcloud docker` コマンドを利用します。

```
$ docker --version
Docker version 17.06.0-ce, build 02c1d87

$ cat ~/.docker/config.json
{
  ...
  "credHelpers": {
  }
}
```

Container Registry のイメージファイルは Cloud Storage のバケット `artifacts.<PROJECT_ID>.appspot.com` へ保管されます。利用料金は Cloud Storage に準じます。

>Container Registry only charges for the Cloud Storage storage and network egress used by your Docker images. 
- [Container Registry > Pricing](https://cloud.google.com/container-registry/pricing)

[kubectl run](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#run) で push しておいたコンテナイメージをクラスタにデプロイします。

```shell
# デプロイするクラスタを確認
$ kubectl config current-context
...

$ kubectl run hello-app --image=gcr.io/${PROJECT_ID}/hello-app --port=8080
deployment "hello-app" created

$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
hello-app-5844bb4777-4gwbm   1/1       Running   0          11m
```

### Exposing the Deployment

外部ネットワークからのアクセスを受け付ける場合は [kubectl expose](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#expose) でロードバランサを作成します。

```shell
$ kubectl expose deployment hello-app --type=LoadBalancer \
    --port=80 --target-port=8080

$ kubectl get service hello-app
NAME        TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE
hello-app   LoadBalancer   10.0.10.222   35.194.106.55   80:30505/TCP   15m

$ curl http://35.194.106.55
```

[GCP Cmnsole > Network services > Load balancing](https://console.cloud.google.com/net-services/loadbalancing/loadBalancers/list) を確認するとロードバランサが作成されていることがわかります。forwarding rule は５つまで同一料金で 3,000 円/月、一つ増やすごとに 900 円/月が目安です。

### Clean up

[kubectl delete](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-image-em-) でリソースを削除します。

#### Deleting a service

`kubectl delete service <NAME>` でロードバランサを削除します。非同期に削除されるため、forwarding rules を確認して、完全に遮断するまで待ちます。

```shell
$ kubectl delete service hello-app
...
# ロードバランサが削除されたことを確認する
$ gcloud compute forwarding-rules list
...
```

#### Deleting a deployment

`kubectl delete pod <NAME>` は Pod の再起動を意味します。Deployment によって、新たな Pod が再生成されます。

```
$ kubectl delete pod hello-app-6b66495ff6-6grrf

$ kubectl get pods
NAME                         READY     STATUS        RESTARTS   AGE
hello-app-6b66495ff6-6grrf   1/1       Terminating   0          20m
hello-app-6b66495ff6-dk2lf   1/1       Running       0          4s
```

Deployment を削除するには `kubectl delete deployments <NAME>` を実行します。

```
$ kubectl delete deployments hello-app
deployment "hello-app" deleted
$ kubectl get pods
No resources found.
```

#### Deleting a cluster

クラスタを削除しないと、作成時に指定したノード数の仮想マシンが Compute Engine 上で起動したままなので、料金が発生しつづけます。無料なのはクラスタ管理料です。

[gcloud container clusters delete](https://cloud.google.com/sdk/gcloud/reference/container/clusters/delete) でクラスタを削除します。

```
$ gcloud container clusters delete <CLUSTER_NAME>
```

## Conclusions

(TODO)