SpringMT / about_kubernetes

2 stars 0 forks source link

kuberenetes内でのcgroup #3

Open SpringMT opened 3 years ago

SpringMT commented 3 years ago

Kubernetes で cgroup がどう利用されているか

SpringMT commented 3 years ago

kubernetesはノード上にPodを配置しますが、なにも制限をせずにPodを配置してPodを動かせばノードのリソースを食いつぶして満足にアプリケーションを動かすことはできなくなります。 そこで、kubernetesはPodに含まれるコンテナに対して、リソースの使用量を決めることができる仕組みを用意しています。

指定できるリソースの種類は下記の通りです。

リソース 単位
CPU vCPU(仮想CPUのコア数) 1 = 1 vCPU(1仮想コア) = 1000 m
メモリ メモリのバイト数 1 Gi = 1024 Mi (1 G 1000 M も使える )
ローカルの一時ストレージ(v1.11以降から利用可能) ストレージの容量 1 Gi = 1024 Mi (1 G 1000 M も使える )

また、リソースの使用量の設定には大きく2つの種類があります。

リソースの要求(下限)(Resource Request)

コンテナ に最低限割り当てたいリソースの下限値を指定します。 Podを配置する際に、Podに含まれるコンテナのリソース要求の量を全て合算して、リソース要求量以上の空きがあるノードに対してPodを配置します。 ノードの空きが無ければ、Podは空きができるまで待機(Pending)状態になります。 リソース要求を指定しない場合は、リソースが0になっても構わないという意味になります。

リソース要求の量を超える場合の挙動

リソースの制限(上限)(Resource Limit)

https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#how-pods-with-resource-limits-are-run

コンテナが使えるリソースの上限を指定します。 指定しないと、無尽蔵に使ってOKってなってしまいます。 リソースの種別によって挙動が異なります。

リソースの設定のデフォルト値

LimitRangeオブジェクトによって設定可能です。 手元でGKEの設定を見てみるとこんな感じです。

% kubectl get LimitRange
NAME      CREATED AT
limits    2018-11-21T05:51:39Z
% kubectl describe limits
Name:       limits
Namespace:  default
Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---  ---  ---------------  -------------  -----------------------
Container   cpu       -    -    100m             -              -

cpuのリソースが100mがデフォルトになっています。 この場合、cpuのリソースリクエストを何も指定しない場合は、100mが自動的にセットされます。

設定例

          resources:
            limits:
              cpu: 2000m
              memory: 2Gi
            requests:
              cpu: 1500m
              memory: 1.5Gi

参照

SpringMT commented 3 years ago

https://medium.com/@betz.mark/understanding-resource-limits-in-kubernetes-memory-6b41e9a955f9

SpringMT commented 3 years ago

クラスタ内でPodのスケールアウトができる仕組みはある クラスタの上限はあるので、あるところでPodのスケールアウト(スケールアップ)は頭打ちになります。 頭打ちになった場合、クラスタをスケールする必要があります。 それがクラスタオートスケールの仕組みです。

クラスタオートスケールの仕組みの概要

https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler

クラスタオートスケールはノードプール単位で機能します。 ノードプールの中で、スケジュールされずにPending状態のPodができたタイミングで発動します。 CPUやメモリの使用量などで発動するものではありません なので、 #14 #15 で適切にコンテナのリソース管理、Podの管理をすることが重要になります。(最初のDeploymentの設定で過剰にリソースを確保する場合でも発動しますが。。)

クラスタのオートスケールはResource Requestsを基準に機能します。(実際のCPUの消費量などを監視して発動しない) Resource Requestsが実際よりも大きすぎると無駄にクラスタのオートスケールが走ってしまいますし、Resource Requestsが実際よりも小さすぎると、今あるリソースの中でスケジューリング可能と判断されてオートスケールが発動しません。 適切にResource Requestsを設定することが求められています(VPAなどで自動的に調整できればよさそうですね)

https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#when-does-cluster-autoscaler-change-the-size-of-a-cluster

