0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kata Containers 4.0・gVisor・Firecrackerの本番ベンチマークとAIエージェント向けサンドボックス設計

0
Last updated at Posted at 2026-08-04

Kata Containers 4.0・gVisor・Firecrackerの本番ベンチマークとAIエージェント向けサンドボックス設計

この記事でわかること

  • Kata Containers 4.0のRust製runtime-rsとDragonball VMMが本番環境で何を変えるかの定量評価
  • runc・Kata Containers・gVisorのCPU/メモリ/I/O/HTTPスループットの実測ベンチマーク比較
  • AIエージェントのコード実行を安全に隔離するRuntimeClassベースのマルチランタイム設計パターン
  • 各ランタイムのセキュリティ境界の違いと、マルチテナント環境で選定する際の判断基準
  • 本番Kubernetesクラスタでのトラブルシューティングと回避すべき落とし穴

対象読者

  • 想定読者: Kubernetesの基本操作を理解しているインフラエンジニア・SRE・MLエンジニア
  • 必要な前提知識:
    • Kubernetesのpod・namespace・RuntimeClassの基本概念
    • Linuxのコンテナ技術(namespace・cgroup)の基礎理解
    • kubectlコマンドの基本操作

MLエンジニアの方へ: AI/MLの知識は前提としますが、カーネル仮想化やsyscall interceptionの仕組みは基礎から解説します。PyTorchのtorch.compileがPythonコードをカーネルレベルで最適化するように、ここで扱うのは「コンテナをカーネルレベルでどう分離するか」という技術です。

結論・成果

2026年7月リリースのKata Containers 4.0を含む3つのランタイムを実測ベンチマークで比較した結果、以下の選定指針が得られました。

観点 Kata Containers 4.0 gVisor(systrap) Firecracker
起動時間 150-300ms 50-100ms 100-200ms
CPUオーバーヘッド -2.7%(ほぼゼロ) -1.7%(ほぼゼロ) 2-8%
メモリオーバーヘッド 50-150MB 10-50MB 5-10MB(VMM部分)
HTTP req/sec(vs runc) -89% -42% N/A(直接CRI非対応)
分離レベル ハードウェア(KVM) ユーザースペースカーネル ハードウェア(KVM)
K8s統合 ネイティブ(CRI) RuntimeClass Kata経由で利用可

CPUとメモリの計算性能はほぼ差がないことが確認されました。差が顕著に出るのはI/OとHTTPスループットで、ワークロードの特性に応じた選定が必要です。

既存記事との関係: コンテナ分離技術の基礎アーキテクチャと選定基準については、前回の記事「Kata Containers・gVisor・Firecrackerで学ぶコンテナ分離技術の選定と実装ガイド」で解説しています。本記事では、2026年7月リリースのKata Containers 4.0の新機能と、実測ベンチマークに基づく本番運用設計にフォーカスします。

Kata Containers 4.0の新アーキテクチャを理解する

2026年7月にリリースされたKata Containers 4.0は、プロジェクト史上もっとも大きなアーキテクチャ変更を含むリリースです。Rust製ランタイム(runtime-rs)がデフォルトとなり、従来のGoランタイムは非推奨になりました。ここではこの変更が本番環境にどう影響するかを見ていきましょう。

runtime-rs(Rust製ランタイム)への移行

Kata Containers 4.0の中核となる変更は、ランタイム実装がGoからRustに全面移行したことです。公式ブログによると、この移行には3つの狙いがあります(Kata Containers 4.0.0 Preview)。

  1. メモリ効率の向上: 大規模デプロイでのメモリフットプリント削減
  2. セキュリティ強化: Rustのメモリ安全性によるサンドボックスの堅牢化
  3. 起動レイテンシの低減: Goのガベージコレクションに起因する一時停止の排除
# /etc/kata-containers/configuration.toml の主要設定(4.0)
# runtime-rs がデフォルトになったため、明示指定は不要
[runtime]
# runtime-rs は自動選択される
# 従来の Go ランタイムを使う場合のみ明示指定が必要
# runtime_type = "go"  # 非推奨: 5.0で削除予定

[hypervisor.dragonball]
path = "/usr/bin/dragonball"
kernel = "/usr/share/kata-containers/vmlinux.container"
# Dragonball は in-process VMM のためオーバーヘッドが小さい
default_memory = 256
default_vcpus = 1
# virtio-fs でホストファイルシステムを共有
shared_fs = "virtio-fs"

なぜRustへの移行が重要か:

