やってみただけのメモ的な記事であり、以下の Qiita の記事のほうが分かりやすいかと思います。
Kubernetes: 複数の Node を安全に停止する (kubectl drain + PodDisruptionBudget)
環境
$kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.8-eks-7c34c0", GitCommit:"7c34c0d2f2d0f11f397d55a46945193a0e22d8f3", GitTreeState:"clean", BuildDate:"2019-03-01T22:49:39Z", GoVersion:"go1.10.8", Compiler:"gc", Platform:"linux/amd64"}
# Node は3つ
$kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-31-22-177.ap-northeast-1.compute.internal Ready <none> 65d v1.11.5
ip-172-31-28-5.ap-northeast-1.compute.internal Ready <none> 66d v1.11.5
ip-172-31-4-131.ap-northeast-1.compute.internal Ready <none> 66d v1.11.5
参考
公式だと以下あたりが参考になりそう
以下も参考にさせていただきましたというかこちらに記載頂いた内容を検証してみました
概要
-
kubectl drain
によって対象 Node から Pod を退去でき、以降も Pod がスケジューリングされないように出来る - 注意点として上記だけでは対象 Node 上で起動している Pod は一度に evicted され、一度に退去させられる可能性がある。例えば ReplicaSet 2 で drain 対象の Node に 2つの Pod が起動していた場合、両方の Pod に対して evicted され、一つも Pod が起動していない時間帯がある可能性が出来てしまう
- PodDisruptionBudget(PDB)を定義することで上記を防ぐことが出来る
やってみる
以下の内容をそのまま利用させて頂きます。
Kubernetes: 複数の Node を安全に停止する (kubectl drain + PodDisruptionBudget)の記事に記載がある内容を試させて頂きます。
上記ではinitialDelaySeconds
を使って Pod が Running になるまでの時間が掛かるようにしていました。これは確かに便利そう。
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 2 # レプリカ数の設定
template:
metadata:
labels:
run: myapp
spec:
containers:
- image: nginx:1.13
name: myapp
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 120 # ready まで 2 分かかる設定
また、PDB(PodDisruptionBudget)では maxUnavailable: 1
を指定。これによって最大無効であってもよい Pod 数を示す。その為、ReplicaSet が 2の場合、一度に2つとも無効になることはない。
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: myapp
spec:
maxUnavailable: 1
selector:
matchLabels:
run: myapp
ということで試す。
まずはデプロイ。
# 2つの Podをデプロイ
$kubectl apply -f myapp-dep.yaml
deployment.extensions "myapp" created
# READY になるまで少し時間が掛かる
$ kubectl get pod -l run=myapp
NAME READY STATUS RESTARTS AGE
myapp-79ddcf65f8-hkvr8 0/1 Running 0 2m
myapp-79ddcf65f8-ssnc8 0/1 Running 0 2m
# 2分ほど経過するといずれも READY になる
$kubectl get pod -l run=myapp
NAME READY STATUS RESTARTS AGE
myapp-79ddcf65f8-hkvr8 1/1 Running 0 2m
myapp-79ddcf65f8-ssnc8 1/1 Running 0 2m
# それぞれ以下の Node で起動している
$ kubectl get pod myapp-79ddcf65f8-hkvr8 -o=jsonpath={..spec.nodeName}
ip-172-31-28-5.ap-northeast-1.compute.internal
$kubectl get pod myapp-79ddcf65f8-ssnc8 -o=jsonpath='{.spec.nodeName}'
ip-172-31-4-131.ap-northeast-1.compute.internal
# 以下で見たほうがスマートだった...
$ kubectl get pods -o wide -l run=myapp
NAME READY STATUS RESTARTS AGE IP NODE
myapp-79ddcf65f8-hkvr8 1/1 Running 0 17m 172.31.21.107 ip-172-31-28-5.ap-northeast-1.compute.internal
myapp-79ddcf65f8-ssnc8 1/1 Running 0 17m 172.31.0.239 ip-172-31-4-131.ap-northeast-1.compute.internal
2つの Node に Pod が配置された。
次に PDB も追加。
# 追加
$kubectl apply -f myapp-pdb.yaml
# PDB の作成を確認
$kubectl get pdb
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
myapp N/A 1 1 30s
# 詳細を確認。現在の設定の場合、少なくとも1つの Pod は生きているように制御される
$kubectl get pdb -o yaml myapp
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"policy/v1beta1","kind":"PodDisruptionBudget","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"maxUnavailable":1,"selector":{"matchLabels":{"run":"myapp"}}}}
creationTimestamp: 2019-05-07T00:09:43Z
generation: 1
name: myapp
namespace: default
resourceVersion: "20681705"
selfLink: /apis/policy/v1beta1/namespaces/default/poddisruptionbudgets/myapp
uid: 6a3083c6-705c-11e9-8fa9-068bb854a108
spec:
maxUnavailable: 1
selector:
matchLabels:
run: myapp
status:
currentHealthy: 2
desiredHealthy: 1
disruptedPods: null
disruptionsAllowed: 1
expectedPods: 2
observedGeneration: 1
OK.
準備ができたので対象 Node をそれぞれ drain する。
$ kubectl drain --ignore-daemonsets --force ip-172-31-28-5.ap-northeast-1.compute.internal
$ kubectl drain --ignore-daemonsets --force ip-172-31-4-131.ap-northeast-1.compute.internal
-w
オプション(watch)を付与して監視
$kubectl get rs -w -l run=myapp
# ReplicaSet によって 起動されるが READY になるまでに2分必要なので READY は1
NAME DESIRED CURRENT READY AGE
myapp-79ddcf65f8 2 2 1 24m
# READY が2になる
myapp-79ddcf65f8 2 2 2 25m
# 上記によってもう一つの Pod も evicted 出来る
myapp-79ddcf65f8 2 1 1 25m
# 起動しているが READY までには2分掛かるので待ち
myapp-79ddcf65f8 2 2 1 25m
# 2つとも READY になった
myapp-79ddcf65f8 2 2 2 38m
ということで実際の結果としても一 PDB を使うことで一斉に Pod が削除されることはなく、想定通り一つずつ削除された。