Introduction to Kubernetes

`@Opt Technologies 社内勉強会 2017/01/20`
こちらは、社内勉強会で使った資料となります。

---
## はじめに
### 話すこと
- Kubernetes(以降k8s)とは何か
- k8sの機能の一部
- 簡単なScalaアプリケーションによる例

---
### 話さないこと
- 監視
- ロギング
- 永続化 (Volume)
- 認証
- クラスタの構築方法

---
## コンテナデプロイの利点
- Blue-Green(Red-Black)デプロイによる運用コスト減
  - <=> In-Place (Capistranoなど)
  - コンテナである必要はない。(packerでマシンイメージ作るなどでもいい)
- 起動が速い
  - 素早くスケールできる
  - 仮想マシンには無い利点
- 開発環境と本番環境のギャップを減らせる

---
## コンテナデプロイで考えなければならないこと
- コンテナ同士の通信
  - 例: MicroServices
- Load Balancing
  - オートスケーリング
- マルチホストでのコンテナの割り当て
- 自動リカバリ
- などなど

---
## k8sとは
- 前述のような課題を解決する、コンテナオーケストレーションツールの一つ
  - 他: Docker Swarm, Amazon ECS etc
- Google内部で使われていたBorgが元になっている
- マネージドサービスもある
  - Google Container Engine (GKE)
- 読み方は、k8s meetupでは「クバネテス」が多数派だった印象

---
## この資料の環境
- minikube : v0.14.0
  - kubernetes : v1.5.1

---
## k8sのアーキテクチャ

図などはこちらを参照。[Kubernetes architecture](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/architecture.md)

### Master

- k8sはmaster - slave(node)モデル。
- クラスタの管理を行う、複数のコンポーネントの組をmaster(またはcontrol plane)と呼ぶ。
- すべてを1マシンに配置する必要はない。（特にetcdは分けたほうがよさそう）
- k8sはmasterが死んでもpodは動き続けるので、HA構成にしなくてもある程度運用できそう。(もちろんapi-serverが死んでるのでpodの追加/削除などはできない。あとDNSとかはどうなるんだろう？)

---
以下がmasterを構成するコンポーネント

- kube-apiserver
  - k8sの設定情報のCRUDを行うREST server
- etcd
  - Raftという合意アルゴリズムに基づくGo製の分散KVS
  - k8sクラスタの設定情報はすべてここに保存される
- kube-controller-manager
  - k8sでは、controllerと呼ばれるループがいくつか回っていて、そのループの中で現在のクラスタのstateと設定されたstateを比較して更新していく。
  - そのコントロールループを束ねたデーモン
      - Replication Controller
      - Node Controller
      - Deployment Controller
      - などなど
- kube-scheduler
  - 新たに追加されたpodを検出し、nodeにスケジューリングする。
- addons
  - クラスタ内DNSなど、一部の期間機能はそれ自体がpod/serviceとして動いていて、これらをaddonsと呼ぶ。
  - `kube-system`というnamespaceが割り当てられる。 (`$ kubectl get svc --namespace=kube-system`で見える)

