この記事では、Kubernetesの「RuntimeClass」について、初級者から中級者向けに基本的な概念と使い方を解説します。 RuntimeClassはコンテナ実行時のランタイム環境を切り替えるための機能であり、コンテナのセキュリティ強化やパフォーマンス調整に役立ちます (ランタイムクラス(Runtime Class) | Kubernetes)。以下では、RuntimeClassとは何か、その利用シーン、Kubernetesクラスタでの設定方法(YAMLのコードサンプル付き)、適用方法とデバッグのポイントについて説明します。最後に上級者向けコラムとして、gVisorやKata Containersなどの高度な活用例にも触れます。
RuntimeClassとは何か?
RuntimeClass(ランタイムクラス) とは、KubernetesにおいてPodが使用するコンテナランタイムの設定を選択するための機能です (ランタイムクラス(Runtime Class) | Kubernetes)。通常、Kubernetesの各ノード(ワーカーノード)はDockerやcontainerdなどのコンテナランタイムを使ってPod内のコンテナを起動します。RuntimeClassを利用すると、Podごとに異なるコンテナランタイムや実行環境を指定できるようになります。
具体的には、RuntimeClassはKubernetesのリソースオブジェクト(RuntimeClass
リソース)として定義され、spec.handler
(ハンドラー) という名前でコンテナランタイムの種類や設定を指し示します (ランタイムクラス(Runtime Class) | Kubernetes)。Podの定義(PodManifest)の中でRuntimeClass名を指定すると、kubelet(ノード上でPodを起動するエージェント)はそのRuntimeClassに対応するコンテナランタイムでPodのコンテナを実行します (ランタイムクラス(Runtime Class) | Kubernetes)。もしRuntimeClassが指定されない場合、従来通りデフォルトのランタイム(通常は標準的なruncなど)が使われます (ランタイムクラス(Runtime Class) | Kubernetes)。
どのような場面で利用されるのか?
RuntimeClassの主な利用シーンは、「ワークロードごとに異なるコンテナランタイムを使い分けたい場合」 です。これにより、性能とセキュリティのトレードオフを調整できます。例えば、あるPodにはできるだけオーバーヘッドの少ない通常のランタイム(runcなど)を使って高いパフォーマンスを確保し、別の機密性の高いPodには仮想化技術を用いたサンドボックス型ランタイムを使ってセキュリティを強化する、といった運用が可能です (ランタイムクラス(Runtime Class) | Kubernetes)。実際にRuntimeClassを使うことで、必要に応じて一部のPodだけをより厳重に隔離された環境で動作させることができます。
また、RuntimeClassは「異なるランタイム実装」の切り替えだけでなく、同じランタイムでも設定を変えて使い分ける場合にも有用です (ランタイムクラス(Runtime Class) | Kubernetes)。例えば、同じcontainerdランタイムでもセキュリティ強化のオプションを有効にした設定と、デフォルト設定の2種類をRuntimeClassとして登録し、ワークロードに応じて使い分けることができます。これにより、開発者は詳細なランタイム設定の違いを意識することなく、あらかじめ用意された「クラス」を選ぶ感覚で最適な実行環境を選択できます (enhancements/keps/sig-node/585-runtime-class/README.md at master · kubernetes/enhancements · GitHub) (enhancements/keps/sig-node/585-runtime-class/README.md at master · kubernetes/enhancements · GitHub)。
RuntimeClassはKubernetes 1.20でStable(安定版)機能となっており、現在の多くのKubernetes環境でデフォルトで使用可能です (Runtime Class | Kubernetes)。
RuntimeClassの設定方法
それでは、実際にKubernetesクラスタでRuntimeClassを設定し利用する手順を説明します。大まかな流れは以下のとおりです (ランタイムクラス(Runtime Class) | Kubernetes) (〖 更新者も必見 〗 CKS 攻略ガイド ( 2023 年 6 月版 )):
-
ノード側でランタイム環境を準備する – 利用したいコンテナランタイム(例えばgVisorやKata Containersなど)を各ノードにインストールし、Container Runtime Interface (CRI)の設定を行います。これはクラスタ管理者がノード上のcontainerdやCRI-Oの設定ファイルにランタイムを登録する作業です。 (本記事では詳細なノード設定手順は割愛しますが、runtimeClassを使うには事前に各ノードに対応するランタイムを導入しておく必要がある点に注意してください (〖 更新者も必見 〗 CKS 攻略ガイド ( 2023 年 6 月版 ))。)
-
RuntimeClassリソースを作成する – 次に、Kubernetes上にRuntimeClassオブジェクトを作成します。RuntimeClassはクラスター全体(非ネームスペース)で有効なリソースで、
apiVersion: node.k8s.io/v1
で定義されます (ランタイムクラス(Runtime Class) | Kubernetes)。ここで各RuntimeClassには一意の名前と、対応するランタイムハンドラー名を設定します。以下は例として、サンドボックス型ランタイム「gVisor」を利用するためのRuntimeClassリソースを定義するYAMLです (gVisorって何?システムを守る「軽量セキュリティガード」|toshi):apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: gvisor # RuntimeClassの名前 handler: runsc # 対応するCRIランタイムのハンドラー名(gVisorの場合はrunsc)
上記では、RuntimeClass名を
gvisor
、handlerをrunsc
としています。runsc
はgVisorのOCIランタイム名であり、これを指定することでPod実行時にgVisorが利用されます (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)。作成したYAMLファイル(例:
runtimeclass-gvisor.yaml
)をクラスタに適用するには、通常のリソースと同様に以下のコマンドを使用します。kubectl apply -f runtimeclass-gvisor.yaml
-
PodでRuntimeClassを指定する – RuntimeClassリソースを作成しただけではPodには反映されません。実際にPodを起動する際には、そのPodのマニフェストでRuntimeClass名を指定する必要があります。Podの定義 (
spec
部分) にruntimeClassName
フィールドを追加し、利用したいRuntimeClassの名前を値に設定します (ランタイムクラス(Runtime Class) | Kubernetes)。例えば、先ほど作成したgvisor
というRuntimeClassを使ってNginxコンテナを起動するPodのYAMLは次のようになります (gVisorって何?システムを守る「軽量セキュリティガード」|toshi):apiVersion: v1 kind: Pod metadata: name: nginx-gvisor spec: runtimeClassName: gvisor # 利用するRuntimeClassの名前を指定 containers: - name: nginx image: nginx ports: - containerPort: 80
上記の
runtimeClassName: gvisor
という指定により、このPodはgvisor
RuntimeClass(handlerがrunsc
)で動作するコンテナランタイム上にデプロイされます。YAMLファイル(例:nginx-gvisor.yaml
)を準備してkubectl apply -f nginx-gvisor.yaml
を実行すれば、Podが作成されます (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)。
以上が基本的な設定手順です。ここまでで、特定のRuntimeClassを持つPodを起動するところまでの流れができました。
RuntimeClass適用のポイントとデバッグ方法
RuntimeClassを指定したPodをデプロイした後、正しく適用されているかの確認や、問題発生時のデバッグを行う際には以下のポイントに注意してください。
-
適用の確認: Podが正常にスケジューリングされRunning状態になったら、
kubectl describe pod <Pod名>
コマンドでPodの詳細を確認しましょう。出力の中のRuntimeClass
の項目に、指定したRuntimeClass名が表示されていれば、RuntimeClassが適用されていることが確認できます (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)。例えば上記の例では、RuntimeClass: gvisor
と表示されます。 -
Podが起動しない場合: Podが
Pending
のまま進まなかったり、ContainerCreating
から先に進まず**Failed
フェーズ**になってしまう場合、RuntimeClassの適用に問題が起きている可能性があります。代表的な原因と対処法は以下のとおりです。-
RuntimeClassリソースが存在しない – Podで指定した
runtimeClassName
に対応するRuntimeClassオブジェクトが存在しない場合、kubeletはそのPodを起動できず、PodはFailed
状態になります (ランタイムクラス(Runtime Class) | Kubernetes)。この場合、kubectl get runtimeclass
でRuntimeClass一覧を確認し、名前の誤りがないかチェックしてください。必要であれば正しい名前でRuntimeClassを再作成するか、Pod定義のruntimeClassName
を修正します。 -
ノード側でランタイムが未設定 – 指定したRuntimeClassの
handler
に対応するランタイムがノードで正しく設定・インストールされていない場合も、PodはSandboxの作成に失敗します。その際、kubectl describe pod <Pod名>
の**Events(イベント)**欄にエラー内容が記録されます。例えば、gVisor (runsc
ハンドラー) がノードに設定されていないのにPodでruntimeClassName: gvisor
を指定した場合、イベントには「Failed to create pod sandbox: ... no runtime for "runsc" is configured
」といったエラーが表示されます (gVisor pod fail to create pod sandbox — Linux Foundation Forums)。この場合はノードに対応するランタイムをインストール・設定し、必要ならkubeletやコンテナランタイム(containerd/CRI-O)を再起動して設定を反映させる必要があります。 -
対応するノードが存在しない/スケジューリングされない – クラスター内の全ノードが指定のRuntimeClassをサポートしていない場合、Podはどのノードにもスケジュールできず
Pending
状態になります。前述の通りRuntimeClassはクラスターが単一のノード設定であることを仮定しています (ランタイムクラス(Runtime Class) | Kubernetes)。もし一部のノードでしか特定のランタイムを使用できない場合は、ノードにラベルを付けてスケジューリングを制御する必要があります (Secure Compute Part 2: gVisor Runtime on EKS | Very Good Security)。例えば、gVisorをインストールしたノードにruntime=gvisor
とラベル付けし、RuntimeClassリソースに以下のようなspec.scheduling
を設定できます (Secure Compute Part 2: gVisor Runtime on EKS | Very Good Security):spec: scheduling: nodeSelector: runtime: gvisor
この設定により、
gvisor
RuntimeClassを指定したPodはruntime=gvisor
というラベルを持つノードにのみスケジューリングされます(指定したラベルを持つノードが存在しない場合、PodはPendingのままになります) (ランタイムクラス(Runtime Class) | Kubernetes)。必要に応じてtolerations
もRuntimeClass側で設定し、特定ノードへの割り当てを調整できます (ランタイムクラス(Runtime Class) | Kubernetes)。
-
上記のように、RuntimeClass利用時には**「クラスタ内のどのノードでそのRuntimeClassが使えるか」** を考慮することが重要です。全ノードが対応しているのであれば特別な設定は不要ですが、一部のノードのみで使う場合はラベル付けとスケジューリング制御を組み合わせて運用しましょう。
最後に、PodのRuntimeClass適用に関連してリソースのオーバーヘッドにも触れておきます。たとえば軽量VM型のランタイムを使うと、通常のコンテナ実行よりも追加のCPUやメモリを消費する場合があります。KubernetesではRuntimeClassリソースにoverhead
フィールドを設定することで、そのRuntimeClassで動作するPodにあらかじめ割り増しリソース枠を見積もってスケジューリングすることも可能です (ランタイムクラス(Runtime Class) | Kubernetes)。これは上級者向けのチューニングとなりますが、必要に応じて公式ドキュメントを参照してください。
上級者向けコラム: gVisorやKata Containersの活用によるセキュリティ強化
RuntimeClassは、コンテナのセキュリティを強化するサンドボックス型ランタイムを活用するための重要な機能です。ここでは代表的な2つのランタイムである「gVisor」と「Kata Containers」を例に、RuntimeClassを使った応用シナリオを簡単に紹介します。
-
gVisor: gVisorはGoogleが開発した軽量サンドボックス型のコンテナランタイムで、Linuxカーネルと同等のインターフェースをユーザー空間で実装した「仮想カーネル(ユーザー空間カーネル)」を提供します ( What is gVisor? - gVisor)。コンテナからのシステムコールをホストカーネルに直接届けず、この仮想カーネル(gVisor内の*「Sentry」*というコンポーネント)が受け止めて処理することで、万が一コンテナ内で不正な動作が起きてもホストへの影響を抑えます (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)。gVisorをKubernetesで使う場合、各ノードにgVisor(
runsc
というOCIランタイム)をインストールしてcontainerdなどに統合し、RuntimeClassのhandlerにrunsc
を指定する形で設定します (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)。例えば前述の例のようにname: gvisor, handler: runsc
のRuntimeClassを作成し、PodでruntimeClassName: gvisor
を指定すれば、そのPodはgVisor上で動作します。gVisorを使うことで、コンテナの分離が強化され、従来のネイティブコンテナに比べてホストOSへの攻撃リスクを低減できます。一方で完全な仮想マシンではないため、起動の速さやリソース効率といったコンテナの利点もある程度保たれています。Google Kubernetes Engine(GKE)の「GKE Sandbox」は、このgVisorを利用してPodのサンドボックス実行を提供する機能であり、クラウド上でもRuntimeClassとしてgvisor
を指定するだけで容易に利用できます (GKE Sandbox でワークロード分離を強化する - Google Cloud)。 -
Kata Containers: Kata ContainersはOpenStack Foundation主導で公開されたオープンソースのコンテナランタイムで、軽量の仮想マシン(VM)技術によってコンテナを隔離します (Kata Containerとは | OSSのデージーネット) (Kata Containerとは | OSSのデージーネット)。従来の標準的なコンテナランタイム(runcなど)では全てのコンテナがホストの単一カーネルを共有しますが、それに対しKata Containersではコンテナごとに専用の軽量ハイパーバイザー上で個別のカーネルを動作させることで高い分離を実現しています (Kata Containerとは | OSSのデージーネット)。要するに、「各コンテナを小さなVMの中で動かす」アプローチであり、VMによる強固な分離とコンテナの利便性を両立しようとするものです。Kata ContainersをKubernetesで使うには、やはりノードにkata-runtimeをインストールし(例えばQEMU等のVMMを利用)、RuntimeClassを作成します。たとえば
name: kata-containers, handler: kata
というRuntimeClassを作成し、PodでruntimeClassName: kata-containers
を指定すれば、そのPodはKata Containers上で実行されます (Specify Kata Container Runtime in Pod Spec — StarlingX documentation) (Specify Kata Container Runtime in Pod Spec — StarlingX documentation)。Kata Containersはセキュリティが特に重要なワークロード(マルチテナント環境の不審なコンテナなど)に向いており、コンテナの**「ほぼVMに近い隔離」**を提供します。ただし、軽量とはいえ内部的には仮想マシンを動かすため、起動時間やリソース消費にいくらかのオーバーヘッドが発生します。
以上、gVisorとKata Containersという2つのランタイムを例に挙げましたが、RuntimeClassによってKubernetesはこれら複数のコンテナランタイムを柔軟に扱うことができます。Cluster Administratorは必要に応じてRuntimeClassを追加し、開発者やユーザはPodテンプレートで単にRuntimeClass名を指定するだけで希望の隔離レベルでコンテナを実行できるようになります (enhancements/keps/sig-node/585-runtime-class/README.md at master · kubernetes/enhancements · GitHub) (enhancements/keps/sig-node/585-runtime-class/README.md at master · kubernetes/enhancements · GitHub)。コンテナのセキュリティを強化したい場合、まずはRuntimeClassとしてgVisorやKataを試し、ワークロードに適したバランスを見つけてみるとよいでしょう。
参考資料: RuntimeClassの公式ドキュメント (ランタイムクラス(Runtime Class) | Kubernetes) (ランタイムクラス(Runtime Class) | Kubernetes)や、各種ブログ記事(例: gVisor解説記事 (gVisorって何?システムを守る「軽量セキュリティガード」|toshi)、Kata Containers解説記事 (Kata Containerとは | OSSのデージーネット))も併せて参照してください。RuntimeClassの活用により、Kubernetes上でのコンテナ実行環境をより柔軟かつ安全に制御できます。ぜひ自身のクラスタでも適用を試してみてください。