Open SpringMT opened 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つの種類があります。
コンテナ に最低限割り当てたいリソースの下限値を指定します。 Podを配置する際に、Podに含まれるコンテナのリソース要求の量を全て合算して、リソース要求量以上の空きがあるノードに対してPodを配置します。 ノードの空きが無ければ、Podは空きができるまで待機(Pending)状態になります。 リソース要求を指定しない場合は、リソースが0になっても構わないという意味になります。
CPU
dockerの場合は --cpu-shared
によって設定されます。
https://github.com/kubernetes/kubernetes/blob/e69c735b9e5b37a08e07b0a5e68dd8705d99219c/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go#L51
メモリ
CPU 余剰のCPUがあれば、それを無尽蔵に使っていきます。 なので下記のリソースの制限を使って上限を決めましょう
メモリ 指定した値を超える用のメモリを使い始めたら、OOM Killerさんに目をつけられ、いつでもコンテナ終了の憂き目に合うことがあります。
コンテナが使えるリソースの上限を指定します。 指定しないと、無尽蔵に使ってOKってなってしまいます。 リソースの種別によって挙動が異なります。
CPU
指定した値以上にCPUを利用できません。
dockerであれば、 --cpu-quota
によって設定されます。
https://github.com/kubernetes/kubernetes/blob/e69c735b9e5b37a08e07b0a5e68dd8705d99219c/pkg/kubelet/kuberuntime/kuberuntime_container_linux.go#L76
メモリ 指定した値以上のメモリを利用したら、OOM Killerによってコンテナごと終了させられます。 残念無念
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
クラスタ内で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などで自動的に調整できればよさそうですね)
増やすのは特に考えることも少なくいける。
リソースの利用量が減ってくると、ノードを削除することになるのですが、これがまあ厄介。 ノードの削除によって、サービス断が起こる可能性がでてきます。 そのため、PodDisruptionBudgetを指定して、Podが一つも上がっていない状況を避けるほうが望ましいです。 ノードに含まれるPodの条件によってはNodeの削除が行われないこともあります。
クラスタのオートスケールに対応しているのでは下記に載っている通り。 https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#deployment
コンテナのリソースを超えた場合は、超過したことに応じてスケールしてもらいたいものです。 kubernetesでは、利用しているリソース量に応じてPodをスケールする仕組みを持っています。
スケールの方法としては、スケールアウトとスケールアップの両方があります。
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
種類 | 用途 |
---|---|
Resource | CPU / メモリ |
Pod | Podのメトリクス(だいたいカスタムメトリクスになりそう) |
Object | Kubernetesのオブジェクトのメトリクス(単一のPodの値とか) |
External | Kubernetes 外のメトリクス(GKEのCloud Pub/Sub例の例) |
https://cloud.google.com/kubernetes-engine/docs/tutorials/custom-metrics-autoscaling
stackdriverのカスタムメトリクスを送るサイドカーのコンテナ https://github.com/SpringMT/rack-server-status-to-sd
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の設定に頭を悩ませなくて良くなりそうではあります。
Kubernetes で cgroup がどう利用されているか