containerd とは?Docker ユーザーのためのコンテナランタイム入門
この記事で分かること
- containerd が解決する問題
- コンテナランタイムの分類(高レベル/低レベル)
- Docker と containerd の関係
- containerd のアーキテクチャ
- Kubernetes が containerd を使う仕組み(CRI)
Docker を使っていると、「containerd」という名前を見かけることがあります。docker info を実行すると containerd のバージョンが表示されますし、Kubernetes のドキュメントでも「コンテナランタイムとして containerd を使用」といった記述が出てきます。
この記事では、Docker ユーザーの視点から、containerd とは何か、なぜ存在するのかを解説します。
なぜ containerd を知る必要があるのか
Docker だけ知っていれば十分?
ローカル開発で Docker を使うだけなら、containerd を意識する必要はありません。しかし、以下のような場面では containerd の理解が役立ちます。
- Kubernetes を運用する: Kubernetes v1.24 以降、Docker(dockershim)のサポートが削除され、containerd や CRI-O といったランタイムを直接使用するようになりました
- コンテナのトラブルシューティング:「コンテナが起動しない」「イメージが pull できない」といった問題の原因が Docker 層ではなく containerd 層にあることがある
- 軽量なコンテナ環境を構築する: CI/CD 環境や組み込みシステムでは、Docker デーモンなしで containerd を直接使うケースがある
コンテナ技術のレイヤー構造
containerd を理解するには、コンテナ技術がどのようなレイヤーで構成されているかを知る必要があります。

Docker は「コンテナを便利に使うためのツール群」であり、その内部で containerd と runc を使っています。
コンテナランタイムとは
「コンテナランタイム」という用語は文脈によって指すものが異なります。混乱を避けるため、高レベルと低レベルに分けて整理します。
高レベルランタイム(コンテナマネージャー)
イメージの管理、コンテナのライフサイクル管理、ネットワーク設定などを担当します。
- containerd: Docker 社が開発し、CNCF に寄贈。現在広く使われている
- CRI-O: Red Hat 主導で開発。Kubernetes 専用に設計されている
- Podman: Red Hat が開発するコンテナエンジン。Docker 互換の CLI を持ち、デーモンレスで動作。CRI は実装しておらず、主にローカル開発やスタンドアロン環境向け
低レベルランタイム(OCI ランタイム)
実際にコンテナを作成・起動する処理を担当します。Linux カーネルの機能(namespace、cgroup)を使ってプロセスを隔離します。
- runc: Docker 社が開発し、OCI に寄贈。containerd のデフォルトランタイム
- crun: Red Hat が開発。C 言語で書かれ、runc より高速
- gVisor (runsc): Google が開発。ユーザー空間で動作する独自カーネルがシステムコールを処理し、ホスト OS への攻撃面を削減
- Kata Containers: 軽量 VM 内でコンテナを実行してセキュリティを強化
高レベルランタイムは、低レベルランタイムを呼び出してコンテナを起動します。containerd はデフォルトで runc を使いますが、設定で他のランタイムに切り替えることも可能です。
Docker と containerd の関係
Docker の歴史と containerd の誕生
Docker は当初、コンテナの起動からイメージ管理、ネットワークまですべてを 1 つのモノリシックなデーモンで処理していました。
しかし、この設計には課題がありました。
- 再起動の影響: 旧設計では Docker デーモンを再起動すると、実行中のコンテナも停止してしまう
- 拡張性: 他のツール(Kubernetes など)が Docker の機能の一部だけを使いたくても、全体を組み込む必要がある
- 標準化: コンテナ技術がエコシステムとして成長するには、特定企業の実装に依存しない標準が必要
これらの課題を解決するため、Docker 社は 2016 年にコンテナのコア機能を containerd として切り出し、2017 年に CNCF(Cloud Native Computing Foundation)に寄贈しました。
現在の Docker アーキテクチャ
現在の Docker は以下のように動作します。

- ユーザーが
docker runを実行 - Docker CLI が Docker デーモン(dockerd)に API リクエストを送信
- dockerd が containerd にコンテナ作成を依頼
- containerd が runc を呼び出してコンテナを起動
- runc はコンテナを起動した後、終了する(常駐しない)
- containerd の shim プロセスがコンテナの親プロセスとして残る
このアーキテクチャにより、shim が生きている限り、containerd を再起動しても実行中のコンテナは概ね影響を受けません(shim が独立して動作するため)。
Docker なしで containerd を使う
containerd は Docker なしでも使えます。containerd に付属する ctr コマンドや、Docker 互換の CLI を持つ nerdctl を使います。
# ctr でイメージを pull してコンテナを実行
ctr image pull docker.io/library/nginx:latest
ctr run -d docker.io/library/nginx:latest my-nginx
# nerdctl(Docker 互換の使い勝手)
nerdctl run -d --name my-nginx nginx:latest
nerdctl は containerd/nerdctl で開発されており、docker コマンドとほぼ同じ使い方ができます。Docker Compose 互換の nerdctl compose も提供されています。
containerd のアーキテクチャ
containerd は以下のコンポーネントで構成されています。

