コンテナランタイムとは?
ますます多くのアプリケーションがコンテナへ移行されるか、あるいは最初からコンテナを念頭に置いて構築される中で、コンテナランタイムとは何か、そして様々な選択肢が自社の技術スタック全体とどのように連携するかを理解することが不可欠です。
コンテナを起動し、マシン上で正常に実行するためには、適切にインストールされ機能するランタイムが必須です。コンテナランタイムは、ホストがEC2インスタンスであるか、ベアメタルサーバーに直接インストールされているか、あるいはIBM zSeriesメインフレーム上のLPAR内のLinuxホスト上で動作しているかといった環境を問いません。コンテナランタイムは、サポート対象のオペレーティングシステム上で特定の機能を活用し、指定されたコンテナイメージを実行するための空間を構築する方法を知っているソフトウェアパッケージです。
コンテナランタイムはどのように動作するのか?
オープンコンテナイニシアチブ(OCI)
OCIはLinux Foundationが支援する組織であり、現代のコンテナランタイムがすべて準拠すべき3つの主要な仕様を管理しております:
- 実際のコンテナイメージ仕様
- コンテナランタイムがコンテナイメージを取得する方法
- イメージの展開、レイヤードマウント、および実行の方法
これらの仕様はすべてDockerの先駆的な取り組みに基づいております。Dockerは、オープンで相互運用可能なエコシステムの価値を認識したため、これらを本イニシアチブに寄贈いたしました。
ランタイムプロセス
OCIランタイム仕様で定義されているコンテナライフサイクルの基本的な手順は以下の通りです:
- コンテナランタイムに対し、コンテナイメージを取得可能な場所への参照と一意の識別子を用いて、新しいコンテナインスタンスの作成が要求されます。
- コンテナランタイムはコンテナイメージの設定を読み取り、検証します。
- 次に、名前空間とマウントポイントが作成され、コンテナイメージのレイヤーを展開・マージする際にクォータが適用されます。これにより、コンテナのファイルシステムが整い、使用可能な状態となります。
- その後、起動が発行されます。これにより、ルートファイルシステムが前段階で作成されたマウントポイントに設定された新しいプロセスが起動します。これにより、コンテナは特定のファイルのみを認識し、指定されたクォータとセキュリティポリシーの範囲内でのみ動作することが可能となります。
- この時点で、実行中のコンテナインスタンスを停止させるために停止コマンドを発行できます。
- 最終的に実行可能なステップはコンテナインスタンスの削除です。これによりコンテナへの参照がすべて削除され、ファイルシステムがクリーンアップされます。
これらの低レベルなコマンドを直接操作することはほとんどありません。通常、ユーザーはオーケストレーションプラットフォーム(Kubernetesなど)や、より使いやすい体験を提供する高レベルなコンテナランタイムを利用します。
コンテナランタイムの種類
低レベルコンテナランタイム
OCIランタイム仕様を実装するコンテナエンジンは、すべて低レベルコンテナランタイムと見なされます。これらはコンテナを実現する基本構成要素であり、コンテナインスタンスの実際の展開、作成、起動、停止を行います:
- runCはDockerによって作成され、OCIに寄贈されました。Linuxホストではほぼ普遍的に使用されるデフォルトのコンテナランタイムです。
- crunはOCI準拠のランタイムであり、極めて小型かつ効率的であることに重点を置いています(バイナリサイズは約300KB)。
- runhcsはMicrosoftが作成したrunCのフォークであり、Windows上でWindowsコンテナを実行するために使用されます。
- containerdは低レベルと高レベルの境界に位置します。実際には、OCI互換ランタイムの上にAPIレイヤーを提供する点で高レベルなコンテナランタイムに近いです。ただし、直接操作することはほとんどないため、ここでは含めます。操作には常に外部レイヤー(nerdctlやctrなどのCLI、Kubernetes上のCRIなど)を介して行います。
高レベルコンテナランタイム
- Dockerはおそらく、主流において最もよく知られているコンテナランタイムプラットフォームでしょう。実際には、開発者の作業を容易にする優れたツール群です。これはcontainerdを基盤としており、実際のコンテナイメージやインスタンスの管理に使用されます。開発者がそのように作業することを好む場合、Dockerにはcontainerdと直接やり取りする代わりにKubernetesと連携できるツールも備わっています。
- Podmanは、Dockerのオリジナル実装よりも安全なモデルを提供するためにRed Hatによって開発されました。Podman(およびBuildah、Skopeo)は、Dockerツールセットと同等の高品質な開発者体験を提供することを目的としています。Dockerとは異なり、Podmanはデーモンを必要とせず、ユーザーがroot権限なしでコンテナを実行することを可能にします。
- CRI-Oは、KubernetesのCRI(Container Runtime Interface)仕様に準拠するよう設計された専用ランタイムです。CRIリクエストを受け取り、OCI準拠のランタイム(runCなど)と通信することが可能です。
コンテナランタイムのランタイムセキュリティ
セキュリティに関連する活動のほとんどは、実際のコンテナランタイムの範囲外で行われます。これらの活動には、セキュアソーシング、スキャン(SAST、IASTなど)、アプリケーションのファジテスト、およびネットワークアクセス制御などのポリシーを適用して入出トラフィックを制御することが含まれます。
実際のランタイムは、Linuxカーネルの機能(cgroupsやネームスペースなど)を活用し、実行中のコンテナに一定の分離レベルを提供します。cgroupsやネームスペースは使用制限という形で保護を提供しますが、すべてのコンテナは同じカーネルを共有しています。これは通常、大きな攻撃対象領域ではありませんが、適切な種類のエクスプロイトが発見されコンテナ内で実行された場合、ホスト上で実行中のすべてのサービスが露出され、さらなる権限昇格につながる可能性があります。
これを制限する方法は2つあります:サンドボックス内でコンテナを実行するか、仮想化フレームワーク内で実行するかです。
- サンドボックス化 – サンドボックス化されたコンテナランタイムは、実行中のコンテナと実際のカーネルの間にプロキシ層を導入し、ワークロードからカーネルへの指示(gVisorのrunscなど)を傍受・監視します。信頼できないワークロードを実行する場合(Googleのパブリッククラウドでの運用など)に最適な選択肢です。
- 仮想化 – 仮想化コンテナランタイムは、最小限の機能に絞った仮想マシン内でコンテナイメージを起動します。Windowsホスト上でLinuxコンテナを実行する場合(Hyper-Vを活用するため)に最も一般的に使用される手法です。このタイプのランタイムの他の著名な例としては、Kata Containersが挙げられます。
コンテナランタイムとKubernetes
Kubernetesは最も広く利用されているコンテナオーケストレーションエンジンです。定義されたAPI(その一つがコンテナランタイムインターフェース(CRI)であり、Kubernetesがコンテナに対してどのような処理をどのように行うかを規定します)を通じて機能を拡張する追加機能を備えた、基盤とエコシステム全体が構築されています。作成、起動、停止、更新、一覧表示といった基本的な管理コマンドを利用します。Docker Desktopのような上位レベルのコンテナランタイムでは、さらに多くの操作が可能です。具体的には、コンテナイメージのビルド、検査、プッシュ、署名などが挙げられます。
CRIインターフェースとOCI仕様の組み合わせにより、Kubernetesクラスターでは基本的にあらゆる準拠ランタイムを使用することが可能です。ContainerdはKubernetesディストリビューションに同梱される最も一般的なランタイムであり、次に広く使用されているのはCRI-Oとなります。
コンテナランタイムの選択方法について
コンテナランタイムの選択は、環境全体を管理するために使用するソフトウェアスイートによって決定される場合がほとんどです。これらの管理およびオーケストレーションソリューション(Kubernetesなど)は特定の仕様を前提としており、必要なコンテナランタイムを自身でインストールするか、前提条件としてリストアップします。
Kubernetesだけでなく、大多数のソリューション(Docker Desktopのような開発者向けツールを含む)はcontainerdに依存しています。例外としては、CRI-Oを利用するRed Hat OpenShiftや、runCのような低レベルコンテナランタイムと直接連携するPodmanが挙げられます。また、containerdが提供できる範囲を超える分離性やセキュリティ上の懸念がある場合には、gVisorやKata Containersといった他のランタイムの検討が必要となるでしょう。