RuntimeClass 要件のソース

1. コンテナランタイムのプロセス進化

まず、コンテナランタイムの進化について理解しましょう。プロセス全体は、大きく3つの段階に分かれています。

  • 第一のステップ:2014 年 6 月

Kubernetesは正式にオープンソースとなり、Dockerは当時唯一のデフォルトのコンテナランタイムでした。

  • 第二のステップ:Kubernetes v1.3

rktはKubernetesに統合され、2番目のコンテナランタイムになりました。

  • 第三のステップ:Kubernetes v.15

同時に、多くのコンテナランタイムもKubernetesに統合される方向でした。しかしrktやDockerなどの組み込みサポートがある場合、それはKubernetesコードの保守と品質保証に深刻な課題をもたらします。コミュニティはこれを認識していたため、CRIはバージョン1.5で開始されました。その名称はContainer Runtime Interfaceです。

この利点は、ランタイムとKubernetesの分離が実現し、コミュニティがさまざまなランタイムの適応作業を行う必要がなくなり、ランタイムとKubernetesの間の不整合によって引き起こされるバージョンメンテナンスの問題を心配する必要がないことです。より一般的には、たとえば、containerdのcriプラグインはCRIを実装し、kata-containersやgVisorなどのコンテナは実行時にcontainerdとドッキングさせるだけで済みます。更に多くのコンテナランタイムが出現すれば、異なったコンテナランタイムには異なった需要シナリオがあり、多くのコンテナランタイムに対する需要が生まれるでしょう。ただし、マルチコンテナランタイムを実行する方法では、次の問題も解決する必要があります。

  • クラスターで使用できるコンテナランタイムは何か?
  • Podに適したコンテナランタイムを選択するにはどうすればよいか?
  • 指定されたコンテナランタイムを使用してノードにPodをスケジュールする方法
  • コンテナの実行中は、コンテナの実行業務以外の追加のオーバーヘッドが発生するが、この「追加オーバーヘッド」はどのように計算するか?

2. RuntimeClassの一般的なワークフロー

上記の問題を解決するために、コミュニティはRuntimeClassを立ち上げました。これは実際にはKubernetes v1.12で導入されましたが、元々はCRDの形式で導入されました。 v1.14以降、組み込みクラスターリソースオブジェクトRuntimeClassとして導入されました。 v1.16は、v1.14に基づいてスケジューリングとオーバーヘッドの機能を拡張しました。

以下は、RuntimeClassのワークフローを説明するための例としてv1.16を取りあげます。 上の図に示すように、左側がワークフローのフローChart で、右側がYAMLファイルです。
YAMLファイルには2つの部分が含まれています。上部はrunvという名前のRuntimeClassオブジェクトの作成を担当し、下部はspec.runtimeClassNameを通じてRuntimeClass runvを参照するPodの作成を担当します。
RuntimeClassオブジェクトの中核はハンドラーです。これは、コンテナの作成要求を受信するプログラムを表し、コンテナランタイムにも対応します。 たとえば、上記例のPodは最終的にrunvコンテナランタイムによって作成されます。スケジューリングは、Podが最終的にスケジュールされるノードを決定します。
左側の図と合わせて、RuntimeClassのワークフローを説明します。

  • K8s-masterがPodを作成するリクエストを受け取りました。
  • 正方形の部分は、3種類のノードを表します。 各ノードには、現在のノードでサポートされているコンテナランタイムを識別するためのラベルがあります。ノードには1つ以上のハンドルがあり、各ハンドルはコンテナランタイムに対応しています。 たとえば、2番目の四角はノードにruncおよびrunvコンテナランタイムをサポートするハンドラーがあることを示し、3番目の四角はノードにrunhcsコンテナランタイムをサポートするハンドラーがあることを示します。
  • Scheduling.nodeSelectorによると、Podは最終的に中央のノードにスケジュールされ、Podはrunvハンドラーによって作成されます。

RuntimeClass 機能紹介

1. RuntimeClass 構造体の定義

