個人向けの格安Kubernetes環境はGKEが良さそう

#はじめに
安い個人k8s環境を色々模索してきて、これまで以下のようなものに手を出しました。

- Docker for mac
→唸り始めるとどうしようもないので、あまり動かしたくない。

- Microk8s on Lightsail 1Core 500MB
→動きませんでした。（そもそも稼働条件を満たしていない）

- k3s on Lightsail 1Core 500MB
→一応最小の稼働条件ですが、ギリギリ動きませんでした。

- k3s or kubeadm on Raspi
→現役です。ただ外部向けとかインターネットからアクセスしたいアプリは動かしにくいし、Arm64イメージをビルドするのが面倒。

ずっとAWSばかり使ってきたので仮想マシンはLightsailが一番安いと思い込んでいました。
今回、下記の素晴らしい記事を参考にGKEを作成したらすごく良かったのでそのメモです。

>趣味GKEのIngressを無料で済ませる
https://livingalone.hatenablog.com/entry/2020/04/19/100000

>Kubernetes: The Surprisingly Affordable Platform for Personal Projects
http://www.doxsey.net/blog/kubernetes--the-surprisingly-affordable-platform-for-personal-projects

### Preemptive Instanceへの対応
また今回Nodeで利用するプリエンプティブル VMへの対応として、NodeIPをRoute53に同期するカスタムコントローラーも作成しましたので、最後に紹介します。
https://github.com/jlandowner/kubernetes-route53-sync

# GKE作成時の設定

GKEはControl Planeが無料なので、基本的にはNodeの料金が主です。
Nodeのリソース節約のために、GKEの作成画面で色々オプションを削除していきます。チェックは基本外します。

![スクリーンショット 2020-04-27 20.34.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/1dc561db-e44c-5bb7-9986-7b5dc52b591a.png)

まずNode数をデフォルトの3から減らします(今回は1つに)

インスタンスタイプはe2-smallのPreemptive Instance
https://cloud.google.com/compute/vm-instance-pricing?hl=ja#e2_sharedcore_machine_types
なんと2コア2GBメモリで一ヶ月あたり$3.67です。

>プリエンプティブル VM の実行
https://cloud.google.com/kubernetes-engine/docs/how-to/preemptible-vms?hl=ja
>プリエンプティブル VM は、最長持続時間が 24 時間で、可用性が保証されない Compute Engine VM インスタンスです。

今回は1Nodeの想定のため、必ず1日に最低一回ダウンタイムが発生しますが、個人利用なので許容します。


![スクリーンショット 2020-04-27 19.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/d98e446f-5fa9-870a-c5c7-3b3d6b6c2a5f.png)

自分はStackdriverもいらないです。
![スクリーンショット 2020-04-27 19.56.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/f2208d23-0a17-def5-ca0b-c3a22df54bef.png)

一番重要です。ネットワークロードバランサはお高いので、必ず無効にします。
![スクリーンショット 2020-04-27 19.56.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/bc591216-49e3-6b3a-27ef-056eb0858905.png)

# GKE作成後の設定
GKEのkubeconfigの設定方法は割愛します。
https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja#get_authentication_credentials_for_the_cluster

公式ドキュメントにGKEのアドオンを削減方法があるので、それにしたがってリソースを削減していきます。

>小規模クラスタでアドオン リソース使用を削減する
https://cloud.google.com/kubernetes-engine/docs/how-to/small-cluster-tuning?hl=ja

以下自分が行ったものです。

```bash:dashboard無効
gcloud container clusters update cluster-name \
        --update-addons=KubernetesDashboard=DISABLED
``` 

```bash:kube-dns-autoscalerの無効とkube-dnsの削減
kubectl scale --replicas=0 deployment/kube-dns-autoscaler --namespace=kube-system
kubectl scale --replicas=1 deployment/kube-dns --namespace=kube-system    
```

この段階でのクラスターの状態はこちらです。
Dashboardを無効にしてもmetric-serverは消えないようなので、要らない人は消してください(GKEのアドオンは消えないものもあるので、消えなければScale 0に)

