【Kubernetes】Horizontal Pod AutoscalerとDeploymentのレプリカ管理について

スポンサーリンク

はじめに

HPA(Horizontal Pod Autoscaler)をデプロイした場合のレプリカ数の管理について解説していきます。

HPAとDeploymentのレプリカ管理

HPAを使っている場合、レプリカ数についての情報はHPAのspec.minReplicasspec.maxReplicasとDeploymentのspec.replicasに記載されることになってしまいます。

公式ドキュメントでは、HPAを使っている場合、Deploymentのspec.replicasはマニフェストから削除することが推奨されています。

Horizontal Pod Autoscaling
In Kubernetes, a HorizontalPodAutoscaler automatically updates a workload resource (such as a Deployment or StatefulSet), with the aim of automatically scaling ...

Deploymentでもレプリカ数を管理すると

まずHPAとDeploymentの両方でレプリカ数を管理しているとどうなるか見ていきます。

結論から言うと、Deploymentのマニフェストを反映するたびに一時的にDeploymentで指定されているレプリカ数になってしまいます

実際に試してみたいと思います。

Metrics Serverが必要な場合は、下記を参考にインストールしてください。

【Kubernetes】kubectl topでNodeとPodのリソース取得
はじめにKubernetesでNodeとPodが使用しているリソース量を表示する方法を紹介します。また、ローカルでDocker Desktopを利用してkubectl topを利用するための方法も紹介します。NodeとPodのメモリと...

まずはDeploymentから用意します。

マニフェスト(deployment.yaml)は下記の通りです。レプリカ数は2にしてあります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      run: nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m

Deploymentを作成します。

kubectl apply -f deployment.yaml

もちろんレプリカ数は2になっています。

❯ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-58cc49dd47-2hzlx   1/1     Running   0          69s
nginx-58cc49dd47-m9sk5   1/1     Running   0          69s

次はHPAを用意します。

マニフェスト(hpa.yaml)は下記の通りです。最小のレプリカ数を3、最大を10にしています。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 30

HPAを作成します。

kubectl apply -f hpa.yaml

しばらくすると、HPAの設定した内容が反映され、Podが1つ作られ、レプリカ数が3になりました。

❯ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-58cc49dd47-2hzlx   1/1     Running   0          6m14s
nginx-58cc49dd47-g6lbs   1/1     Running   0          31s
nginx-58cc49dd47-m9sk5   1/1     Running   0          6m14s

❯ kubectl get hpa
NAME        REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx-hpa   Deployment/nginx   0%/30%    3         10        3          2m7s

ここで再度、レプリカ数2のDeploymentのマニフェストを反映してみます。

kubectl apply -f deployment.yaml

Podの挙動を見てみると、一度レプリカ数が2になってから、再度3に戻っています。つまり、Deploymentのレプリカ数を一時的に反映してから、HPAの最小レプリカ数が反映されているということになります。

❯ kubectl get pod -w
NAME                     READY   STATUS              RESTARTS   AGE
nginx-58cc49dd47-2hzlx   1/1     Running             0          10m
nginx-58cc49dd47-g6lbs   1/1     Running             0          5m7s
nginx-58cc49dd47-m9sk5   1/1     Running             0          10m
nginx-58cc49dd47-g6lbs   1/1     Terminating         0          5m9s
nginx-58cc49dd47-g6lbs   0/1     Terminating         0          5m11s
nginx-58cc49dd47-rtpv2   0/1     Pending             0          0s
nginx-58cc49dd47-rtpv2   0/1     ContainerCreating   0          0s
nginx-58cc49dd47-rtpv2   1/1     Running             0          3s

試してみた通り、Deploymentのマニフェストを反映するたびに一時的にDeploymentで指定されているレプリカ数になってしまうことが確認できました。

つまり、HPAが負荷を検知してスケールアウトしていたとしても、Deploymentを反映すると一時的にレプリカ数が少なくなってしまうという現象が起きる可能性があるということになります。

Deploymentからレプリカ数を削除すると

では、すでにDeploymentがデプロイされている状態で、マニフェストからspec.replicasを削除して反映するとどうなるでしょうか。

