CLOVER🍀

That was when it all began.

Docker Daemonのストレージバックエンドがcontainerdになっていたという話(29.0以降)

これは、なにをしたくて書いたもの?

前にDockerのストレージについて見てみました。

Dockerのストレージ(コンテナデータの永続性)について学ぶ(Volumes、Bind mounts、tmpfs mounts) - CLOVER🍀

この時、Docker Daemonのストレージバックエンドについては扱いませんでした。今回はここを少しだけ見ておこうと
思います。
主にDocker Engine 29.0以降ではデフォルトのストレージバックエンドがcontainerdイメージストアになっていた
という話です。

Docker Daemonのストレージバックエンド

Docker Daemonのストレージバックエンドは、ここで少しだけ触れられています。

Storage | Docker Docs

これらは、Dockerがコンテナイメージとコンテナレイヤーを保存する方法に関するものです。そして次の2つが
挙げられています。

  • containerdイメージストア
  • ストレージドライバー

containerdイメージストアという言葉に馴染みがなかったので、今回見てみようと思ったのがこのエントリーを
書き始めた動機です。

containerdイメージストア

containerdイメージストアのドキュメントはこちら。

containerd image store | Docker Docs

containerdイメージストアは、Docker Engine 29.0以降の新規インストールにおけるデフォルトの
ストレージバックエンドです。

The containerd image store is the default storage backend for Docker Engine 29.0 and later on fresh installations.

以前のバージョンからのアップグレードの場合は、引き続きレガシーなグラフドライバー(overlay2)が
使われ続けるとされています。

If you upgraded from an earlier version, your daemon continues using the legacy graph drivers (overlay2) until you enable the containerd image store.

overlay2がレガシー扱いということを知りませんでした…。

ちなみにDocker Engine 29.0のリリースがいつかというと、2025年11月10日なのでごくごく最近の話ですね。

Docker Engine version 29 release notes / 29.0.0

今回、containerd自体については深追いしないので、かなり薄いエントリーになります…。

containerdイメージストアを使うことで、コンテナイメージとコンテナデータはスナップショットを使用した保存
およびアクセス方法になるようです。

containerdイメージストアにより以下のことができるようになるとか。

  • マルチプラットフォームイメージをローカルでビルド、保存可能
  • ProvenanceやSBOMを含むコンテナイメージの操作ができるようになる
    • 従来のストアではサポートしていないイメージインデックスを使用するため
  • WebAssemblyワークロードをサポートしているため、Wasmコンテナを実行できる
  • イメージの遅延Pull(stargz)、Peer-to-Peerのイメージ配布(nydus、dragonfly)などの機能を提供するプラガブルなスナップショットツールのサポート

containerd image store with Docker Engine / Why use the containerd image store

ちなみにディスク使用量は増加するようです。

containerd image store with Docker Engine / Disk space usage

これはなぜかというと、containerdはイメージを圧縮形式と非圧縮形式の両方を保存するのに対して、レガシーな
ストレージドライバーは非圧縮レイヤーのみを保存していたからです。

The containerd image store uses more disk space than the legacy storage drivers for the same images. This is because containerd stores images in both compressed and uncompressed formats, while the legacy drivers stored only the uncompressed layers.

つまり、containerdイメージストアでは二重にデータを持っていることになります。圧縮形式の利点はPullとPushの
高速化になるようですね。

containerdイメージストアが圧縮形式と非圧縮形式の両方を持つというのは、複数のイメージが同じベースイメージを
共有する場合に特に顕著に違いとして現れるようです。
従来のストレージドライバーでは共有されるベースレイヤーは1度ローカルに保存されると再利用されていたのに
対して、containerdでは非圧縮レイヤーはスナップショットにより重複排除されるものの圧縮レイヤーについては
各イメージが個別に保存する振る舞いになるようです。

つまり、同じベースイメージを共有するイメージが増えるとオーバーヘッドが追加されていくことを意味します。

containerdイメージストアを有効にするには、/etc/docker/daemon.jsonに以下のように設定して

{
  "features": {
    "containerd-snapshotter": true
  }
}

Docker Daemonを再起動します。

$ sudo systemctl restart docker

containerd image store with Docker Engine / Enable containerd image store on Docker Engine

docker infoで見た時に、Storage Driverが「overlayfs」、driver-typeが「io.containerd.snapshotter.v1」
となっていればcontainerdイメージストアが有効になっています。

$ docker info | grep -E 'Storage Driver|driver-type'
 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1


$ docker info -f '{{ .Driver}} {{ .DriverStatus }}'
overlayfs [[driver-type io.containerd.snapshotter.v1]]

従来のストレージドライバーからの実験的な自動移行機能もあるようですが、推奨としては最初から構築しなおすことに
なっているようです。

containerd image store with Docker Engine / Experimental automatic migration

ストレージドライバー

従来のストレージドライバーについてのドキュメントはこちら。

Storage drivers | Docker Docs