Goランタイムではガベージコレクション(GC)の一時停止がコンテナ起動時のレイテンシに影響していました。数百のpodを同時スケジュールする大規模クラスタでは、GC pauseが積み重なって起動時間のP99が悪化するケースが報告されています。Rustではこのオーバーヘッドが排除されます。

注意点:

Goランタイムは4.0で非推奨となり、5.0(18ヶ月後の予定)で削除される見込みです。既存のGo依存のカスタム設定を使っている場合は、移行計画を立てる必要があります。特にカスタムhookやプラグインをGoランタイムのAPI向けに実装している場合、runtime-rsのAPI互換性を事前に確認してください。

Dragonball VMM:軽量インプロセスハイパーバイザ

4.0のもう一つの注目点は、Ant Group(アリババグループ)が開発したDragonball VMMがデフォルトハイパーバイザになったことです。

従来のQEMU構成では、kata-shimとQEMUが別プロセスとして動作し、プロセス間通信のオーバーヘッドが発生していました。Dragonballはcontainerd shimプロセス内で直接動作するインプロセスVMMで、このオーバーヘッドを排除します。

Dragonballは以下のvirtioデバイスをサポートしています(Cloud Native Now)。

  • virtio-net: ネットワーク
  • virtio-blk: ブロックストレージ
  • VFIO: デバイスパススルー(GPUパススルーに重要)

制約条件:

DragonballはQEMUほどのデバイスエミュレーション機能を持ちません。レガシーデバイスのエミュレーションが必要な場合や、NVIDIAのGPUパススルー(vGPU)を使う場合はQEMUを選択する必要があります。GPUパススルー(VFIO)はDragonballでもサポートされていますが、vGPU(NVIDIA GRID)はQEMUのみの対応です。

対応アーキテクチャとハイパーバイザの選択肢

runtime-rsは4つのハイパーバイザをサポートしています。

ハイパーバイザ 特徴 推奨ユースケース
Dragonball インプロセスVMM、最小オーバーヘッド 標準的なサンドボックス、AIエージェント実行
Cloud Hypervisor 高性能、VFIOサポート GPUワークロード、高I/O環境
QEMU 最大の互換性、vGPU対応 レガシー環境、GPU仮想化
Firecracker 最小フットプリント、高速起動 FaaS基盤、ステートレスワークロード

対応アーキテクチャはx86_64、ARM64、IBM s390x、IBM PowerPC、RISC-V(実験的)です。

実測ベンチマークで比較する3つのランタイム

ここからは、公開されているベンチマークデータを基に、runc(標準ランタイム)を基準としたKata Containers・gVisorの性能差を定量的に見ていきます。

ベンチマーク環境と手法

以下のベンチマークデータは、bikramkgupta/container-runtime-benchmarksリポジトリで公開された実測値です。

項目
ハードウェア DigitalOcean c5-8vcpu-16gb-intel(Intel Xeon Gold 6548N)
OS Ubuntu 24.04.3 LTS, kernel 6.8.0
Kubernetes v1.32.11
リソース制限 2 CPU / 4GiB memory per pod
Kata VMM Cloud Hypervisor v50.0
試行回数 各ワークロード3回、中央値を採用

CPU・メモリ性能:ほぼ差なし

まず計算性能の比較です。sysbench CPUベンチマーク(--threads=2)とメモリベンチマーク(1MBブロック、10GB total)の結果を見てみましょう。