こちらも結論から言うと、一時的にレプリカ数が1になってからHPAで管理されているレプリカ数に戻ります。この場合は、spec.replicasをDeploymentのマニフェストから削除して初めて反映するタイミングだけになります。

実際に試してみます。

Deploymentからspec.replicasを削除します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      run: nginx
  #replicas: 2 # レプリカ数を削除
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m

マニフェストを反映してみます。

kubectl apply -f deployment.yaml

すると、一時的にレプリカ数が1になってから、HPAの最小レプリカ数の3まで戻っています。

❯ kubectl get pod -w
NAME                     READY   STATUS              RESTARTS   AGE
nginx-58cc49dd47-2hzlx   1/1     Running             0          31m
nginx-58cc49dd47-m9sk5   1/1     Running             0          31m
nginx-58cc49dd47-rtpv2   1/1     Running             0          19m
nginx-58cc49dd47-m9sk5   1/1     Terminating         0          31m
nginx-58cc49dd47-2hzlx   1/1     Terminating         0          31m
nginx-58cc49dd47-2hzlx   0/1     Terminating         0          31m
nginx-58cc49dd47-m9sk5   0/1     Terminating         0          31m
nginx-58cc49dd47-mvdgw   0/1     Pending             0          0s
nginx-58cc49dd47-4s6jx   0/1     Pending             0          0s
nginx-58cc49dd47-mvdgw   0/1     ContainerCreating   0          0s
nginx-58cc49dd47-4s6jx   0/1     ContainerCreating   0          0s
nginx-58cc49dd47-mvdgw   1/1     Running             0          7s
nginx-58cc49dd47-4s6jx   1/1     Running             0          9s

安全にDeploymentからレプリカ数を削除する方法

Deploymentからspec.replicasを削除するのが推奨されているとはいえ、単純に削除して反映してしまうと一時的にレプリカ数が1になってしまうのは本番環境などではインパクトが大きいかと思います。

このレプリカ数が1になってしまう現象を回避する場合は、下記の手順でDeploymentのspec.replicasを削除します。

  1. kubectl apply edit-last-applied deployment/<deployment_name>を実行し、エディタ上でspec.replicasを削除する
  2. マニフェストのspec.replicasを削除する
  3. spec.replicasが削除されたマニフェストを反映する

実際に試してみます。

spec.replicasが削除されていないDeploymentを反映します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      run: nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
kubectl apply -f deployment.yaml

下記を実行して、エディタ上からspec.replicasを削除して、保存します。

kubectl apply edit-last-applied deployment/nginx
# Please edit the 'last-applied-configuration' annotations below.
# Lines beginning with a '#' will be ignored, and an empty file will abort the edit.
#
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations: {}
  name: nginx
  namespace: default
spec: # replicasを削除します
  selector:
    matchLabels:
      run: nginx
  template:

そうすると、Podの数はHPAで管理されている数のままになっています。

❯ kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-58cc49dd47-4s6jx   1/1     Running   0          17m
nginx-58cc49dd47-rtpv2   1/1     Running   0          37m
nginx-58cc49dd47-sgtcn   1/1     Running   0          2m40s

次に、Deploymentのマニフェストからspec.replicasを削除します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec: # replicasを削除します
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:

...

これを反映させてみると、unchangedとなりレプリカ数も3のままになっています。

❯ kubectl apply -f deployment.yaml
deployment.apps/nginx unchanged

これで安全にDeploymentからspec.replicasを削除することができました。

まとめ

  • HPAを使っている場合、Deploymentのspec.replicasは削除するのが推奨されている
  • HPAとDeploymentでレプリカ数を管理していると、Deploymentのマニフェストを反映するたびに一時的にDeploymentで指定されているレプリカ数になってしまう
  • すでにデプロイされているDeploymentのマニフェストからspec.replicasを削除すると、次回反映時に一時的にレプリカ数が1になってしまう
  • 安全にDeploymentからspec.replicasを削除するにはkubectl apply edit-last-applied deployment/<deployment_name>で削除してから、マニフェストのspec.replicasを削除する

参考

タイトルとURLをコピーしました