
runc(ランシー)は、OCI(Open Container Initiative)の実行時仕様を直接実装したCLIコンテナランタイムです。2015年6月のOCI設立と同時にDocker社がlibcontainerを寄贈する形で誕生し、Linuxカーネルのnamespacesとcgroups、capabilitiesなどを直接操作してコンテナプロセスを起動・終了するという、コンテナ実行スタックの最下層を担います。containerd、CRI-O、Podman、Dockerなど主要なコンテナエンジンはいずれも内部でruncを呼び出しており、現代のLinuxコンテナの大半がruncによって実際に起動されています。
この記事の目次
- namespaces・cgroups・capabilities
- libcontainerからOCIへの変遷
- 上位ランタイムから見たruncの役割
- 代替ランタイムとの比較
- まとめ
namespaces・cgroups・capabilities

runcの責任は「OCI Runtime Specに書かれた手順通りにLinuxプロセスをコンテナとして起動する」ことに尽きます。そのために操作するLinuxカーネル機能が、namespaces、cgroups、capabilitiesの3つです。namespaces(PID、Network、Mount、UTS、IPC、User、Cgroup)はプロセスから見える資源を隔離する仕組みで、runcはこれらを組み合わせて「他のプロセスから独立した仮想的なOS環境」を作り出します。
cgroups(v1/v2)はCPU、メモリ、ディスクI/O、PID数などの資源使用量に上限を設けるカーネル機能で、runcはspec.json(実行時設定ファイル)の指示に沿って各cgroupサブシステムへの書き込みを行います。capabilitiesはroot権限を機能単位に細分化したもので、runcはコンテナプロセスに与える権限を最小限に絞ります。seccomp、AppArmor、SELinuxなどのLSMもspec.jsonから設定可能で、runcはこれらの統合点としてLinuxセキュリティ機構の入口を担っています。
libcontainerからOCIへの変遷

runcの祖先はDocker社が2013年に開発したGoライブラリ「libcontainer」です。それ以前のDockerはLXC(Linux Containers)を呼び出してコンテナを起動していましたが、Docker独自の要件に応じてカーネル機能を直接叩く実装としてlibcontainerが生まれ、Docker 0.9(2014年)で既定実行エンジンとなりました。2015年6月、Linux Foundation傘下のOpen Container Initiative(OCI)が設立された際、Docker社はlibcontainerをOCI仕様の参照実装として寄贈しました。
このときコマンドラインインターフェースを備えた形に整えられたのがruncです。2017年7月のOCI Runtime Spec 1.0公開と歩調を合わせ、runc 1.0.0-rc系がリリースされ、長らくRC状態のまま実運用に投入される期間が続きました。2021年6月にようやくruncの「真の」1.0.0が公開され、API・CLIの安定保証が約束されました。現在は半年〜1年に一度のペースでメンテナンスリリースが続き、CVE対応とcgroups v2対応の改善が中心テーマとなっています。
上位ランタイムから見たruncの役割

runcは単独で使うこともできますが、実運用ではcontainerd、CRI-O、Podmanなどの高レベルランタイムから呼び出されます。例えばKubernetesの典型構成では、kubeletがcontainerdにgRPCで指示を出し、containerdがOCI Runtime Spec準拠のspec.jsonを生成し、containerd-shim(軽量な常駐プロセス)がrunc createとrunc startを呼び出してコンテナを起動します。runc自身はコンテナ起動後すぐに退場し、アプリプロセスはshimプロセスにぶら下がる構造となり、ノード再起動時の影響範囲を最小化しています。
障害解析の場面では、runcが残すstate.jsonやログ、runc listコマンドが直接の調査対象になります。コンテナが起動できない場合、原因はnamespacesの作成失敗、cgroupsの権限不足、seccompルールの構文ミス、ボリュームマウントの整合性エラーなど多岐にわたりますが、そのいずれもがruncのエラー出力に痕跡を残します。「Dockerが動かない」「Podがハングする」といった事象を深掘りすると、最終的にruncのバージョンや設定差分にたどり着くケースは少なくありません。
代替ランタイムとの比較

OCI仕様は実装中立なので、runc以外の低レベルランタイムも複数存在します。代表例がRed Hatのジョバンニ・ベルナルディが2018年頃から開発したcrunで、C言語で実装されているため起動が速くメモリも少なく、cgroups v2対応も先行しました。Kata Containersはコンテナごとに軽量なKVM仮想マシンを起動して強い分離を提供し、機密性の高いマルチテナント環境で採用されています。gVisorはGoogleが開発したユーザー空間Linuxカーネル実装で、システムコールをサンドボックス越しに処理して攻撃面を縮小します。youkiはRust実装の低レベルランタイムで、メモリ安全性と性能のバランスを狙ったプロジェクトです。
とはいえ、現実のサーバの大多数では依然としてruncが既定であり、互換性と安定性、ドキュメントの厚さで他を圧倒します。OCI仕様の参照実装という立場上、新しい機能はruncで最初に検証され、その後crunや他実装に波及するという順序が定着しています。「コンテナの中身がどう動いているのか」を理解しようとすると、最終的にはruncのソースコードに行き着くと言われるほど、エコシステムの中心に位置するツールです。
まとめ
runcはDocker社が2015年にOCIへ寄贈した低レベルコンテナランタイムで、Linuxのnamespaces・cgroups・capabilitiesを直接操作してコンテナを起動します。containerd、CRI-O、Podman、Dockerすべての内部エンジンとして使われており、現代のLinuxコンテナのほぼすべてがruncによって動かされています。上位ランタイムの陰に隠れがちですが、トラブルシュートで最終的に向き合うのはこのレイヤーであり、コンテナ技術を深く理解する上で必須の知識となります。
※本記事はIT用語辞典の手書きドラフトです。公開前に最新情報・出典を確認のうえ加筆修正してください。

コメント