Kubernetes の運用をしていると避けて通れないのは、サーバー/Kubernetes コンポーネントのアップデート、アップグレードの作業です。それを実行する際には、Node 再起動が必要となります。ここまで Pod が動いている Node を指定する仕組みなどを触れてきましたが、再起動する際にアプリケーションへの影響を最小限にする仕組みを見ていきたいと思います。
環境準備
過去の記事にしたがって、AKS の検証環境を準備します。
Azure Kubernetes Services 環境を構築する
その上で今回は以下のマニフェストファイルで、3つの Node を持つクラスターに対して Nignx の Deployment を作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
作成が完了したら、Pod と Node の関係性を以下オプションを付けたコマンドで確認します。
$ kubectl get pod -o custom-columns=Pod:metadata.name,Node:spec.nodeName
Pod Node
nginx-5c7588df-77kvs aks-nodepool1-38358128-vmss000001
nginx-5c7588df-rpdbl aks-nodepool1-38358128-vmss000000
nginx-5c7588df-z64g6 aks-nodepool1-38358128-vmss000002
作成したそれぞれの Pod が 3つの Node に分散されて配置していることが分かります。ここまでで準備は完了です。
Cordon/Uncordon
Cordon は「閉鎖する」という意味です。Cordon を実行することで、特定の Node をスケジュールの対象から除外することが可能です。Uncordon はその逆で、Node をスケジュール対象に戻すコマンドです。実際に上記で確認した aks-nodepool1-38358128-vmss000001
という名前の Node に対して Cordon を実行してみます。
$ kubectl cordon aks-nodepool1-38358128-vmss000001
node/aks-nodepool1-38358128-vmss000001 cordoned
これで特定の Node が Cordon の対象になりました。kubectl get node
コマンドで詳細を確認してみます。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
aks-nodepool1-38358128-vmss000000 Ready agent 11m v1.13.12
aks-nodepool1-38358128-vmss000001 Ready,SchedulingDisabled agent 10m v1.13.12
aks-nodepool1-38358128-vmss000002 Ready agent 11m v1.13.12
指定した Node が SchedulingDisabled
となっているのが分かります。これはスケジューリングから除外されたことを意味していて、Pod のスケールアップ等から除外されていることを表します。試しにレプリカ数を増やしてみます。
$ kubectl scale deployment nginx --replicas=6
deployment.extensions/nginx scaled
先ほどの Pod と Node の関係性を表示するコマンドで確認してみます。
$ kubectl get pod -o custom-columns=Pod:metadata.name,Node:spec.nodeName
Pod Node
nginx-5c7588df-77kvs aks-nodepool1-38358128-vmss000001
nginx-5c7588df-9nwdd aks-nodepool1-38358128-vmss000000
nginx-5c7588df-jbwjg aks-nodepool1-38358128-vmss000002
nginx-5c7588df-jkwck aks-nodepool1-38358128-vmss000000
nginx-5c7588df-rpdbl aks-nodepool1-38358128-vmss000000
nginx-5c7588df-z64g6 aks-nodepool1-38358128-vmss000002
Cordon した Node には変更が加わっていないことが分かります。これが Cordon の効果です。Cordon されている Node は Uncordon コマンドでスケジュール対象に戻すことが可能です。
$ kubectl uncordon aks-nodepool1-38358128-vmss000001
node/aks-nodepool1-38358128-vmss000001 uncordoned
$ kubectl get node
NAME STATUS ROLES AGE VERSION
aks-nodepool1-38358128-vmss000000 Ready agent 15m v1.13.12
aks-nodepool1-38358128-vmss000001 Ready agent 15m v1.13.12
aks-nodepool1-38358128-vmss000002 Ready agent 15m v1.13.12
Drain
Drain では、先ほどの Cordon の動きに加えて、Pod の削除と再作成を行います。Cordon の様に CLI で実行できます。
$ kubectl drain aks-nodepool1-38358128-vmss000001
node/aks-nodepool1-38358128-vmss000001 cordoned
error: unable to drain node "aks-nodepool1-38358128-vmss000001", aborting command...
There are pending nodes to be drained:
aks-nodepool1-38358128-vmss000001
error: cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): kube-system/kube-proxy-d5pqv
この際エラーメッセージが出ています。デーモンセットがあるため、オプションを指定して実行してくださいと言わているため、その通りに実行してみます。
$ kubectl drain aks-nodepool1-38358128-vmss000001 --ignore-daemonsets
node/aks-nodepool1-38358128-vmss000001 already cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/kube-proxy-d5pqv
evicting pod "nginx-5c7588df-77kvs"
pod/nginx-5c7588df-77kvs evicted
node/aks-nodepool1-38358128-vmss000001 evicted
この Drain では、aks-nodepool1-38358128-vmss000001
に配置されている Pod を削除し、他の Node に再作成を行っています。先ほどの Pod と Node の関係性を確認するコマンドを実行して確認してます。
$ kubectl get pod -o custom-columns=Pod:metadata.name,Node:spec.nodeName
Pod Node
nginx-5c7588df-9nwdd aks-nodepool1-38358128-vmss000000
nginx-5c7588df-jbwjg aks-nodepool1-38358128-vmss000002
nginx-5c7588df-jkwck aks-nodepool1-38358128-vmss000000
nginx-5c7588df-nhzfv aks-nodepool1-38358128-vmss000002
nginx-5c7588df-rpdbl aks-nodepool1-38358128-vmss000000
nginx-5c7588df-z64g6 aks-nodepool1-38358128-vmss000002
Drain で指定した aks-nodepool1-38358128-vmss000001
には Pod が配置されていないことが確認できました。Node の状態も確認してみると、Cordon したときと同じように ScheduleDisable の状態になっていることが分かります。何も配置されていない Node なので正常にアップデートできる準備が整った、という事になります。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
aks-nodepool1-38358128-vmss000000 Ready agent 22m v1.13.12
aks-nodepool1-38358128-vmss000001 Ready,SchedulingDisabled agent 22m v1.13.12
aks-nodepool1-38358128-vmss000002 Ready agent 22m v1.13.12
ここまでできればあとは Node をアップデートしたり、再起動することが出来ます。Azure CLI でできるので非常に簡単ですね!
参考
Cluster Management
https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/
Safely Drain a Node while Respecting the PodDisruptionBudget
https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/