例として、Kubernetes v1.16のRuntimeClassを取り上げましょう。 まず、RuntimeClassの構造定義を紹介します。
RuntimeClassオブジェクトはコンテナランタイムを表し、その構造には主にHandler、Overhead、およびSchedulingの3つのフィールドが含まれます。

  • 前述の例では、コンテナの作成要求を受け取り、コンテナランタイムにも対応するプログラムを表すハンドラーについて説明しました。
  • オーバーヘッドは、v1.16でのみ導入された新しいフィールドで、Podでのビジネスオペレーションに必要なリソースを超える追加のオーバーヘッドを表します。
  • 3番目のフィールドであるSchedulingもv1.16で導入され、Scheduling構成は自動的にPodのnodeSelectorに挿入されます。

2. RuntimeClass リソース定義の例

PodでのRuntimeClassの参照の使い方は非常に簡単です。runtimeClassの名前がruntimeClassNameフィールドで構成されている限り、このRuntimeClassを導入できます。

3. Scheduling 構造体の定義

名前が示すように、Schedulingはスケジューリングを意味しますが、ここでのスケジューリングは、RuntimeClassオブジェクト自体のスケジューリングを意味するのではなく、RuntimeClassを参照するPodのスケジューリングに影響します。

スケジューリングには、NodeSelectorとTolerationsの2つのフィールドが含まれます。 これら2つは、Pod自体に含まれるNodeSelectorおよびTolerationsによく似ています。
NodeSelectorは、RuntimeClassをサポートするノード上にあるはずのラベルのリストを表します。 PodがRuntimeClassを参照した後、RuntimeClass admissionはラベルリストをPod内のラベルリストとマージします。 これらの2つのラベルの間に矛盾がある場合は、admissionによって拒否されます。 ここでの競合は、キーは同じであるが値が異なることを意味します。この場合、それらはadmissionによって拒否されます。

注意すべきもう1つの点は、RuntimeClassはNodeのラベルを自動的に設定しないため、ユーザーが使用する前に事前に設定する必要があることです。
Tolerationsは、RuntimeClassの許容範囲リストを表します。 PodがRuntimeClassを参照すると、admissionは許容リストをPod内の許容リストとマージします。 2つの許容差が同じ許容差設定を持つ場合、それらは1つにマージされます。

4. なぜPod Overheadが導入されたか?

左側はDockerPod、右側はKataPodです。
従来のコンテナに加えて、Docker Podにはpauseコンテナもありますが、コンテナのオーバーヘッドを計算するときにpauseコンテナを無視します。 Kata Podの場合、コンテナ、kata-agent、pause、guest-kernelを除いてカウントされません。 これらのオーバーヘッドは、多くの場合100MBを超えることもあり、これらのオーバーヘッドは無視できません。
これが、Pod Overheadを導入するという当初の目的です。 その構造は次のように定義されています。

その定義は非常に単純で、PodFixedフィールドは1つだけです。 これは内部のマッピングでもあり、そのキーはResourceNameで、値はQuantityです。 各数量は、リソースの使用状況を表します。 したがって、PodFixedは、CPUやメモリーの占有率など、PodFixedを介して設定できるさまざまなリソースの占有率を表します。

5. Pod Overhead の使用シナリオと制限

Pod Overhead の使用シナリオは主に3つです。

  • Pod スケジューリング
    Overheadが導入される前は、ノードのリソースの可用性がPodのリクエスト以上である限り、Podをこのノードにスケジュールできます。Overheadの導入後、ノードのリソースの可用性がOverheadにリクエストの値を加えた値以上である場合にのみ、スケジューリングできます。
  • ResourceQuota
    これは名前空間レベルのリソース割り当てです。 このような名前空間があり、そのメモリー使用量が1Gであり、リクエストが500に等しいPodがあるとすると、この名前空間では、最大2つのPodをスケジュールできます。 また、これらの2つのPodに200MBのOverheadを追加すると、この名前空間で最大1つのPodをスケジュールできます。
  • Kubelet Pod の追放
    Overheadの導入後、Overheadはノードの使用済みリソースにカウントされるため、使用済みリソースの割合が増加し、最終的にKubeletPodの排除に影響します。 上記はPodOverheadの使用シナリオです。 さらに、PodOverheadにはいくつかの制限と注意事項があります。
  • PodOverheadは最終的にPodに永続的に挿入され、手動で変更することはできません。 RuntimeClassが削除または更新されても、PodOverheadは存在し、有効です。
  • PodOverheadは、RuntimeClass admissionによって(少なくとも現時点では)自動的に挿入でき、手動で追加または変更することはできません。 これを行うと拒否されます。