ストレージドライバーはイメージレイヤーの保存と、コンテナの書き込み可能なレイヤーにデータを保存する際に
使われます。

Storage drivers / Storage drivers versus Docker volumes

コンテナの書き込み可能なレイヤーはコンテナが終了すると破棄されます。

ストレージドライバーはスペース効率に最適化されているとされていますが、選択したストレージドライバーによっては
書き込み速度がネイティブファイルシステムのパフォーマンスよりも悪くなります。特にコピーオンライトを
使用するストレージドライバーの場合は顕著になるようです。

よって、書き込み負荷が高いデータやコンテナが終了しても保持する必要があるデータ、コンテナ間で共有する
必要があるデータについてはボリュームを使用することになります。

こちらでは、Dockerfileでのファイルシステムを変更するコマンドはレイヤーを作成することが書かれています。
FROMでレイヤーが作成され、COPYRUNで変更されていきます。

Storage drivers / Images and layers

LABELCMDはイメージのメタデータのみを変更するため、レイヤーは作成されません。

こちらはイメージとコンテナの違いで、コンテナには最上位に書き込み可能なレイヤーが存在することが
挙げられます。

Storage drivers / Container and layers

イメージを構成するレイヤーの数を把握するには、以下のコマンドを実行するとよさそうです。

$ docker image inspect --format "{{json .RootFS.Layers}}" [イメージ名] | jq

こういう感じになります。

[
  "sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
  "sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a"
]

また以下のようにdocker image historyでイメージが作られる際のステップを確認することもできます。

$ docker image history ubuntu:24.04
IMAGE          CREATED        CREATED BY                                       SIZE      COMMENT
c35e29c94501   2 months ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]             0B
<missing>      2 months ago   /bin/sh -c #(nop) ADD file:ddf1aa62235de6657…   87.6MB
<missing>      2 months ago   /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago   /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>      2 months ago   /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH      0B
<missing>      2 months ago   /bin/sh -c #(nop)  ARG RELEASE                   0B

ストレージドライバーは以下の種類があります。

Select a storage driver | Docker Docs

各ストレージドライバーを有効にする方法には触れませんが、OverlayFS(overlay2)だけ取り上げておくと
/etc/docker/daemon.jsonに以下のように設定して、Docker Daemonを再起動すればOKです。

{
  "storage-driver": "overlay2"
}

docker infoには以下のような表示が含まれます。

 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false

もしくはこうですね。

$ docker info -f '{{ .Driver}} {{ .DriverStatus }}'
overlay2 [[Backing Filesystem extfs] [Supports d_type true] [Using metacopy false] [Native Overlay Diff true] [userxattr false]]

OverlayFS storage driver / Configure Docker with the overlay2 storage driver

OverlayFSの仕組みはこちら。時々見かける/var/lib/docker/overlay2などが出てきます。

OverlayFS storage driver / How the overlay2 driver works

ドキュメントを見るのは今回はこれくらいにしておくのですが、あとはコンテナイメージがcontainerdイメージストアに
保存されているようになっていることを見ておきましょうか。

環境

今回の環境はこちら。

$ docker version
Client: Docker Engine - Community
 Version:           29.1.3
 API version:       1.52
 Go version:        go1.25.5
 Git commit:        f52814d
 Built:             Fri Dec 12 14:49:32 2025
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          29.1.3
  API version:      1.52 (minimum version 1.44)
  Go version:       go1.25.5
  Git commit:       fbf3ed2
  Built:            Fri Dec 12 14:49:32 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v2.2.1
  GitCommit:        dea7da592f5d1d2b7755e3a161be07f43fad8f75
 runc:
  Version:          1.3.4
  GitCommit:        v1.3.4-0-gd6d73eb8
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

containerd。

$ containerd --version
containerd containerd.io v2.2.1 dea7da592f5d1d2b7755e3a161be07f43fad8f75


$ ctr --version
ctr containerd.io v2.2.1

ctrというのはcontainerd CLIです。

$ ctr --help
NAME:
   ctr -
                 __
           _____/ /______
          / ___/ __/ ___/
         / /__/ /_/ /
         \___/\__/_/

         containerd CLI


USAGE:
   ctr [global options] command [command options]

VERSION:
   v2.2.1

DESCRIPTION:

   ctr is an unsupported debug and administrative client for interacting
   with the containerd daemon. Because it is unsupported, the commands,
   options, and operations are not guaranteed to be backward compatible or
   stable from release to release of the containerd project.