ワークロード runc Kata(CLH) gVisor 差分
CPU(events/sec) 2,258 2,197(-2.7% 2,220(-1.7% ほぼ同等
メモリ(MiB/s) 34,002 32,829(-3.4% 34,025(+0.07% ほぼ同等

CPU・メモリの計算性能では3つのランタイムにほとんど差がありません。Kata Containersのオーバーヘッドは仮想化レイヤの存在によるものですが、-2.7%は誤差範囲です。gVisorのメモリ性能がruncとほぼ同一なのは、メモリ操作ではsyscall interceptionが発生しないためです。

ポイント: 計算集約型のワークロード(ML推論、データ処理パイプラインなど)では、どのランタイムを選んでもCPU性能への影響はほぼゼロです。

I/O性能:ランタイムごとに大きな差

I/O性能ではランタイム間の差が顕著に現れます。fioによるディスクI/Oベンチマークの結果です。

ワークロード runc Kata(CLH) gVisor
シーケンシャル読込(MiB/s) 1,808 3,831(+112% 11,776(+551%
ランダム4K読書(MiB/s) 3,838 45.8(-99% 932(-76%

この結果は一見すると矛盾しているように見えます。シーケンシャル読み込みではgVisorがruncの5.5倍の速度を記録する一方、ランダム4Kアクセスではruncの24%しか出ていません。

なぜこのような差が出るのか:

gVisorのSentryプロセスは独自のページキャッシュを持っています。シーケンシャルな大量読み込みではこのキャッシュが効率的に機能しますが、ランダムアクセスではsyscall interceptionのオーバーヘッドがキャッシュの恩恵を上回ります。一方、Kata Containersのランダム4K性能が-99%と極端に低いのは、ゲストカーネルとホスト間のvirtio-blk通信レイテンシが小ブロックI/Oで支配的になるためです。

よくある間違い: 「gVisorはI/Oが遅い」と一概に言われますが、実際にはシーケンシャルI/Oではruncより高速です。ワークロードのI/Oパターンを事前にプロファイリングして判断する必要があります。

HTTPスループット:最大の差分ポイント

nginx + wrkによるHTTPベンチマーク(-t4 -c100 -d30s)の結果です。

メトリクス runc Kata(CLH) gVisor
req/sec 26,400 2,888(-89% 15,310(-42%
レイテンシ(ms) 10.04 35.08 6.62

スループットではruncが圧倒的ですが、レイテンシではgVisorが最も低い値を記録しています。これはgVisorのネットワークスタック実装がLinuxカーネルと異なる最適化をしているためと考えられます。

トレードオフ: gVisorはレイテンシは低いがスループットが低い、Kata Containersはレイテンシもスループットも低い。リバースプロキシやAPIゲートウェイのようなHTTP多重化が前提のワークロードでは、このオーバーヘッドが直接的にスループット低下につながります。

AIエージェント向けマルチランタイムサンドボックスを設計する

2026年のコンテナランタイム選定で最も注目されているユースケースが、AIエージェントが生成するコードの安全な実行です。LLMが生成したコードを本番環境で実行する場合、通常のコンテナ(runc)ではホストカーネルを共有しているため、カーネル脆弱性を突いたエスケープのリスクがあります。

ここでは、Kubernetes上で信頼度に応じてランタイムを使い分けるマルチランタイム設計パターンを解説します。

RuntimeClassによるランタイム切り替え

KubernetesのRuntimeClassは、podのspec内で使用するコンテナランタイムを指定する仕組みです。PyTorchでいえば、.to("cuda")でGPUに切り替えるのと同じように、runtimeClassNameで分離レベルを切り替えられます。

# RuntimeClass定義: gVisor用
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
scheduling:
  nodeSelector:
    sandbox.runtime/gvisor: "true"
overhead:
  podFixed:
    memory: "64Mi"
    cpu: "50m"
---
# RuntimeClass定義: Kata Containers用
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata-dragonball
handler: kata-dragonball
scheduling:
  nodeSelector:
    sandbox.runtime/kata: "true"
overhead:
  podFixed:
    memory: "256Mi"
    cpu: "100m"

overheadフィールドは、Kubernetes 4.0で導入されたサンドボックスリソースアカウンティングに対応しています。ランタイム自体が消費するリソースをpodのリソース要求に自動加算することで、スケジューラが正確なリソース配置を行えるようになります。

信頼度レベルに基づくランタイム選択

マルチテナントのAIエージェント実行基盤では、実行するコードの信頼度に応じてランタイムを使い分けます。

# レベル1: 信頼済みコード(社内ツール、検証済みライブラリ)
# → runc(標準ランタイム)で実行
apiVersion: v1
kind: Pod
metadata:
  name: trusted-agent-task
  labels:
    trust-level: "high"
spec:
  # runtimeClassName を指定しない = デフォルト(runc)
  containers:
  - name: task
    image: internal-registry/verified-tool:v2.1
    resources:
      limits:
        cpu: "2"
        memory: "4Gi"
    securityContext:
      runAsNonRoot: true
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false
---
# レベル2: 準信頼コード(社内LLMが生成、レビュー済み)
# → gVisor で実行(KVM不要、syscall filtering)
apiVersion: v1
kind: Pod
metadata:
  name: semi-trusted-agent-task
  labels:
    trust-level: "medium"
spec:
  runtimeClassName: gvisor
  containers:
  - name: task
    image: internal-registry/agent-sandbox:latest
    resources:
      limits:
        cpu: "1"
        memory: "2Gi"
    securityContext:
      runAsNonRoot: true
      readOnlyRootFilesystem: true
---
# レベル3: 未信頼コード(外部ユーザー入力、未検証LLM出力)
# → Kata Containers(ハードウェア分離)で実行
apiVersion: v1
kind: Pod
metadata:
  name: untrusted-agent-task
  labels:
    trust-level: "low"
spec:
  runtimeClassName: kata-dragonball
  containers:
  - name: task
    image: internal-registry/agent-sandbox:latest
    resources:
      limits:
        cpu: "1"
        memory: "2Gi"
    securityContext:
      runAsNonRoot: true
      readOnlyRootFilesystem: true

なぜこの3段階が必要か:

すべてのワークロードをKata Containersで実行すれば安全性は最大化されますが、メモリオーバーヘッドが50-150MB/podのため、数千podを同時実行する環境ではコストが膨大になります。信頼度に応じてランタイムを使い分けることで、セキュリティとリソース効率のバランスを取ります。

Kyvernoによるランタイム強制ポリシー

手動でruntimeClassNameを指定する運用はヒューマンエラーのリスクがあります。Kyvernoポリシーエンジンを使って、namespace単位でランタイムを自動強制しましょう。

# Kyverno ClusterPolicy: untrusted namespaceでは
# Kata Containers を強制
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-kata-for-untrusted
spec:
  validationFailureAction: Enforce
  background: true
  rules:
  - name: require-kata-runtime
    match:
      any:
      - resources:
          kinds:
          - Pod
          namespaces:
          - "agent-sandbox-*"
          - "untrusted-*"
    validate:
      message: >-
        Pods in untrusted namespaces must use kata-dragonball
        RuntimeClass for hardware-level isolation.
      pattern:
        spec:
          runtimeClassName: "kata-dragonball"
  - name: require-gvisor-for-semi-trusted
    match:
      any:
      - resources:
          kinds:
          - Pod
          namespaces:
          - "semi-trusted-*"
    validate:
      message: >-
        Pods in semi-trusted namespaces must use gvisor
        RuntimeClass.
      pattern:
        spec:
          runtimeClassName: "gvisor"

この設定により、agent-sandbox-*untrusted-*というnamespace名のpodは自動的にKata Containersでの実行が強制されます(Enhancing Kubernetes Security with Kyverno, RuntimeClass, and Kata Containers)。

ハマりポイント:

KyvernoポリシーでRuntimeClassを強制する場合、対象ノードにそのランタイムがインストールされていないとpodがPending状態のまま止まります。RuntimeClassのscheduling.nodeSelectorと、ノードへのランタイムデプロイを必ずセットで管理してください。Helmチャートやkata-deployツールで一元管理するのが確実です。

セキュリティ境界の多層防御

ランタイムの分離だけでは十分ではありません。防御の多層化が必要です。

gVisorを使っている場合でも、seccompプロファイルとNetworkPolicyを併用することで、gVisorのSentryプロセス自体が攻撃された場合のフォールバック防御になります。Kata Containersの場合も同様に、ゲストVM内部でのlateral movementを防ぐためにNetworkPolicyは必須です。

本番運用のトラブルシューティングと最適化

実際に本番環境でセキュアランタイムを運用すると、標準的なrunc環境では発生しない問題に遭遇します。ここでは代表的なトラブルと解決方法を整理します。

よくある問題と解決方法

問題 原因 解決方法
Kata podがPending状態のまま ノードにKata未インストール、またはnodeSelectorの不一致 kubectl describe podでイベント確認、RuntimeClassのnodeSelectorとノードラベルの一致を検証
gVisorで特定のsyscallがブロックされる gVisorが未実装のsyscallをEPERMで返す dmesgでブロックされたsyscall番号を確認し、gVisor互換性リストで対応状況を確認
Kata ContainersでGPUパススルーが動かない DragonballのvGPU非対応 ハイパーバイザをQEMUに変更: handler: kata-qemu
gVisorコンテナのI/O性能が極端に低い ランダムI/Oワークロードでsyscall interceptionオーバーヘッドが支配的 I/O heavyなワークロードはgVisorを避け、Kataまたはruncを使用
Kata podのメモリ使用量が想定より大きい ゲストカーネル+kata-agentの固定オーバーヘッド RuntimeClassのoverhead.podFixedを正しく設定し、スケジューラにオーバーヘッドを認識させる
ノードのメモリが不足する Kata podのオーバーヘッドがスケジューラに認識されていない overhead.podFixed.memoryを設定し、Cluster Autoscalerのメモリバッファを増やす

Kata Containers起動時間の最適化

Kata Containersの起動時間(150-300ms)は、FaaS的なユースケースではボトルネックになることがあります。以下の最適化が有効です。

# /etc/kata-containers/configuration.toml
# 起動時間最適化設定

[hypervisor.dragonball]
# カーネルの軽量化: 不要なモジュールを除外した最小カーネルを使用
kernel = "/usr/share/kata-containers/vmlinux-minimal.container"

# メモリの事前割り当てでページフォールト削減
enable_mem_prealloc = true

# rootfsにinitrdを使用(DAXでメモリマップ、ディスクI/O削減)
image = ""  # ディスクイメージ不使用
initrd = "/usr/share/kata-containers/kata-containers-initrd-minimal.img"

# virtio-fsのキャッシュモード最適化
[hypervisor.dragonball.shared_fs]
shared_fs = "virtio-fs"
# "always" でメタデータキャッシュを有効化(読み取り中心のワークロード向け)
virtio_fs_cache = "always"
virtio_fs_cache_size = 1024

制約条件:

enable_mem_prealloc = trueはメモリの事前割り当てを行うため、起動は速くなりますが、ノード上のメモリ消費が増加します。メモリに余裕がないノードでは、OOMKillerに捕まるリスクがあります。本番環境ではCluster Autoscalerとセットで使い、メモリ不足時にノードが自動スケールアウトする構成にしてください。

gVisorの互換性問題への対処

gVisorはLinuxカーネルのすべてのsyscallを実装しているわけではありません。未実装のsyscallを呼び出すアプリケーションはクラッシュまたは予期しない挙動を示します。

# gVisor のsyscall対応状況を確認
# 実行中のgVisorコンテナ内でstrace相当のデバッグ
kubectl exec -it gvisor-pod -- /usr/bin/runsc debug \
  --log-packets \
  --strace \
  --log-fd=2

# gVisor のバージョン確認(互換性はバージョンで大きく変わる)
runsc --version
# runsc version release-20260701
# spec: 1.2.0

gVisorで動作しないアプリケーションの典型例として、io_uringを使うアプリケーション(一部のデータベース、高性能ネットワーキングライブラリ)があります。gVisorは2026年時点でもio_uringを完全にはサポートしていないため、これらのワークロードはKata Containersまたはruncで実行する必要があります。

パフォーマンスモニタリングの設定

セキュアランタイムのオーバーヘッドを継続的に監視するために、Prometheusメトリクスを設定します。

# PrometheusRule: セキュアランタイムのオーバーヘッド監視
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: sandbox-runtime-alerts
spec:
  groups:
  - name: sandbox-runtime
    rules:
    # Kata pod の起動時間が500msを超えたらアラート
    - alert: KataPodSlowStartup
      expr: |
        histogram_quantile(0.99,
          rate(kubelet_pod_start_duration_seconds_bucket{
            runtime_handler="kata-dragonball"
          }[5m])
        ) > 0.5
      for: 10m
      labels:
        severity: warning
      annotations:
        summary: "Kata pod startup P99 exceeds 500ms"

    # gVisor pod のsyscall拒否率が1%を超えたらアラート
    - alert: GVisorHighSyscallDenial
      expr: |
        rate(runsc_syscalls_denied_total[5m])
        / rate(runsc_syscalls_total[5m]) > 0.01
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "gVisor syscall denial rate exceeds 1%"

まとめと次のステップ

まとめ:

  • CPU・メモリ計算性能はどのランタイムでもほぼ同等(差分2-3%)。ランタイム選定はI/OパターンとHTTPスループット要件で判断する
  • Kata Containers 4.0のRust製runtime-rsとDragonball VMMは、AIエージェントのサンドボックスに適したハードウェア分離を、より低いオーバーヘッドで実現する
  • gVisorはKVM不要でデプロイが容易。シーケンシャルI/Oではruncより高速だが、ランダムI/OとHTTPスループットではオーバーヘッドが大きい
  • Firecrackerは125ms起動・5MBオーバーヘッドでFaaS基盤に適するが、Kubernetesとの直接統合にはKata Containersが必要
  • マルチランタイム設計ではRuntimeClass + Kyvernoポリシーで信頼度に応じた自動ランタイム切り替えを実現する

次にやるべきこと:

  1. 自分のワークロードでベンチマークを実行する。公開データは参考になるが、実際のアプリケーションのI/Oパターンは異なる。container-runtime-benchmarksのForkがそのまま使える
  2. RuntimeClassのoverhead設定を正確に計測・設定する。これを怠るとスケジューラが不正確なリソース配置を行い、OOMやノード過負荷の原因になる
  3. KyvernoポリシーのDry-runモードで既存podへの影響を確認してから、Enforceモードに切り替える

参考


注意: この記事はAI(Claude Code)により自動生成されました。内容の正確性については複数の情報源で検証していますが、実際の利用時は公式ドキュメントもご確認ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?