@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
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
- CoreOS User Forum
- Master-Node communication
- Can Pod/Service still work if kube-master or etcd service down?
- Kubernetesを拡張しよう
Node
- コンテナが走るマシンのことを、nodeと呼ぶ。(従来はminionと呼ばれていた)
- nodeの追加/削除はk8sの責務の外。(落ちているnodeにpodをスケジューリングしない、などはしてくれる)
k8sクラスタのメンバとして動作するために、すべてのnodeで以下のデーモンが動いている。
- kubelet
- apiserverを通じて、自ノードに割り当てられたpodを確認し、起動する
- kube-proxy
- 設定されたserviceに応じて、TCP/UDP通信を適切なpodにforwardする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を使う。
ExternalName
- 他のとは違い、podから外部サービスを参照したい際に使う
- 実運用では、RDBはマネージドサービスを使いたかったりすると思うので、そういう場合にExternalNameを立てる。
- ローカルと本番で向き先を変える、みたいのがExternalName Serviceの切り替えだけでできる。
参考
Example
- Akka-Http application
- backend DB (external MySQL)
0. Clone repository
$ git clone https://github.com/ocadaruma/introduction-to-kubernetes
1. Build image
$ 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
$ 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
$ 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