---
#### 参考
- [Kubernetes Components](https://kubernetes.io/docs/admin/cluster-components/)
- [CoreOS User Forum](https://groups.google.com/d/msg/coreos-user/-g3o3ZAOwQ4/Lm25-6gdYdEJ)
- [Master-Node communication](https://kubernetes.io/docs/admin/master-node-communication/)
- [Can Pod/Service still work if kube-master or etcd service down?](http://stackoverflow.com/questions/33951663/can-pod-service-still-work-if-kube-master-or-etcd-service-down)
- [Kubernetesを拡張しよう](https://www.ianlewis.org/jp/extending-kubernetes-ja)

---
### Node

- コンテナが走るマシンのことを、nodeと呼ぶ。（従来はminionと呼ばれていた）
- nodeの追加/削除はk8sの責務の外。（落ちているnodeにpodをスケジューリングしない、などはしてくれる）

k8sクラスタのメンバとして動作するために、すべてのnodeで以下のデーモンが動いている。

- kubelet
  - apiserverを通じて、自ノードに割り当てられたpodを確認し、起動する
- kube-proxy
  - 設定されたserviceに応じて、TCP/UDP通信を適切なpodにforwardするproxy

---
#### 参考

- [kubelet](https://kubernetes.io/docs/admin/kubelet/)
- [kube-proxy](https://kubernetes.io/docs/admin/kube-proxy/)

---
## Resources(一部)

k8sで提供されているresourceの一部を解説。

カスタムresourceを定義することもできる。(https://kubernetes.io/docs/user-guide/thirdpartyresources/)

---
### Pod

複数のコンテナの集合で、デプロイの最小単位。

- 複数のコンテナをまとめたいケース:
  - fluentdなどのログコレクターを一緒に走らせる
  - Redisのキャッシュレイヤーを挟む

---
### Replication Controller

- 指定した数のpodが立ち上がっていることを保証する。
  - 多すぎたら殺す、少なかったら立ち上げる、落ちたら再起動する

---
### Deployment

- Replication Controllerの機能に加え、以下の機能を提供する
  - podのローリングアップデート
  - ロールバック

---
### Service

- podは、replication controllerによる追加/削除や再起動が行われるため、基本的にipは固定でない。
- なので、podに別のpodからリクエストを送ったり(micro serviceなど)、クラスタ外部からpodにアクセスする際にはserviceを作る。
- クラスタ内部からは、DNSでserviceを参照できるようになる。

Serviceは、用途別に4種類ある。

---
#### ClusterIP

- クラスタ内部からしかアクセスしないpodに対しては、このtypeのserviceを作成する。
- どのpodにリクエストを振り分けるかどうか、はlabelで設定する。

---
#### NodePort

- クラスタ外部からアクセスする際に、このtypeで作成する。
- 作成時に、nodePortとよばれるポートが自動的に割り当てられ、**すべてのnodeに対して、**`nodeのip:nodePort`で該当podにアクセスできるようになる。(ClusterIPと同じく、podの行き先はlabelで設定)
- nodePortは明示的に指定できるが、重複をさけるためk8sに任せた方がよい。
- 外部LBを使って、詳細なhealthチェックの設定やSSL-terminationを行う場合、「NodePortでserviceを作成後、kubectlでnodePortを取得、別途(GCPならdeployment-managerなど)でLBを設定」するのがよさそう？

---
#### LoadBalancer

- NodePortと同じくクラスタ外部にpodを公開する際に使うが、外部LBも自動的に作成される。(GKEならCloud LB)
  - healthチェックのエンドポイントや間隔など、細かい制御が可能なのか？(未調査)
  - 作成されるLBはL4。L7LBを使いたい場合は上述の通りNodePort + L7LBを別途立てるか、[Ingress Resources](http://kubernetes.io/docs/user-guide/ingress/)を使う。

---
#### ExternalName

- 他のとは違い、podから外部サービスを参照したい際に使う
  - 実運用では、RDBはマネージドサービスを使いたかったりすると思うので、そういう場合にExternalNameを立てる。
  - ローカルと本番で向き先を変える、みたいのがExternalName Serviceの切り替えだけでできる。

---
### 参考
- [Pods](https://kubernetes.io/docs/user-guide/pods/)
- [Replication Controller](https://kubernetes.io/docs/user-guide/replication-controller/)
- [Deployments](https://kubernetes.io/docs/user-guide/deployments/)
- [Services](https://kubernetes.io/docs/user-guide/services/)

---
## Example
- Akka-Http application
  - backend DB (external MySQL)

### 0. Clone repository

```bash
$ git clone https://github.com/ocadaruma/introduction-to-kubernetes
```

### 1. Build image

```bash
$ eval $(minikube docker-env) # minikube上でローカルのdockerイメージを使うため
$ cd app
$ sbt docker
$ docker images
REPOSITORY                                            TAG                 IMAGE ID            CREATED             SIZE
example/example                                       latest              ac5970138dba        About an hour ago   144.4 MB
example/example                                       v1.0-SNAPSHOT       4a6bdb4a8719        8 hours ago         144.4 MB
```

### 2. Create services

```bash
$ cd ../k8s
$ kubectl create -f services.yaml
service "mysql-service" created
service "example-app" created
$ kubectl get svc
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
example-app     10.0.0.24    <nodes>       3000/TCP   40s
kubernetes      10.0.0.1     <none>        443/TCP    54d
mysql-service                10.0.2.2      3306/TCP   40s
$ kubectl get svc example-app -o 'jsonpath={.spec.ports[0].nodePort}'
32425
```

32425番でNodePortが作成されました。

### 3. Deploy application

```bash
$ kubectl apply -f deployment.yaml
deployment "example-app-deployment" created
$ kubectl get po
NAME                                      READY     STATUS    RESTARTS   AGE
example-app-deployment-2393591303-86kcz   1/1       Running   0          18s
example-app-deployment-2393591303-8nn4g   1/1       Running   0          18s
example-app-deployment-2393591303-ldbx1   1/1       Running   0          18s
```

![Screen Shot 2017-01-20 at 6.51.18 PM.png](https://qiita-image-store.s3.amazonaws.com/0/38151/c48cc659-0fd9-c385-d2f2-18e7cfc1abbd.png)

---
## リポジトリ
- https://github.com/ocadaruma/introduction-to-kubernetes

## Further Reading
- [User Guide](https://kubernetes.io/docs/user-guide/)
- [Building High-Availability Clusters](https://kubernetes.io/docs/admin/high-availability/)
- [Zero Downtime Deployments in Kuberentes](https://www.chrismoos.com/2016/09/28/zero-downtime-deployments-kubernetes/)