COMMANDS:
   plugins, plugin            Provides information about containerd plugins
   version                    Print the client and server versions
   containers, c, container   Manage containers
   content                    Manage content
   events, event              Display containerd events
   images, image, i           Manage images
   leases                     Manage leases
   namespaces, namespace, ns  Manage namespaces
   pprof                      Provide golang pprof outputs for containerd
   run                        Run a container
   snapshots, snapshot        Manage snapshots
   tasks, t, task             Manage tasks
   install                    Install a new package
   oci                        OCI tools
   sandboxes, sandbox, sb, s  Manage sandboxes
   info                       Print the server info
   deprecations
   shim                       Interact with a shim directly
   help, h                    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug                      Enable debug output in logs (default: false)
   --address value, -a value    Address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
   --timeout value              Total timeout for ctr commands (default: 0s)
   --connect-timeout value      Timeout for connecting to containerd (default: 0s)
   --namespace value, -n value  Namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]
   --help, -h                   Show help (default: false)
   --version, -v                Print the version (default: false)

containerdイメージストアが使われている環境です。

$ docker info -f '{{ .Driver}} {{ .DriverStatus }}'
overlayfs [[driver-type io.containerd.snapshotter.v1]]

containerdイメージストアが使われているかどうか見てみる

コンテナイメージをPullしてみます。ここではubuntu:24.04を対象としましょう。

$ docker image pull ubuntu:24.04

確認。

$ docker image ls
                                                                                                                                                        i Info →   U  In Use
IMAGE          ID             DISK USAGE   CONTENT SIZE   EXTRA
ubuntu:24.04   c35e29c94501        119MB         31.7MB

このコンテナイメージをcontainerd側でも確認できます。

namespaceを確認すると、「moby」というnamespaceがあります。

$ sudo ctr namespaces list
NAME LABELS
moby

containerdでイメージの一覧を確認してみます。

$ sudo ctr --namespace moby images list
REF                            TYPE                                    DIGEST                                                                  SIZE     PLATFORMS                                                                       LABELS
docker.io/library/ubuntu:24.04 application/vnd.oci.image.index.v1+json sha256:c35e29c9450151419d9448b0fd75374fec4fff364a27f176fb458d472dfc9e54 28.4 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/riscv64,linux/s390x -

すると、先ほどdocker image pullしたubuntu:24.04のコンテナイメージと同じハッシュ値が確認できます。
しかもプラットフォーム数が多いですね。これがマルチプラットフォームイメージを保存可能という
ことなのでしょう。

OverlayFSストレージドライバー環境で見てみる

ところで、OverlayFSストレージドライバー環境だとどうなるのでしょう。

コンテナイメージをPull。

$ docker image pull ubuntu:24.04

コンテナイメージの一覧。

$ docker image ls
                                                                                                                                                        i Info →   U  In Use
IMAGE                              ID             DISK USAGE   CONTENT SIZE   EXTRA
ubuntu:24.04                       c3a134f2ace4       78.1MB             0B

よくよく見ると、表示がすでに違いますね。containerdイメージストアの場合はこうでした。

$ docker image ls
                                                                                                                                                        i Info →   U  In Use
IMAGE          ID             DISK USAGE   CONTENT SIZE   EXTRA
ubuntu:24.04   c35e29c94501        119MB         31.7MB

確かにcontainerdイメージストアを使った方がディスクサイズは大きいようです。

OverlayFSストレージドライバー環境でcontainerdでイメージの一覧を見ても、当然ながら空っぽです。

$ sudo ctr --namespace moby images list
REF TYPE DIGEST SIZE PLATFORMS LABELS

containerdイメージストアでのコンテナイメージはどこに?

ちょっと気になるのが、containerdイメージストアでのコンテナイメージはどこに保存されているのか?という
ところなのですが。

docker infoでこのように表示される環境であれば

 Storage Driver: overlayfs
  driver-type: io.containerd.snapshotter.v1

/var/lib/containerd/io.containerd.snapshotter.v1.overlayfsディレクトリーにあるみたいですね。

しかもファイルが見れそうな感じがします。

$ sudo cat /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/88/fs/etc/os-release
PRETTY_NAME="Ubuntu 24.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="24.04"
VERSION="24.04.3 LTS (Noble Numbat)"
VERSION_CODENAME=noble
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=noble
LOGO=ubuntu-logo

これが「非圧縮レイヤーはスナップショットで管理される」ということなのでしょうか。

まあ、このあたりはまた機会があれば…。

オマケ

OverlayFSストレージドライバーを使っている既存の環境から再構築して移行する場合は、Docker Engine自体を
再インストールするだけではなくて/var/lib/dockerディレクトリーごと削除した方がよさそうです。

$ sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin


$ sudo rm -rf /var/lib/docker
$ sudo rm -rf /var/lib/containerd

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Install Docker Engine on Ubuntu / Uninstall Docker Engine

自分の環境だと、再インストールしてもOverlayFSストレージドライバーのままだったのでなんでだろう?と
思いました。

おわりに

Docker Daemonのストレージバックエンドについて見てみました。

かなり最近、デフォルトのストレージバックエンドが変更されていたんですね。ちょっと驚きました。
それにcontainerdの世界をほんの少しだけとはいえ見ることになるとは思っていませんでしたよ。

ストレージドライバーについてもほとんど見てきていなかったので、良い勉強の機会になりました。