```bash
$ kubectl get all -A                                                          
NAMESPACE     NAME                                                      READY   STATUS    RESTARTS   AGE
kube-system   pod/kube-dns-5f7d7d8796-rc96q                             3/3     Running   0          46m
kube-system   pod/kube-proxy-gke-cluster-1-default-pool-3e1d5b15-kb4r   1/1     Running   0          46m
kube-system   pod/metrics-server-v0.3.3-7599dd85cd-nx7vq                2/2     Running   0          46m


NAMESPACE     NAME                     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
default       service/kubernetes       ClusterIP   10.8.0.1     <none>        443/TCP         47m
kube-system   service/kube-dns         ClusterIP   10.8.0.10    <none>        53/UDP,53/TCP   46m
kube-system   service/metrics-server   ClusterIP   10.8.8.93    <none>        443/TCP         46m

NAMESPACE     NAME                                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                                              AGE
kube-system   daemonset.apps/metadata-proxy-v0.1        0         0         0       0            0           beta.kubernetes.io/metadata-proxy-ready=true,beta.kubernetes.io/os=linux   46m
kube-system   daemonset.apps/nvidia-gpu-device-plugin   0         0         0       0            0           <none>                                                                     46m

NAMESPACE     NAME                                    READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/kube-dns                1/1     1            1           46m
kube-system   deployment.apps/kube-dns-autoscaler     0/0     0            0           46m
kube-system   deployment.apps/metrics-server-v0.3.3   1/1     1            1           46m

NAMESPACE     NAME                                               DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/kube-dns-5f7d7d8796                1         1         1       46m
kube-system   replicaset.apps/kube-dns-autoscaler-6b7f784798     0         0         0       46m
kube-system   replicaset.apps/metrics-server-v0.3.3-7599dd85cd   1         1         1       46m

$ kubectl get nodes
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-3e1d5b15-kb4r   Ready    <none>   50m   v1.15.11-gke.9
```

これでクラスターの作成は完了です。
以降はこの環境を少し使いやすくしていきたいと思います。

# Preemptive Instanceへの対応
あとでIngress Controllerをセットアップしますが、ネットワークロードバランサーは作成しないため、基本的にIngress ControllerはNodePortで公開します。

NodeにはExternal IPでアクセスすることになりますが、Preemptive InstanceのためNodeが削除される度に、External IPが毎回変わってしまいます。

参考にさせていただいた記事では、CloudFlareのDNSとExternal IPを同期する以下のカスタムコントローラーが紹介されていました。
https://github.com/calebdoxsey/kubernetes-cloudflare-sync

自分はCloudFlareは使っていませんでしたが、過去にRoute53で取得したドメインとホストゾーンがすでにあったので、Route53に同期したいと思いました。

公式のAWS Service Operatorというものもありますが、まだ発展途上でRoute53には対応していません。

>AWS Service Operator for Kubernetes Now Available
https://aws.amazon.com/jp/blogs/opensource/aws-service-operator-kubernetes-available/

Route53にはヘルスチェックなどの機能もあるので、カスタムリソースで作成できると便利かもしれませんが、
今回はリソースも限られているので、kubernetes-cloudflare-syncのようなライトなコントローラーがいいよねということで、

新たに上記のリポジトリをForkして、Route53にNodeIPを同期するカスタムコントローラーを作成しました。
https://github.com/jlandowner/kubernetes-route53-sync

これをデプロイすることで、Preemptive InstanceでNodeが削除されても、しばらくすれば新しいNodeにアクセスできるようになりました。

EKSや他のk8s環境でも利用することができます。
EKS＋Spot Instanceでは効果が期待できると思いますが、EKS自体安くないので、EKS使うなら普通にELBを立てますね。。

# 外部アクセス(Ingress)の設定
外部アクセス用のCert-managerとIngress Controllerを次回セットアップします。

Kubernetes cert-managerでRoute53で作成したドメインの証明書を作成し、Ingressで利用する。
https://qiita.com/jlandowner/items/9f3c4c0a03d2ae3d2189