【何となく理解したい】Kubernetesってなに?
覚えたい理由の背景
Certified Kubernetes Administrator (CKA) の資格を取得するため、実務的な部分だけでなくKubernetes全体像を何となく理解したいから。
どうやって学ぶ?
以下のUdemyコースを受講し、要点をスクラップにまとめていく。
抑えておくべき最低限の専門用語
- Master
- kube-apiserver
- etcd (KVS; Meta data for k8s cluster)
- kube-scheduler
- Controller-Manager
- Node-Controller
- Replication-Controller
- Workder Nodes
- kubelet
- kube-proxy
- pod ( Can have multiple containers )
Master
kube-apiserver
k8sの司令塔の役割。HTTPプロトコルで例えばPODを作成すると以下のフローのようにapiserver経由でやり取りされる。
- Authenticate User
- Validate Request
- Retrieve data
- Update ETCD
- Scheduler
- Kubelet
etcd
Key-Value Store形式のデータベース。Nodeの情報やk8sリソースがここに保管され、管理される。
Controller-Manager
Node-Controller
kube-apiserver経由で、
- 5秒間隔でNodeを死活監視 (Node Monitor Period = 5s)
- 40秒間繋がらない場合Unreachableにステータスを変更する(Node Monitor Grace Period = 40s)
- 5分間UnreachableならPODを作り直す (POD Eviction Timeout = 5m)
のようにNode監視がメイン。
Kube-Controller-Manager
Controllerはk8sのリソース毎に種類があり、それらを統括しているのが「kube-controller-manager」で、Controllerを立ち上げる時、デフォルトで全てのControllerがONとなる。
kube-scheduler
どのPODがどのNODEに行くのかを決めるだけ。どこに割り当てるかは「CPU/Memory」などの条件でざっくり、
- Filter Nodes (割当可能な場所を見つける)
- Rank Nodes (リソースに余裕がある場所ほどRankが高い)
の2つを行う。他にも条件付けが可能で詳細は後述。
Workder Nodes
kubelet
Nodeの司令塔。Worker Nodeには手動でインストールする必要あり。
kube-proxy
複数のPod間で特定のサービスにアクセスするためのプロキシとして動く。各Node上でどのサービスがどのIPなのかを記録してルーティングを行う。
PODs with YAML
PODをYamlファイル形式で作る時
- pod.yaml
apiVersion: v1
kind: Pod
# metadataは基本は自由形式
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
# ContainersはList/Array
spec:
containers:
- name: nginx-container
image: nginx
- kubectl apply -f pod.yaml
Replication Controller
-
冗長性の確保。例え1つのPODでもReplication Controllerは作動していて、確実に動くように担保してくれる。
-
LoadBalancerの時にも活用
Replica Controller with Yaml
Yamlの定義は以下のような感じ。
apiVersion: v1
kind: ReplicationController
metadata:
name: myapp-rc
labels:
app: myapp
type: front-end
spec:
replicas: 3
# (POD with yaml)
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx
- 作成されたリソース確認
$ kubectl get rc myapp-rc
NAME DESIRED CURRENT READY AGE
myapp-rc 3 3 3 63s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-rc-dgwfl 1/1 Running 0 96s
myapp-rc-l4qsr 1/1 Running 0 96s
myapp-rc-mr5rq 1/1 Running 0 96s
StatefulSet
Deploymentと対になるもの。Podとストレージの結びつきがDeploymentと異なる。以下のイメージが非常に分かりやすいです。
引用元: https://qiita.com/sugimount/items/b163b08fe9a3b1b102d9
ReplicaSet
Replication Controllerの次のバージョン。Deploymentが親で大体管理されてる。
Deployment
アプリを効率良く展開させたい時に便利なもの。これを作るとReplicaSetもおまけで作成される。
ユースケースは以下の通り。[1]
- Create a Deployment to rollout a ReplicaSet
- Declare the new state of the Pods
- Rollback to an earlier Deployment revision
- Scale up the Deployment to facilitate more load.
- Pause the Deployment to apply multiple fixes
- Clean up older ReplicaSets that you don't need anymore
Yaml例は以下。KindをReplicaSetに変えても動く。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
k8s 試験でお役立ちコマンド
- お手軽POD作成:
kubectl run nginx --image=nginx
- マニフェスト作成 (--replicas=x のようにオプション指定も可能)
kubectl create deploy nginx --image=nginx --dry-run=client -o yaml
kubectl run nginx --image=nginx --dry-run=client -o yaml
- POD + Serviceを同時に作成
kubectl run httpd --image=httpd:alpine --port 80 --expose
- 特定のnamespace配下リソースを全てリストアップ
$ kubectl get all -l app=myapp,type=front-end
NAME READY STATUS RESTARTS AGE
pod/myapp-rc-dgwfl 1/1 Running 0 3h13m
pod/myapp-rc-l4qsr 1/1 Running 0 3h13m
pod/myapp-rc-mr5rq 1/1 Running 0 3h13m
NAME DESIRED CURRENT READY AGE
replicationcontroller/myapp-rc 3 3 3 3h13m
Namespace
Podを棲み分ける時に使う。Namespace配下でResourceQuotaを使うとある程度の制限が可能となる。
- Compute Resource Quota (limits/requests of CPU, Memory)
- Storage Resource Quota (Persistent Volume Claims)
- Object Count Quota (count/pvc, services, secrets, configmaps, deploy, rc, rs, etc)
- Quota Scopes (Filter Pods where you gonna apply quota for)
Services
Services Types
- NodePort
- ClusterIP
- LoadBalancer
NodePort
特定PodをPort指定して外からアクセスできるようにする。k8s外から繋ぎたい時に便利。
- TargetPort, Port, NodePort の違いは以下の図が分かりやすい
https://www.bogotobogo.com/DevOps/Docker/Docker_Kubernetes_Pods_Services_Yaml.php より引用
$ kubectl create service nodeport myapp-service --tcp=80:30008 -o yaml --dry-run=client
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: myapp-service
name: myapp-service
spec:
ports:
- name: 80-30008
port: 80
protocol: TCP
targetPort: 30008
selector:
app: myapp-service
type: NodePort
status:
loadBalancer: {}
ClusterIP
Cluster内でback-endにどのPodを割り当てるか、等で他Podが簡単にアクセスできるようにする。
LoadBalancer
LBを使うと複数Node間で負荷分散が可能となる。
Scheduling
Manual Scheduling
Podを作成する時にspec.nodeName
が割当されない場合、Schedulerが自動で決めてくれる。仮にSchedulerが機能しない場合、Podは「Pending」のステートになる。
この部分を手動で割当することも可能。その他の方法としてBindingが使える。
- pod-bind-definition.yml
apiVersion: v1
kind: Binding
metadata:
name: nginx
target:
apiVersion: v1
kind: Node
name: node02
上記Yamlファイルをjson形式に変換してAPIを投げる。(e.g., curl -X POST -h "Content-Type:application/json" --data '...' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/
Labels & Selectors & Annotations
metadataに基本書き込む。Labelsはk8s用でAnnotationsは人間用に使い分けましょう。[1]
Taints & Tolerations
- Taint: 特定の条件を設定して、Podが展開されないようにする
- Toleration: 特定PodにTaintへTolerantな状態を指定する
- Taintは必ずしもそこにPodが割当られることを保証しない。希望する割当はNode Affinityを使う
- Taintの挙動として以下の3つがある。
- NoSchedule: 新規PodでTolerantでないものはScheduleしない
- PreferNoSchedule: なるべくScheduleしない
- NoExecute: TolerantでないPodをEvictする
Node Selectors
NodeにラベルをつけてPod作成時にSelectさせる。複雑な条件にはNode Affinityを使う。
kubectl label node <node-name> <label-key>=<label-value>
kubectl label node node-01 size=Large
- pod-definitionyml
apiVersion:
kind: Pod
metadata:
name: myapp-pod
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
size: Large
Node Affinity
特定NodeにPodを新しく展開するために「条件が必ず必要、好ましい」の2タイプがある。将来的には実行中のPodをEvictできるようになる。
Pod に tolerations付き(Podの展開を拒否するやつ)でaffinityで展開する例
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
strategy:
type: Recreate
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- app
tolerations:
- key: "nginx"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- image: nginx:latest
name: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/
DaemonSets
各Node上で、1つ以上のPodを確実に動かしたい場合に使う。(e.g., kube-proxy)
Yaml定義はReplicaSetとほぼ同一
Static PODs
KubeletのみでPodを動かすことも可能。その場合、パスを指定して動かす。Master NodeにJoinした場合、kube-api上ではReadOnlyの権限しかもらえず、Podを直接変更することはできない。
Daemonsetとの違いは「kubelet, kube-api」のどちらかが作成するのか等がある。
Static Podの特徴として、名前の末尾にNode名が付与される。
- Manifest Pathを調べる時に便利なコマンド:
ps -ef|grep kubelet
- config指定されてたら
staticPodPath
を調べる
- config指定されてたら
Multiple Schedulers
複数のSchedulerを設定する条件
- Yamlに以下のフラグを立てる
--leader-elect=true
--lock-object-namespace=<lock-object-namespace>
--lock-object-name=<lock-object-name>
- 細かい設定とかはDocumentを見ながら確認
- https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/
-
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/
- --scheduler-name
- --secure-port
Application Lifecycle Management
Rolling Updates and Rollbacks
- Rollout Status
kubectl rollout status deployment/<your-deploy>
- Rollback
kubectl rollout undo/deployment/<your-deploy>
Deployment Strategy
- Recreate
- 古いものを一気にダウンさせて新しいものを展開させるけど、アプリケーションがダウンする可能性あり
- Rolling Update
- 各pod一つずつをアップデートさせていく
Docker Command and Pod Definition
Maintenance
Upgrade
Restore & Backup
DisasterRecoveryにおいて基本的には以下の3つを考える
- Resource Configuration
- ETCD Cluster
- Persistent Volumes
- Resource Configuration:
kubectl get all -o yaml -A > all-deploy-services.yaml
- Open Sourceで「Velero」を使うのもあり
Velero is an open source tool to safely backup and restore, perform disaster recovery, and migrate Kubernetes cluster resources and persistent volumes.