コンテナ分離およびランタイム技術(Container Isolation & Runtime)
1. 概要
A. 定義
コンテナ分離およびランタイム技術とは、Linuxカーネルの名前空間(namespace)・コントロールグループ(cgroups)・権限縮小(capabilities)・システムコールフィルタリング(seccomp)などのOSレベルの分離機能を組み合わせ、一つのカーネル上で複数のプロセスを互いに独立した実行環境のように見せ、これをOCI(Open Container Initiative)標準に従って生成・実行・終了するソフトウェア層(ランタイム)をいう。
ハイパーバイザ型の仮想マシンがハードウェアを仮想化してゲストOSごとに別個のカーネルを載せるのとは異なり、コンテナはホストカーネルを共有しながらプロセスレベルでのみ分離する。 したがって起動過程がなく数百MBのゲストOSイメージも不要であり、数十ミリ秒単位で起動し、一つのノードで数百〜数千個を密に配置できる。 しかしカーネルを共有するという事実は、すなわち「分離の強度がカーネル機能の正確性と設定品質に依存する」ことを意味し、これがコンテナセキュリティとランタイム設計の出発点である。
B. 登場背景と必要性
第一に、仮想マシンはアプリケーション一つを分離するためにOS全体を複製する方式であり、資源効率とデプロイ速度が低かった。 マイクロサービスのように小さなサービスを数十〜数百個に分割してデプロイする流れでは、サービスごとに数GBのVMを起動する費用が耐え難かった。 コンテナは「アプリケーションとその依存関係のみをパッケージング」する軽量単位を提供してこの問題を解決した。
第二に、「自分のノートPCでは動くのに運用では動かない」という環境不一致の問題が深刻であった。
コンテナイメージはライブラリ・ランタイム・設定を一つの不変(immutable)アーティファクトに固定するため、開発・テスト・運用環境間の再現性を保証する。
この再現性は、CI/CD自動化、すなわち[[ci-cd-pipeline]]・[[gitops]]の前提条件となった。
第三に、2013年にDockerがLinuxカーネル機能を扱いやすいCLIとイメージフォーマットでまとめて大衆化し、2015年にOCIが発足してイメージフォーマット・ランタイム・配布規格を標準化したことで、特定ベンダに依存しない生態系が形成された。
これによりDocker、containerd、CRI-O、Podmanなどの複数実装が相互互換となり、[[kubernetes]]がCRI(Container Runtime Interface)を通じてランタイムを交換可能に扱えるようになった。
C. 特徴
コンテナ分離は(1)共有カーネル — 性能・密度の源泉であると同時にセキュリティ境界の弱点、(2)宣言的な不変イメージ — 再現性と供給網の追跡可能性の基盤、(3)標準ベースの交換可能性 — OCI/CRIを通じたベンダ中立性、という三つの特徴を同時に持つ。 この三つの均衡点がどこかによって、純粋なコンテナからサンドボックスランタイム、軽量VMまで多様な分離水準が選択される。
2. コンテナ分離の中核構成要素
コンテナは単一の技術ではなく、複数のカーネル機能の組み合わせである。まず全体構造を俯瞰した後、各要素の原理を説明する。
graph TD
subgraph Host["ホスト (単一の共有カーネル)"]
K["Linuxカーネル"]
subgraph C1["コンテナ A"]
P1["アプリケーションプロセス"]
end
subgraph C2["コンテナ B"]
P2["アプリケーションプロセス"]
end
end
K -->|"名前空間 (何を見られるか)"| C1
K -->|"名前空間 (何を見られるか)"| C2
K -->|"cgroups (どれだけ使えるか)"| C1
K -->|"cgroups (どれだけ使えるか)"| C2
K -->|"capabilities・seccomp・LSM (何ができるか)"| C1
K -->|"capabilities・seccomp・LSM (何ができるか)"| C2
A. 名前空間(Namespace) — 可視性の分離
名前空間は「プロセスが何を見られるか」を分割する機能である。 PID名前空間はコンテナ内部のプロセスが自らをPID 1と認識させ、ホストの他のプロセスを見られないようにする。 NET名前空間は独立したネットワークスタック(インタフェース・ルーティングテーブル・ファイアウォール規則)を提供するため、コンテナごとに自前のIPとポート空間を持てる。 このほかMNT(ファイルシステムマウント)、IPC(共有メモリ・セマフォ)、UTS(ホスト名)、USER(ユーザ・グループIDマッピング)、CGROUP、TIME名前空間があり、2024年時点でカーネルに計8種が存在する。
とりわけUSER名前空間はセキュリティ上の中核である。コンテナ内部のroot(UID 0)をホストの非特権ユーザ(例:UID 100000)にマッピングすれば、コンテナ脱出が発生してもホストでは一般ユーザ権限のみを得ることになり、被害を大きく減らす。 これが後述するルートレス(rootless)コンテナの基盤である。
B. コントロールグループ(cgroups) — 資源の分離
cgroupsは「プロセス群が資源をどれだけ使えるか」を制限・測定する。 CPUクォータ(例:0.5 vCPU)、メモリ上限(例:512MiB)、ブロックI/O帯域、PID個数などを制御し、あるコンテナの暴走がノード全体を麻痺させるノイジーネイバー(noisy neighbor) 問題を防ぐ。 たとえばメモリ上限を超過するとOOM Killerが当該コンテナのプロセスを終了させ、他のワークロードを保護する。
現在は階層構造が単純化され資源種別を統合管理するcgroups v2が標準である。 systemdと結合して単一の統合階層として動作し、Kubernetes 1.25からv2が正式(GA)にサポートされ、メモリ圧迫信号(PSI, Pressure Stall Information)に基づく精密な負荷制御が可能となった。
C. 権限縮小・システムコールフィルタリング — 行為の分離
capabilitiesは従来「全部か無か」であったroot権限を約40余りの細分化された権限に分ける。
コンテナランタイムは基本的にCAP_NET_RAW、CAP_SYS_ADMINなどの危険な権限を除去した最小集合のみを付与する。
seccomp(secure computing)はBPFフィルタでプロセスが呼び出せるシステムコールをホワイトリストで制限し、カーネル攻撃面を減らす — Dockerの既定プロファイルは約300余りのうち44個の危険なシステムコールを遮断する。
ここにSELinux・AppArmorのようなLSM(Linux Security Module)でファイル・ネットワークアクセスを強制アクセス制御の水準で統制すれば、名前空間が破られても第二の防御線が作動する。
| 区分 | 統制の問い | 主な機能 | 分離失敗時の影響 |
|---|---|---|---|
| 名前空間 | 何を見るか | PID・NET・MNT・USERなど8種 | 他コンテナ・ホスト資源の露出 |
| cgroups | どれだけ使うか | CPU・メモリ・I/O・PID上限 | 資源枯渇・サービス拒否 |
| capabilities | 何をするか | root権限の細分化 | 権限昇格・ホスト掌握 |
| seccomp/LSM | カーネルをどう呼ぶか | システムコール・MAC制限 | カーネル脆弱性の悪用・脱出 |
表が示すように三つの範疇は異なる問いに答え、多層防御(defense in depth) として共に作動せねばならない。 いずれか一つのみでは完全な分離が成立しないという点が、コンテナセキュリティ設計の核心的含意である。
3. コンテナランタイムのアーキテクチャと実行手順
ランタイムは役割に応じて高水準ランタイム(イメージ管理・ネットワーク・ストレージのオーケストレーション)と低水準ランタイム(名前空間・cgroupsを実際に設定してプロセスを起動するOCIランタイム)に分かれる。 KubernetesがPodを起動する際の呼び出しの流れを通じて、この階層を説明する。
sequenceDiagram
participant K as kubelet
participant HL as containerd / CRI-O (高水準)
participant S as containerd-shim
participant LL as runc / crun (低水準OCI)
participant KN as Linuxカーネル
K->>HL: CRI gRPC呼び出し (RunPodSandbox/CreateContainer)
HL->>HL: OCIイメージのPull・展開・rootfs構成
HL->>S: shimプロセス生成 (コンテナ寿命の分離)
S->>LL: OCIバンドル(config.json + rootfs)を渡す
LL->>KN: clone() + 名前空間・cgroups・capabilities設定
KN-->>LL: 分離されたPID 1プロセス起動
LL-->>S: 実行結果を返して終了
S-->>HL: コンテナ状態を報告 (shimが常駐)
A. 高水準ランタイムとCRI
特定のランタイムに依存しないよう、kubeletはCRI(Container Runtime Interface) というgRPC標準で通信する。
2020年にKubernetesがDocker専用の接続層(dockershim)を廃止(1.24で除去)したことで、現在はcontainerdとCRI-Oが事実上の標準高水準ランタイムである。
高水準ランタイムはイメージレジストリからOCIイメージを取得して層(layer)を合わせ、ネットワーク(CNI)・ストレージ(CSI)を接続した後、OCIバンドル(rootfs + config.json)を作る。
B. shimと低水準OCIランタイム
containerd-shimはコンテナプロセスの親の役割を常駐して引き受け、containerdデーモンを再起動しても実行中のコンテナが死なないように寿命周期を分離する。
実際の分離設定は低水準ランタイムであるrunc(Go)が行う。runcはclone()/unshare()システムコールで名前空間を作り、cgroups・capabilities・seccompを適用した後、ユーザプロセスをexecする。
最近はCで記述してメモリ使用と起動遅延を減らしたcrun、Rustで記述したyoukiなどOCI互換の代替ランタイムが登場し、高密度・低遅延環境で採用が増えている。
C. イメージと供給網
実行手順の再現性はOCIイメージ仕様(コンテンツアドレス指定の層 + マニフェスト)に基づく。
同一ダイジェスト(SHA-256)のイメージはどこでも同一であるため、イメージ署名・[[sbom]]・脆弱性スキャンを結合すればソフトウェア供給網の無欠性を検証できる。
すなわちランタイムは「分離された実行」だけでなく「検証されたアーティファクトの実行」まで責任を負う方向に拡張されている。
4. 分離強化・サンドボックスランタイムの比較
共有カーネルの限界を補うため、分離強度を高めたランタイムが登場した。単なる列挙ではなく、なぜそのような選択をしたかを中心に比較する。
| 方式 | 分離境界 | カーネル共有 | 起動速度 | 密度・効率 | 代表的適用 |
|---|---|---|---|---|---|
| 標準コンテナ(runc) | 名前空間/cgroups | ホストカーネルを直接共有 | 非常に速い(数十ms) | 最高 | 一般マイクロサービス |
| gVisor(runsc) | ユーザ空間のゲストカーネル | システムコールの横取り | 速い | 高い | マルチテナントPaaS |
| Kata Containers | 軽量VM(ハードウェア) | ゲストカーネル分離 | 中間(数百ms) | 中間 | 信頼境界の異なるテナント |
| Firecracker microVM | microVM(ハードウェア) | ゲストカーネル分離 | 速い(~125ms) | 高い | サーバレス(FaaS) |
gVisorはGoogleが公開した方式で、コンテナのシステムコールをユーザ空間で動作する独自のゲストカーネル(Sentry)が横取りして処理する。 ホストカーネルに直接触れるシステムコール面を劇的に減らし、カーネル脆弱性を通じた脱出の危険を低くする。 ただしシステムコールを中継するため、I/O集約型ワークロードでは性能低下が発生するトレードオフがある — このため信頼の低いコードを分離実行するマルチテナント環境に適する。
Kata Containersは各PodをQEMU・Cloud Hypervisorのようなハイパーバイザ上の軽量VMで包み、ハードウェア水準のカーネル分離を提供する。
標準のコンテナインタフェース(OCI/CRI)をそのまま維持するため、アプリケーションを修正せずruntimeClassNameだけ変えてより強い分離を選べる。
[[confidential-containers]]はここにTEEメモリ暗号化を結合した拡張であり、これはKataベースの軽量VM分離が機密コンピューティングの土台となることを示す。
FirecrackerはAWSがLambda・Fargateのために作ったmicroVMで、起動を約125ms以内に終え、VMあたりのメモリオーバーヘッドを約5MiB水準に下げ、単一ホストで数千個の分離された関数インスタンスを密に実行する。 VMの強い分離とコンテナの速い起動を結合した事例であり、「分離強度と性能は必ず相反する」という通念を攻撃面最小化設計で緩和した実務例である。
5. 深化:最新動向と実務適用
A. ルートレス(Rootless)コンテナの拡散
従来、コンテナデーモンはrootで動作し、デーモンが奪取されるとホストが丸ごと危険であった。 USER名前空間を活用したルートレス方式はデーモン・ランタイムを非特権ユーザで実行し、コンテナ内部のrootをホストの一般ユーザにマッピングする。 Podmanはデーモンのない(daemonless)ルートレス構造を既定で採択し、Kubernetesもルートレスkubeletを実験的に支援しながら、「最小権限」原則がランタイムの既定値へ移動している。
B. Wasmランタイムとの結合
WebAssembly([[webassembly]])をコンテナ生態系に編入しようとする流れも明確である。
containerdのrunwasi shimを使えば、WasmモジュールをOCIイメージで包んでPodのようにデプロイできる。
Wasmは起動がミリ秒未満で非常に速く、メモリ分離が言語水準で保証されるため、サーバレス・エッジ([[edge-computing]])の極低遅延ワークロードで軽量コンテナの補完材として注目される。
C. カーネル水準の可視性・セキュリティ — eBPF
[[ebpf]]ベースのツール(Cilium、Falco、Tetragon)はコンテナのシステムコール・ネットワーク流れをカーネルで直接観測・強制し、ランタイム脅威検知とネットワークポリシ適用を行う。
たとえば金融圏では、コンテナランタイムに対する異常行為(予期せぬシェル実行、権限昇格の試み)をeBPFで検知してランタイムセキュリティ([[rasp]]に類似したワークロード自己保護)を実現する事例が増えている。
これは分離が「静的設定」から「動的検知・対応」へ拡張されていることを示す。
6. 考慮事項および示唆点
技術士の観点では、コンテナ分離・ランタイムの導入は次を総合的に判断せねばならない。
- 分離水準と性能のトレードオフ設計:すべてのワークロードにVM級の分離を適用すれば費用・性能が悪化する。信頼境界(同一組織内部 vs 外部テナントコード)を基準に、低信頼ワークロードにのみgVisor・Kataを選択的に適用する
runtimeClassNameベースの階層的分離戦略が現実的である。 - 最小権限の既定値化:capabilities除去、seccomp・AppArmorプロファイルの強制、ルートレス・読み取り専用ルートファイルシステム、USER名前空間マッピングを既定ポリシとすべきである。
[[kubernetes-pod-security-standards]]のRestrictedプロファイルをアドミッション段階で強制して設定漏れを防ぐ。 - 供給網の信頼まで含む統制:分離された実行のみでは悪性・脆弱なイメージを防げない。イメージ署名検証、
[[sbom]]生成、脆弱性スキャン、レジストリアクセス制御をCI/CDと[[policy-as-code]]で結び、「検証されたアーティファクトのみ実行」を強制すべきである。 - 可視性とランタイム脅威対応の連携:静的な分離設定とともに、eBPFベースのランタイム検知(
[[edr]]・Falco)、中央ログ・[[observability]]を結合し、分離が破られる瞬間を早期に検知・対応する体系を備えるべきである。 - 標準・ベンダ中立性の確保:OCI/CRI標準を遵守するランタイムを選んで特定ベンダへの依存を避け、dockershim除去の事例のように生態系の変化に備えた交換可能なアーキテクチャを維持する。
総合すると、コンテナ分離は単一機能ではなく、カーネル分離要素・ランタイム層・供給網・可視性が結合した信頼実行体系であり、技術士はセキュリティ・性能・運用効率の均衡点を組織の信頼モデルに合わせて設計する力量を要求される。
参考資料
- Open Container Initiative, "Runtime/Image/Distribution Specifications", https://opencontainers.org/
- Kubernetes Documentation, "Container Runtime Interface (CRI)", https://kubernetes.io/docs/concepts/architecture/cri/
- Linux man-pages, "namespaces(7) / cgroups(7) / capabilities(7) / seccomp(2)", https://man7.org/linux/man-pages/man7/namespaces.7.html
- AWS, "Firecracker: Lightweight Virtualization for Serverless Applications", https://firecracker-microvm.github.io/
- gVisor Documentation, "What is gVisor?", https://gvisor.dev/docs/
一言まとめ: コンテナ分離・ランタイムはLinuxの名前空間(可視性)・cgroups(資源)・capabilities/seccomp(行為)で共有カーネル上のプロセスを分離し、OCI/CRI標準ランタイム(containerd→runc)で実行する技術であり、共有カーネルのセキュリティ限界をgVisor・Kata・Firecrackerなどのサンドボックス・軽量VMとルートレス・eBPF観測で補い、分離強度と性能の均衡を設計する信頼実行体系である。