Open11

【何となく理解したい】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経由でやり取りされる。

  1. Authenticate User
  2. Validate Request
  3. Retrieve data
  4. Update ETCD
  5. Scheduler
  6. 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」などの条件でざっくり、

  1. Filter Nodes (割当可能な場所を見つける)
  2. 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

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
脚注
  1. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#use-case ↩︎

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

  • $ 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な状態を指定する

https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
  • Taintは必ずしもそこにPodが割当られることを保証しない。希望する割当はNode Affinityを使う
  • Taintの挙動として以下の3つがある。
    • NoSchedule: 新規PodでTolerantでないものはScheduleしない
    • PreferNoSchedule: なるべくScheduleしない
    • NoExecute: TolerantでないPodをEvictする
脚注
  1. https://blog.getambassador.io/kubernetes-labels-vs-annotations-95fc47196b6d ↩︎

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できるようになる。

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を調べる

Multiple Schedulers

複数のSchedulerを設定する条件

  • Yamlに以下のフラグを立てる
--leader-elect=true
--lock-object-namespace=<lock-object-namespace>
--lock-object-name=<lock-object-name>

https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/#enable-leader-election

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.

ログインするとコメントできます