TL;DR
- kubernetes で hpa 使うと rollingUpdate 時に縮退してしまうことがある
- これを防ぐには deployment で replicas を指定せず、hpa にすべて任せて
minReplicas
で調整するのが良い - 既に デプロイ済みの deployment がある場合は、ワークアラウンドとして
kubectl edit
で、spec.replicas
を削除してしまう手がある
はじめに
(株)いい生活 サーバープラットフォームチーム の多田 (@es-y-tada)です。
Kubernetes で hpa(Horizontal Pod Autoscaler) を使っている際の rollingUpdate を安全に行う方法について解説します。
注釈
この記事は下記環境での実験的観測結果を記載しているため、実際に適用する際は改めて検証していただくことをおすすめいたします。
- Client Version: v1.17.2
- Server Version: v1.13.12-eks-eb1860
スケールアウト時になにが起こるか
deployment で spec.replicas=3
を指定した場合を想定します。
負荷の高まりに従って hpa によって pod 数が 9 にスケールアウトしていたとします。
Q. このとき kubectl apply
によって pod の更新を行うとどうなるでしょう
A. 6pod が Terminate されると同時に、残りの 3pod の中で Strategy に従ったローリングアップデートが起こる
挙動の説明
hpa の機能は、ざっくりと言えば対象の負荷状況に応じた pod の必要数 desiredReplicas
を算出し、 deployment の spec.replicas
を書き変えることです。
Deployment の spec.replicas
に値が指定されている場合、 apply 時に Pod 数がテンプレートに指定された spec.replicas
の値で上書きされます。
hpa の desiredReplicas
の反映はそのあと遅れてやってきます。
実際の動きを今回に当てはめると、
- deployment の
spec.replicas
が 9 -> 3 に置き換わると同時に、この 3pod に対して rollingUpdate がかかる。同時に、このとき過剰と判断された 6pod は削除される - hpa が負荷状況を察知したタイミングでスケールアウトを指示、
desiredReplicas=9
となるよう 6pod が新しく作成される
という動きになります。
この動きの問題は、負荷状態だからスケールアウトしているにも関わらず、一時的にスケールアウト前のデフォルト数まで pod が縮退してしまうため、過負荷によって性能劣化やエラーを誘発してしまう点です。
解決法
こちらの issue に記載があります。
kubectl apply
時に、spec.replicas
が指定されていなければ元の値がキープされることを利用します。
ただし、 既に replicas を指定して Deployment を作成している場合は、 edit して replicas フィールドを削除する必要があります 。
spec.replicas
無指定の templete を初めて apply するタイミングでは、 apply 前の spec.replicas
の値が優先されるため、従前と同様の pod縮退が起きてしまいます。
2回目以降の apply では、 spec.replicas
無指定のテンプレートを元に更新が行われるため、 hpa の desiredReplicas
で置き換わってくれます。
初回適用時の問題に対処するには、 kubectl apply edit-last-applied deployment/the-deployement
を使って、対象 deployment の spec.replicas
フィールドを手動で削除しておく方法があります。
新しく作成する deployment の場合にはもちろんこのようなワークアラウンドな作業は不要です。
deployment + hpa で構成する多くの場合は、始めから deployment の spec.replicas
を指定しないことをおすすめします。