ノードの追加時の挙動

増やすのは特に考えることも少なくいける。

ノード削除時の挙動

リソースの利用量が減ってくると、ノードを削除することになるのですが、これがまあ厄介。 ノードの削除によって、サービス断が起こる可能性がでてきます。 そのため、PodDisruptionBudgetを指定して、Podが一つも上がっていない状況を避けるほうが望ましいです。 ノードに含まれるPodの条件によってはNodeの削除が行われないこともあります。

試してみる

クラスタのオートスケールに対応しているのでは下記に載っている通り。 https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#deployment

SpringMT commented 3 years ago

コンテナのリソースを超えた場合は、超過したことに応じてスケールしてもらいたいものです。 kubernetesでは、利用しているリソース量に応じてPodをスケールする仕組みを持っています。

スケールの方法としては、スケールアウトとスケールアップの両方があります。

Podのスケールアウト HorizontalPodAutoscaler(HPA)

HPAはPodの を増やすためのリソースです。 スケールアウトするための基準値はリソース管理の設定とは別に設定をする必要があります。 HPAは各種メトリクスを取得するAPIを定期的に叩いてメトリクスを取得しています。 メトリクスを取得する間隔は --horizontal-pod-autoscaler-sync-period によって設定される(v1.13だとデフォルト15 sec、v1.11だと30 sec) GKEの場合、特に設定されているようにはみえないので、デフォルトが設定されると思われます。 https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/

スケーリングの仕様

Podの増加数の計算は下記の通り

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]

一回に増えるPodの数は、要求する数がその時上がっているPodの2倍、もしくは2倍にしても4つまで届かない場合は4つまで一気に増えます。 https://github.com/kubernetes/kubernetes/blob/1b28775db1290a772967d192a19a8ec447053cd5/pkg/controller/podautoscaler/horizontal.go#L699 https://github.com/kubernetes/kubernetes/blob/1b28775db1290a772967d192a19a8ec447053cd5/pkg/controller/podautoscaler/horizontal.go#L671 これはハードコードされているので変更不可ですね。

アップスケールの間隔は、v1.12以降では随時行われるようになっています。 ダウンスケールの間隔は5分になっています。 https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-cooldown-delay

HPAで指標とできるメトリクスの種類

種類 用途
Resource CPU / メモリ
Pod Podのメトリクス(だいたいカスタムメトリクスになりそう)
Object Kubernetesのオブジェクトのメトリクス(単一のPodの値とか)
External Kubernetes 外のメトリクス(GKEのCloud Pub/Sub例の例)

GKEでstackdriverのカスタムメトリクスを使ったHPA

https://cloud.google.com/kubernetes-engine/docs/tutorials/custom-metrics-autoscaling

stackdriverのカスタムメトリクスを送るサイドカーのコンテナ https://github.com/SpringMT/rack-server-status-to-sd

Podのスケールアップ(VerticalPodAutoscaler)

kubernetesのissue https://github.com/kubernetes/enhancements/issues/21

Podのリソースの上限に達したら、自動的にResource Requestを設定し直す機能になります。 GKEでは1.11.3以降から利用可能となっています。

重要なのは、Request の値はあくまでもユーザが指定した値であり、実際のリソース使用量とは無関係であるという点です。そのため、Request が小さすぎると実際の動作時にリソースが不足してアプリケーションの挙動に悪影響を与える可能性がある一方、大きすぎるとリソースが余っているのにもかかわらず Pod が配置されないスペースが増えるため、集積度が下がり無駄なコストを抱えることになります。
この Request と実績値の乖離という問題を解決するのが VPA です。VPA は、リソース使用量の実績値をモニタして、過去の履歴から算出した推奨値を自動で Request として設定してくれます。結果として、Scheduler はその Pod をより実態に合った Node に配置することができ、クラスタ全体のリソースを有効活用することができます。

Resource Requestの設定に頭を悩ませなくて良くなりそうではあります。

参照