HPAとVPAはコンテナレベルのメトリックデータに基づいて集計され、PodOverheadはそれらに影響しません。

マルチコンテナランタイムの例

現在、Alibaba Cloud ACKセキュリティサンドボックスコンテナはマルチコンテナランタイムをサポートしています。上図に示す環境を例として、マルチコンテナランタイムの仕組みを説明します。
上の図に示すように、2つのPodがあります。左側はruncのPod、対応するRuntimeClassはrunc、右側はrunvのPod、および参照されるRuntimeClassはrunvです。
対応するリクエストは異なる色でマークされ、青はrunc、赤はrunvを表します。 図の下部では、コアパーツがcontainerdされています。containerdでは、複数のコンテナを実行するように構成できます。最後に、上記の要求もここに到着して要求を転送します。
まずruncのリクエストを見てみましょう。最初にkube-apiserverに到着し、kube-apiserverリクエストがkubeletに転送され、最後にkubeletがリクエストをcri-plugin(CRIを実装するプラグインです)に送信します。cri-pluginはcontainerdにあります 構成ファイルでruncに対応するハンドラーを照会し、最終的に、Shim APIランタイムv1を通じてcontainerd-shimが要求されていることを確認し、対応するコンテナを作成します。これがruncの流れです。
runvのフローはruncのフローに似ています。最初にkube-apiserverに到達し、次にkubeletに到達し、次にcri-pluginに到達します。cri-pluginは最終的に、containerdに一致する構成ファイルに戻り、最終的にShim APIランタイムv2によって作成されたcontainerd-shim-kata-createdを見つけます。 v2、それからKata Podを作成します。
次に、containerdの具体的な構成を見てみましょう。

containerdはデフォルトでfile:///etc/containerd/config.tomlに配置されます。 コア構成はplugins.cri.containerdディレクトリにあります。
ランタイムの構成には同じ接頭辞plugins.cri.containerd.runtimesがあり、その後に2つのRuntimeClass runc、runvが続きます。ここで、runcとrunvは、前のRuntimeClassオブジェクトのハンドラーの名前に対応しています。さらに、特殊な設定plugins.cri.containerd.runtimes.default_runtimeがあります。これは、PodがRuntimeClassを指定せず、現在のノードにスケジュールされている場合、デフォルトのruncコンテナを使用して実行することを意味します。
次の例では、runcとrunvの2つのRuntimeClassオブジェクトを作成しています。kubectlget runtimeclassを使用すると、現在使用可能なすべてのコンテナランタイムを確認できます。

次の図は、runcとrunvのPodを左から右に示しています。比較の要点となるのは、runcとrunvのコンテナのランタイムがruntimeClassNameフィールドで参照されることです。

Podが最終的に作成された後、kubectlコマンドを使用して、各Podコンテナの実行ステータスと、Podで使用されるコンテナランタイムを表示できます。 クラスターに2つのPodがあることがわかります。1つはrunc-pod、もう1つはrunv-podで、それぞれruncとrunvのRuntimeClassを参照しており、それらの状態はどちらもRunningです。

この記事のまとめ

この記事の主な内容はここまでです。ここに簡単にまとめます。

  • RuntimeClassはKubernetesの組み込みクラスターリソースであり、主に複数コンテナのランタイムミキシングの問題を解決するために使用されます。
  • 指定したコンテナランタイムを実行するノードにPodを自動的にスケジュールできるように、RuntimeClassでSchedulingを構成できます。 ただし、前提として、ユーザーはこれらのノードのラベルを事前に設定する必要があります。
  • OverheadはRuntimeClassに構成され、Podで必要なビジネスオペレーション以外のオーバーヘッドをカウントできるため、スケジューリング、
    ResourceQuota、KubeletPodの削除、その他の動作がより正確になります。
PAGE TOP