コアサービス
- Content Store: イメージのレイヤー(blob)を保存
- Metadata Store: コンテナやイメージのメタデータを BoltDB で管理
- Snapshotter: コンテナのファイルシステムを管理。overlayfs や btrfs などのバックエンドをサポート
- Task Service: コンテナのライフサイクル(作成、開始、停止)を管理
shim(シム)
containerd と低レベルランタイム(runc など)の間に位置するプロセスです。
shim の主な役割は以下の通りです。
- プロセスの親として動作: コンテナプロセスの親となり、containerd が再起動してもコンテナは動き続ける
- stdio の中継: コンテナの標準入出力を containerd に中継
- 終了ステータスの報告: コンテナ終了時に終了コードを containerd に報告
shim があることで、containerd のアップグレードやクラッシュがコンテナに影響しない設計になっています。
プラグインアーキテクチャ
containerd はプラグインベースで設計されています。ほぼすべての機能がプラグインとして実装されており、必要に応じて拡張や置き換えが可能です。
# containerd のプラグイン一覧を確認
ctr plugins ls
Kubernetes と containerd
CRI(Container Runtime Interface)
Kubernetes はコンテナランタイムを直接呼び出すのではなく、CRI という標準インターフェースを通じて操作します。

kubelet が CRI 経由で containerd に指示を出し、containerd が実際のコンテナ操作を行います。
※ shim の単位は runtime 実装や設定で変わります。本図は io.containerd.runc.v2(Kubernetes + containerd)で Pod 単位になるケースを示しています。
なぜ Docker ではなく containerd を使うのか
Kubernetes v1.20 で「Docker サポートの非推奨」がアナウンスされ、v1.24 で dockershim(Docker を CRI 経由で呼び出すためのアダプター)が削除されました。
ただし、Docker Engine を使い続けたい場合は cri-dockerd を介して利用できます。
この背景には以下の理由があります。
- オーバーヘッドの削減: kubelet → dockershim → dockerd → containerd という経路が、kubelet → containerd に短縮される
- メンテナンスの簡素化: dockershim のコードを Kubernetes 本体から削除できる
- 機能の重複: Kubernetes は Docker のイメージビルド機能やネットワーク管理機能を使わない
ただし、Docker でビルドしたイメージは引き続き使える ことは重要なポイントです。Docker イメージは OCI(Open Container Initiative)の標準と互換であり、containerd や CRI-O でもそのまま実行できます。
crictl コマンド
Kubernetes 環境で containerd を操作するには、crictl コマンドを使います。
使用前にランタイムのエンドポイントを設定しておくとスムーズです。
# /etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
# Pod の一覧を表示
crictl pods
# コンテナの一覧を表示
crictl ps
# イメージの一覧を表示
crictl images
# コンテナのログを表示
crictl logs <container-id>
crictl は CRI 互換のランタイムすべてで使えるため、containerd でも CRI-O でも同じコマンドで操作できます。
まとめ
- containerd は、Docker の内部で使われているコンテナランタイム。CNCF プロジェクトとして独立している
- コンテナランタイムには高レベル(containerd、CRI-O)と低レベル(runc)の区分がある
- Docker は containerd を呼び出し、containerd は runc を呼び出してコンテナを起動する
- Kubernetes v1.24 以降は containerd を直接使用する(Docker を経由しない)
- Docker でビルドしたイメージは、OCI 標準と互換であるため containerd でもそのまま使える
- shim プロセスにより、containerd の再起動がコンテナに影響しない設計になっている
参考
- containerd 公式サイト
- containerd/containerd – GitHub
- containerd/nerdctl – GitHub
- Open Container Initiative
- Kubernetes – Container Runtimes
- Don’t Panic: Kubernetes and Docker
- CRI: the Container Runtime Interface
- containerd: CRI Plugin Config Guide
- containerd: PLUGINS.md
- Docker Engine: Alternative Runtimes
- Docker Image Specification
- Podman Documentation
- Kubernetes 1.24: Dockershim Removal