この記事は Kubernetes道場 Advent Calendar 2018 21日目の記事です。

今回はCordon / Drain / PodDisruptionBudgetについて。

cordonとuncordon

Cordonは指定したNodeにスケジュールさせないようにするための処理だ。 kubectl cordon コマンドで実行することができる。

また、Cordonの状態を解除するための処理が kubectl uncordon コマンドだ。

早速使ってみよう。

cordonを使ってみる

まずNodeを確認しよう。

1
2
3
4
$ kubectl get node
kubectl get node
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    <none>   24h   v1.13.1

さて、この表示された minikube をCordonしてみよう。

1
2
$ kubectl cordon minikube
node/minikube cordoned

Cordonされたようだ。 kubectl describe でNodeを確認してみよう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ kubectl describe node/minikube
Name:               minikube
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/hostname=minikube
Annotations:        node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Mon, 24 Dec 2018 03:22:13 +0900
Taints:             node.kubernetes.io/unschedulable:NoSchedule
Unschedulable:      true
~~~

(下の部分は省略している)

NoSchedule のTaintが追加されていることがわかる。 NoSchedule のTaintということは、既にスケジュールされているPodは実行したままだが、新たにスケジュールされるPodはこのNodeは対象にならない。

ついでに kubectl uncordon も実行してみよう。

1
2
$ kubectl uncordon minikube
node/minikube uncordoned

Describeで確認してみる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ kubectl describe node/minikube
Name:               minikube
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/hostname=minikube
Annotations:        node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Mon, 24 Dec 2018 03:22:13 +0900
Taints:             <none>
Unschedulable:      false

先程追加されていたTaintが削除されている。要はスケジュールできるようになった。

drain

drainはNodeを停止させる前準備として動作しているPodを別Nodeへ退去させるコマンドだ。

早速使ってみよう。

drainを使ってみる

まず適当なDeploymentを作成しておこう。以下のManifestを作成し、適用する。

1
2
$ kubectl create deploy nginx --image nginx:alpine
deployment.apps/nginx created

さて、drainさせてみよう。 kubectl drain で行う。

1
2
3
4
$ kubectl drain minikube
node/minikube cordoned
pod/nginx-54458cd494-dhf5h evicted
node/minikube evicted

ログを見るとまずcordonが実行されたことがわかる。次にDeploymentによって作成されていたPodが追い出されたことがわかる。

それでは追い出されたPodがどうなってるか確認しよう。

1
2
3
$ kubectl get po
NAME                     READY   STATUS    RESTARTS   AGE
nginx-54458cd494-9d76w   0/1     Pending   0          99s

Pendingのままだ。Descirbeで確認しよう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ kubectl describe po
Name:               nginx-54458cd494-9d76w
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               <none>
Labels:             app=nginx
                    pod-template-hash=54458cd494
Annotations:        <none>
Status:             Pending
IP:
Controlled By:      ReplicaSet/nginx-54458cd494
Containers:
  nginx:
    Image:        nginx:alpine
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-fqjxc (ro)
Conditions:
  Type           Status
  PodScheduled   False
Volumes:
  default-token-fqjxc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-fqjxc
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason            Age                    From               Message
  ----     ------            ----                   ----               -------
  Warning  FailedScheduling  2m53s (x3 over 2m55s)  default-scheduler  0/1 nodes are available: 1 node(s) were unschedulable.

スケジュールに失敗していることがわかる。これはローカル環境のMinikubeではNodeが1つしかないためだ。

Nodeの方もどうなったか確認してみよう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ kubectl describe node
Name:               minikube
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/hostname=minikube
Annotations:        node.alpha.kubernetes.io/ttl: 0
                    volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp:  Mon, 24 Dec 2018 03:22:13 +0900
Taints:             node.kubernetes.io/unschedulable:NoSchedule
Unschedulable:      true
~~~

cordonの実行で確認したとおり、 NoSchedule がTaintに追加されていることがわかる。

このようにdrainはNodeを停止させる前に動作しているPodを追い出して、Nodeを安全に停止させる準備をしてくれる。

drainの注意点

drainはNodeを停止させる前準備として便利なコマンドだが、注意することがある。

以下のようなクラスタを考えよう。

Nodeが2つあり、片方のNodeにPodがスケジュールされ、実行されている。

ここで、PodがスケジュールされているNode-oldをdrainしよう。

すると以下のような状態になる。

drainしたためPodが削除され、別のNode-newでPod-1がスケジュールされた。

しかし、このタイミングでPodが1つReadyの状態のものがない。このように、drainを実行する際にReadyのPod数が少なくなったり、0になってしまうケースがある。

これを回避するために PodDisruptionBudget というオブジェクトがある。

PodDisruptionBudget

PodDisruptionBudget はPodの最小の有効状態や最大の無効状態の数を指定する。

PodDisruptionBudget のPodの管理対象はLabelSelectorで指定する。

PodDisruptionBudget のフィールドを解説しよう。

  • spec.maxUnavailable : Eviction実行時にPodを無効状態にしていい最大数を指定する。絶対値か百分率で指定する。
  • spec.minAvailable : Eviction実行時にPodを有効状態にしておく最小数を指定する。絶対値か百分率で指定する。
  • spec.selector : このBudgetを適用する対象のPodを選択するLabelSelectorを指定

以下が PodDisruptionBudget の指定例だ。

1
2
3
4
5
6
7
8
9
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: nginx-pdb
spec:
  minAvailable: "100%"
  selector:
    matchLabels:
      app: nginx

このリソースを作成することで、drainを実行した際のEvictionの処理でのPodの停止数を制御することができる。


というわけで今回はここまで。

次回はIngressについて見ていこう。

それでは。