storage(storagedrivers): q4 tier 1 refresh

Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
David Karlsson 2023-12-18 17:13:24 +01:00
parent a1015ad58d
commit 31a16f1da2
6 changed files with 618 additions and 578 deletions

View File

@ -1,7 +1,7 @@
---
title: containerd image store with Docker Engine
keywords: containerd, snapshotters, image store, docker engine
description: Enabling the containerd image store on Docker Engine
description: Learn how to enable the containerd image store on Docker Engine
---
> **Note**
@ -48,11 +48,9 @@ The following steps explain how to enable the containerd snapshotters feature.
After restarting the daemon, running `docker info` shows that you're using
containerd snapshotter storage drivers.
```console
$ docker info -f '{{ .DriverStatus }}'
[[driver-type io.containerd.snapshotter.v1]]
```
Docker Engine uses the `overlayfs` containerd snapshotter by default.
Docker Engine uses the `overlayfs` containerd snapshotter by default.

View File

@ -1,6 +1,6 @@
---
description: Learn the technologies that support storage drivers.
keywords: container, storage, driver, btrfs, devicemapper, overlayfs, vfs, zfs
keywords: container, storage, driver, btrfs, overlayfs, vfs, zfs
title: About storage drivers
aliases:
- /en/latest/terms/layer/
@ -17,7 +17,7 @@ your applications and avoid performance problems along the way.
## Storage drivers versus Docker volumes
Docker uses storage drivers to store image layers, and to store data in the
writable layer of a container. The container's writable layer does not persist
writable layer of a container. The container's writable layer doesn't persist
after the container is deleted, but is suitable for storing ephemeral data that
is generated at runtime. Storage drivers are optimized for space efficiency, but
(depending on the storage driver) write speeds are lower than native file system
@ -50,13 +50,13 @@ CMD python /app/app.py
This Dockerfile contains four commands. Commands that modify the filesystem create
a layer. The `FROM` statement starts out by creating a layer from the `ubuntu:22.04`
image. The `LABEL` command only modifies the image's metadata, and does not produce
image. The `LABEL` command only modifies the image's metadata, and doesn't produce
a new layer. The `COPY` command adds some files from your Docker client's current
directory. The first `RUN` command builds your application using the `make` command,
and writes the result to a new layer. The second `RUN` command removes a cache
directory, and writes the result to a new layer. Finally, the `CMD` instruction
specifies what command to run within the container, which only modifies the
image's metadata, which does not produce an image layer.
image's metadata, which doesn't produce an image layer.
Each layer is only a set of differences from the layer before it. Note that both
_adding_, and _removing_ files will result in a new layer. In the example above,
@ -75,7 +75,7 @@ on an `ubuntu:15.04` image.
![Layers of a container based on the Ubuntu image](images/container-layers.webp?w=450&h=300)
A _storage driver_ handles the details about the way these layers interact with
A storage driver handles the details about the way these layers interact with
each other. Different storage drivers are available, which have advantages
and disadvantages in different situations.
@ -104,13 +104,12 @@ differently, but all drivers use stackable image layers and the copy-on-write
> the exact same data. Refer to the [volumes section](../volumes.md) to learn
> about volumes.
## Container size on disk
To view the approximate size of a running container, you can use the `docker ps -s`
command. Two different columns relate to size.
- `size`: the amount of data (on disk) that is used for the writable layer of
- `size`: the amount of data (on disk) that's used for the writable layer of
each container.
- `virtual size`: the amount of data used for the read-only image data
used by the container plus the container's writable layer `size`.
@ -127,12 +126,12 @@ multiple containers started from the same exact image, the total size on disk fo
these containers would be SUM (`size` of containers) plus one image size
(`virtual size` - `size`).
This also does not count the following additional ways a container can take up
This also doesn't count the following additional ways a container can take up
disk space:
- Disk space used for log files stored by the [logging-driver](../../config/containers/logging/index.md).
This can be non-trivial if your container generates a large amount of logging
data and log rotation is not configured.
data and log rotation isn't configured.
- Volumes and bind mounts used by the container.
- Disk space used for the container's configuration files, which are typically
small.
@ -152,7 +151,7 @@ These advantages are explained in more depth below.
### Sharing promotes smaller images
When you use `docker pull` to pull down an image from a repository, or when you
create a container from an image that does not yet exist locally, each layer is
create a container from an image that doesn't yet exist locally, each layer is
pulled down separately, and stored in Docker's local storage area, which is
usually `/var/lib/docker/` on Linux hosts. You can see these layers being pulled
in this example:
@ -183,7 +182,7 @@ ec1ec45792908e90484f7e629330666e7eee599f08729c93890a7205a6ba35f5
l
```
The directory names do not correspond to the layer IDs.
The directory names don't correspond to the layer IDs.
Now imagine that you have two different Dockerfiles. You use the first one to
create an image called `acme/my-base-image:1.0`.
@ -207,183 +206,180 @@ CMD /app/hello.sh
The second image contains all the layers from the first image, plus new layers
created by the `COPY` and `RUN` instructions, and a read-write container layer.
Docker already has all the layers from the first image, so it does not need to
Docker already has all the layers from the first image, so it doesn't need to
pull them again. The two images share any layers they have in common.
If you build images from the two Dockerfiles, you can use `docker image ls` and
`docker image history` commands to verify that the cryptographic IDs of the shared
layers are the same.
1. Make a new directory `cow-test/` and change into it.
1. Make a new directory `cow-test/` and change into it.
2. Within `cow-test/`, create a new file called `hello.sh` with the following contents:
2. Within `cow-test/`, create a new file called `hello.sh` with the following contents.
```bash
#!/usr/bin/env bash
echo "Hello world"
```
```bash
#!/usr/bin/env bash
echo "Hello world"
```
3. Copy the contents of the first Dockerfile above into a new file called
`Dockerfile.base`.
3. Copy the contents of the first Dockerfile above into a new file called
`Dockerfile.base`.
4. Copy the contents of the second Dockerfile above into a new file called
`Dockerfile`.
4. Copy the contents of the second Dockerfile above into a new file called
`Dockerfile`.
5. Within the `cow-test/` directory, build the first image. Don't forget to
include the final `.` in the command. That sets the `PATH`, which tells
Docker where to look for any files that need to be added to the image.
5. Within the `cow-test/` directory, build the first image. Don't forget to
include the final `.` in the command. That sets the `PATH`, which tells
Docker where to look for any files that need to be added to the image.
```console
$ docker build -t acme/my-base-image:1.0 -f Dockerfile.base .
[+] Building 6.0s (11/11) FINISHED
=> [internal] load build definition from Dockerfile.base 0.4s
=> => transferring dockerfile: 116B 0.0s
=> [internal] load .dockerignore 0.3s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 1.5s
=> [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile.base 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 0.0s
=> CACHED [1/2] FROM docker.io/library/alpine 0.0s
=> [2/2] RUN apk add --no-cache bash 3.1s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:da3cf8df55ee9777ddcd5afc40fffc3ead816bda99430bad2257de4459625eaa 0.0s
=> => naming to docker.io/acme/my-base-image:1.0 0.0s
```
```console
$ docker build -t acme/my-base-image:1.0 -f Dockerfile.base .
[+] Building 6.0s (11/11) FINISHED
=> [internal] load build definition from Dockerfile.base 0.4s
=> => transferring dockerfile: 116B 0.0s
=> [internal] load .dockerignore 0.3s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 1.5s
=> [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile.base 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 0.0s
=> CACHED [1/2] FROM docker.io/library/alpine 0.0s
=> [2/2] RUN apk add --no-cache bash 3.1s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:da3cf8df55ee9777ddcd5afc40fffc3ead816bda99430bad2257de4459625eaa 0.0s
=> => naming to docker.io/acme/my-base-image:1.0 0.0s
```
6. Build the second image.
6. Build the second image.
```console
$ docker build -t acme/my-final-image:1.0 -f Dockerfile .
```console
$ docker build -t acme/my-final-image:1.0 -f Dockerfile .
[+] Building 3.6s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 156B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 0.5s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load metadata for docker.io/acme/my-base-image:1.0 0.0s
=> [internal] load build context 0.2s
=> => transferring context: 340B 0.0s
=> [1/3] FROM docker.io/acme/my-base-image:1.0 0.2s
=> [2/3] COPY . /app 0.1s
=> [3/3] RUN chmod +x /app/hello.sh 0.4s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:8bd85c42fa7ff6b33902ada7dcefaaae112bf5673873a089d73583b0074313dd 0.0s
=> => naming to docker.io/acme/my-final-image:1.0 0.0s
```
[+] Building 3.6s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 156B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 0.5s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load metadata for docker.io/acme/my-base-image:1.0 0.0s
=> [internal] load build context 0.2s
=> => transferring context: 340B 0.0s
=> [1/3] FROM docker.io/acme/my-base-image:1.0 0.2s
=> [2/3] COPY . /app 0.1s
=> [3/3] RUN chmod +x /app/hello.sh 0.4s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:8bd85c42fa7ff6b33902ada7dcefaaae112bf5673873a089d73583b0074313dd 0.0s
=> => naming to docker.io/acme/my-final-image:1.0 0.0s
```
7. Check out the sizes of the images:
7. Check out the sizes of the images.
```console
$ docker image ls
```console
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
acme/my-final-image 1.0 8bd85c42fa7f About a minute ago 7.75MB
acme/my-base-image 1.0 da3cf8df55ee 2 minutes ago 7.75MB
```
REPOSITORY TAG IMAGE ID CREATED SIZE
acme/my-final-image 1.0 8bd85c42fa7f About a minute ago 7.75MB
acme/my-base-image 1.0 da3cf8df55ee 2 minutes ago 7.75MB
```
8. Check out the history of each image:
8. Check out the history of each image.
```console
$ docker image history acme/my-base-image:1.0
```console
$ docker image history acme/my-base-image:1.0
IMAGE CREATED CREATED BY SIZE COMMENT
da3cf8df55ee 5 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
```
IMAGE CREATED CREATED BY SIZE COMMENT
da3cf8df55ee 5 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
```
Some steps do not have a size (`0B`), and are metadata-only changes, which do
not produce an image layer and do not take up any size, other than the metadata
itself. The output above shows that this image consists of 2 image layers.
Some steps don't have a size (`0B`), and are metadata-only changes, which do
not produce an image layer and don't take up any size, other than the metadata
itself. The output above shows that this image consists of 2 image layers.
```console
$ docker image history acme/my-final-image:1.0
```console
$ docker image history acme/my-final-image:1.0
IMAGE CREATED CREATED BY SIZE COMMENT
8bd85c42fa7f 3 minutes ago CMD ["/bin/sh" "-c" "/app/hello.sh"] 0B buildkit.dockerfile.v0
<missing> 3 minutes ago RUN /bin/sh -c chmod +x /app/hello.sh # buil… 39B buildkit.dockerfile.v0
<missing> 3 minutes ago COPY . /app # buildkit 222B buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
```
IMAGE CREATED CREATED BY SIZE COMMENT
8bd85c42fa7f 3 minutes ago CMD ["/bin/sh" "-c" "/app/hello.sh"] 0B buildkit.dockerfile.v0
<missing> 3 minutes ago RUN /bin/sh -c chmod +x /app/hello.sh # buil… 39B buildkit.dockerfile.v0
<missing> 3 minutes ago COPY . /app # buildkit 222B buildkit.dockerfile.v0
<missing> 4 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
```
Notice that all steps of the first image are also included in the final
image. The final image includes the two layers from the first image, and
two layers that were added in the second image.
Notice that all steps of the first image are also included in the final
image. The final image includes the two layers from the first image, and
two layers that were added in the second image.
> What are the `<missing>` steps?
>
> The `<missing>` lines in the `docker history` output indicate that those
> steps were either built on another system and part of the `alpine` image
> that was pulled from Docker Hub, or were built with BuildKit as builder.
> Before BuildKit, the "classic" builder would produce a new "intermediate"
> image for each step for caching purposes, and the `IMAGE` column would show
> the ID of that image.
> BuildKit uses its own caching mechanism, and no longer requires intermediate
> images for caching. Refer to [BuildKit](../../build/buildkit/index.md)
> to learn more about other enhancements made in BuildKit.
The `<missing>` lines in the `docker history` output indicate that those
steps were either built on another system and part of the `alpine` image
that was pulled from Docker Hub, or were built with BuildKit as builder.
Before BuildKit, the "classic" builder would produce a new "intermediate"
image for each step for caching purposes, and the `IMAGE` column would show
the ID of that image.
BuildKit uses its own caching mechanism, and no longer requires intermediate
images for caching. Refer to [BuildKit](../../build/buildkit/_index.md)
to learn more about other enhancements made in BuildKit.
9. Check out the layers for each image
9. Check out the layers for each image
Use the `docker image inspect` command to view the cryptographic IDs of the
layers in each image:
Use the `docker image inspect` command to view the cryptographic IDs of the
layers in each image:
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-base-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a"
]
```
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-final-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a",
"sha256:cc644054967e516db4689b5282ee98e4bc4b11ea2255c9630309f559ab96562e",
"sha256:e84fb818852626e89a09f5143dbc31fe7f0e0a6a24cd8d2eb68062b904337af4"
]
```
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-base-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a"
]
```
Notice that the first two layers are identical in both images. The second
image adds two additional layers. Shared image layers are only stored once
in `/var/lib/docker/` and are also shared when pushing and pulling an image
to an image registry. Shared image layers can therefore reduce network
bandwidth and storage.
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-final-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a",
"sha256:cc644054967e516db4689b5282ee98e4bc4b11ea2255c9630309f559ab96562e",
"sha256:e84fb818852626e89a09f5143dbc31fe7f0e0a6a24cd8d2eb68062b904337af4"
]
```
Notice that the first two layers are identical in both images. The second
image adds two additional layers. Shared image layers are only stored once
in `/var/lib/docker/` and are also shared when pushing and pulling and image
to an image registry. Shared image layers can therefore reduce network
bandwidth and storage.
> Tip: format output of Docker commands with the `--format` option
>
> The examples above use the `docker image inspect` command with the `--format`
> option to view the layer IDs, formatted as a JSON array. The `--format`
> option on Docker commands can be a powerful feature that allows you to
> extract and format specific information from the output, without requiring
> additional tools such as `awk` or `sed`. To learn more about formatting
> the output of docker commands using the `--format` flag, refer to the
> [format command and log output section](../../config/formatting.md).
> We also pretty-printed the JSON output using the [`jq` utility](https://stedolan.github.io/jq/)
> for readability.
> **Tip**
>
> Format output of Docker commands with the `--format` option.
>
> The examples above use the `docker image inspect` command with the `--format`
> option to view the layer IDs, formatted as a JSON array. The `--format`
> option on Docker commands can be a powerful feature that allows you to
> extract and format specific information from the output, without requiring
> additional tools such as `awk` or `sed`. To learn more about formatting
> the output of docker commands using the `--format` flag, refer to the
> [format command and log output section](../../config/formatting.md).
> We also pretty-printed the JSON output using the [`jq` utility](https://stedolan.github.io/jq/)
> for readability.
{ .tip }
### Copying makes containers efficient
When you start a container, a thin writable container layer is added on top of
the other layers. Any changes the container makes to the filesystem are stored
here. Any files the container does not change do not get copied to this writable
here. Any files the container doesn't change don't get copied to this writable
layer. This means that the writable layer is as small as possible.
When an existing file in a container is modified, the storage driver performs a
@ -393,10 +389,10 @@ this rough sequence:
* Search through the image layers for the file to update. The process starts
at the newest layer and works down to the base layer one layer at a time.
When results are found, they are added to a cache to speed future operations.
* Perform a `copy_up` operation on the first copy of the file that is found, to
When results are found, they're added to a cache to speed future operations.
* Perform a `copy_up` operation on the first copy of the file that's found, to
copy the file to the container's writable layer.
* Any modifications are made to this copy of the file, and the container cannot
* Any modifications are made to this copy of the file, and the container can't
see the read-only copy of the file that exists in the lower layer.
Btrfs, ZFS, and other drivers handle the copy-on-write differently. You can
@ -404,21 +400,26 @@ read more about the methods of these drivers later in their detailed
descriptions.
Containers that write a lot of data consume more space than containers
that do not. This is because most write operations consume new space in the
that don't. This is because most write operations consume new space in the
container's thin writable top layer. Note that changing the metadata of files,
for example, changing file permissions or ownership of a file, can also result
in a `copy_up` operation, therefore duplicating the file to the writable layer.
> Tip: Use volumes for write-heavy applications
> **Tip**
>
> For write-heavy applications, you should not store the data in the container.
> Applications, such as write-intensive database storage, are known to be
> problematic particularly when pre-existing data exists in the read-only layer.
> Use volumes for write-heavy applications.
>
> Don't store the data in the container for write-heavy applications. Such
> applications, for example write-intensive databases, are known to be
> problematic particularly when pre-existing data exists in the read-only
> layer.
>
> Instead, use Docker volumes, which are independent of the running container,
> and designed to be efficient for I/O. In addition, volumes can be shared among
> containers and do not increase the size of your container's writable layer.
> Refer to the [use volumes](../volumes.md) section to learn about volumes.
> and designed to be efficient for I/O. In addition, volumes can be shared
> among containers and don't increase the size of your container's writable
> layer. Refer to the [use volumes](../volumes.md) section to learn about
> volumes.
{ .tip }
A `copy_up` operation can incur a noticeable performance overhead. This overhead
is different depending on which storage driver is in use. Large files,
@ -430,109 +431,111 @@ To verify the way that copy-on-write works, the following procedures spins up 5
containers based on the `acme/my-final-image:1.0` image we built earlier and
examines how much room they take up.
1. From a terminal on your Docker host, run the following `docker run` commands.
The strings at the end are the IDs of each container.
1. From a terminal on your Docker host, run the following `docker run` commands.
The strings at the end are the IDs of each container.
```console
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_5 acme/my-final-image:1.0 bash
```console
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_5 acme/my-final-image:1.0 bash
40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
```
40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
```
2. Run the `docker ps` command with the `--size` option to verify the 5 containers
are running, and to see each container's size.
2. Run the `docker ps` command with the `--size` option to verify the 5 containers
are running, and to see each container's size.
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
CONTAINER ID IMAGE NAMES SIZE
cddae31c314f acme/my-final-image:1.0 my_container_5 0B (virtual 7.75MB)
939b3bf9e7ec acme/my-final-image:1.0 my_container_4 0B (virtual 7.75MB)
3ed3c1a10430 acme/my-final-image:1.0 my_container_3 0B (virtual 7.75MB)
a5ff32e2b551 acme/my-final-image:1.0 my_container_2 0B (virtual 7.75MB)
40ebdd763416 acme/my-final-image:1.0 my_container_1 0B (virtual 7.75MB)
```
CONTAINER ID IMAGE NAMES SIZE
cddae31c314f acme/my-final-image:1.0 my_container_5 0B (virtual 7.75MB)
939b3bf9e7ec acme/my-final-image:1.0 my_container_4 0B (virtual 7.75MB)
3ed3c1a10430 acme/my-final-image:1.0 my_container_3 0B (virtual 7.75MB)
a5ff32e2b551 acme/my-final-image:1.0 my_container_2 0B (virtual 7.75MB)
40ebdd763416 acme/my-final-image:1.0 my_container_1 0B (virtual 7.75MB)
```
The output above shows that all containers share the image's read-only layers
(7.75MB), but no data was written to the container's filesystem, so no additional
storage is used for the containers.
The output above shows that all containers share the image's read-only layers
(7.75MB), but no data was written to the container's filesystem, so no additional
storage is used for the containers.
{{< accordion title="Advanced: metadata and logs storage used for containers" >}}
> **Note**
>
> This step requires a Linux machine, and doesn't work on Docker Desktop, as
> it requires access to the Docker Daemon's file storage.
While the output of `docker ps` provides you information about disk space
consumed by a container's writable layer, it doesn't include information
about metadata and log-files stored for each container.
More details can be obtained by exploring the Docker Daemon's storage
location (`/var/lib/docker` by default).
```console
$ sudo du -sh /var/lib/docker/containers/*
36K /var/lib/docker/containers/3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
36K /var/lib/docker/containers/40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
36K /var/lib/docker/containers/939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
36K /var/lib/docker/containers/a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
36K /var/lib/docker/containers/cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
```
Each of these containers only takes up 36k of space on the filesystem.
> Advanced: metadata and logs storage used for containers
>
> **Note**: This step requires a Linux machine, and does not work on Docker
> Desktop for Mac or Docker Desktop for Windows, as it requires access to
> the Docker Daemon's file storage.
>
> While the output of `docker ps` provides you information about disk space
> consumed by a container's writable layer, it does not include information
> about metadata and log-files stored for each container.
>
> More details can be obtained by exploring the Docker Daemon's storage location
> (`/var/lib/docker` by default).
>
> ```console
> $ sudo du -sh /var/lib/docker/containers/*
>
> 36K /var/lib/docker/containers/3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
> 36K /var/lib/docker/containers/40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
> 36K /var/lib/docker/containers/939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
> 36K /var/lib/docker/containers/a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
> 36K /var/lib/docker/containers/cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
> ```
>
> Each of these containers only takes up 36k of space on the filesystem.
{{< /accordion >}}
3. Per-container storage
To demonstrate this, run the following command to write the word 'hello' to
a file on the container's writable layer in containers `my_container_1`,
`my_container_2`, and `my_container_3`:
To demonstrate this, run the following command to write the word 'hello' to
a file on the container's writable layer in containers `my_container_1`,
`my_container_2`, and `my_container_3`:
```console
$ for i in {1..3}; do docker exec my_container_$i sh -c 'printf hello > /out.txt'; done
```
```console
$ for i in {1..3}; do docker exec my_container_$i sh -c 'printf hello > /out.txt'; done
```
Running the `docker ps` command again afterward shows that those containers
now consume 5 bytes each. This data is unique to each container, and not
shared. The read-only layers of the containers are not affected, and are still
shared by all containers.
Running the `docker ps` command again afterward shows that those containers
now consume 5 bytes each. This data is unique to each container, and not
shared. The read-only layers of the containers aren't affected, and are still
shared by all containers.
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
CONTAINER ID IMAGE NAMES SIZE
cddae31c314f acme/my-final-image:1.0 my_container_5 0B (virtual 7.75MB)
939b3bf9e7ec acme/my-final-image:1.0 my_container_4 0B (virtual 7.75MB)
3ed3c1a10430 acme/my-final-image:1.0 my_container_3 5B (virtual 7.75MB)
a5ff32e2b551 acme/my-final-image:1.0 my_container_2 5B (virtual 7.75MB)
40ebdd763416 acme/my-final-image:1.0 my_container_1 5B (virtual 7.75MB)
```
CONTAINER ID IMAGE NAMES SIZE
cddae31c314f acme/my-final-image:1.0 my_container_5 0B (virtual 7.75MB)
939b3bf9e7ec acme/my-final-image:1.0 my_container_4 0B (virtual 7.75MB)
3ed3c1a10430 acme/my-final-image:1.0 my_container_3 5B (virtual 7.75MB)
a5ff32e2b551 acme/my-final-image:1.0 my_container_2 5B (virtual 7.75MB)
40ebdd763416 acme/my-final-image:1.0 my_container_1 5B (virtual 7.75MB)
```
The examples above illustrate how copy-on-write filesystems help making containers
efficient. Not only does copy-on-write save space, but it also reduces container
start-up time. When you create a container (or multiple containers from the same
image), Docker only needs to create the thin writable container layer.
The previous examples illustrate how copy-on-write filesystems help making
containers efficient. Not only does copy-on-write save space, but it also
reduces container start-up time. When you create a container (or multiple
containers from the same image), Docker only needs to create the thin writable
container layer.
If Docker had to make an entire copy of the underlying image stack each time it
created a new container, container create times and disk space used would be
significantly increased. This would be similar to the way that virtual machines
work, with one or more virtual disks per virtual machine. The [`vfs` storage](vfs-driver.md)
does not provide a CoW filesystem or other optimizations. When using this storage
doesn't provide a CoW filesystem or other optimizations. When using this storage
driver, a full copy of the image's data is created for each container.
## Related information
* [Volumes](../volumes.md)
* [Select a storage driver](select-storage-driver.md)
* [Select a storage driver](select-storage-driver.md)

View File

@ -1,30 +1,33 @@
---
description: Learn how to optimize your use of Btrfs driver.
keywords: 'container, storage, driver, Btrfs '
keywords: container, storage, driver, Btrfs
title: Use the BTRFS storage driver
aliases:
- /engine/userguide/storagedriver/btrfs-driver/
- /engine/userguide/storagedriver/btrfs-driver/
---
Btrfs is a next generation copy-on-write filesystem that supports many advanced
storage technologies that make it a good fit for Docker. Btrfs is included in
the mainline Linux kernel.
Btrfs is a copy-on-write filesystem that supports many advanced storage
technologies, making it a good fit for Docker. Btrfs is included in the
mainline Linux kernel.
Docker's `btrfs` storage driver leverages many Btrfs features for image and
container management. Among these features are block-level operations, thin
provisioning, copy-on-write snapshots, and ease of administration. You can
easily combine multiple physical block devices into a single Btrfs filesystem.
combine multiple physical block devices into a single Btrfs filesystem.
This article refers to Docker's Btrfs storage driver as `btrfs` and the overall
This page refers to Docker's Btrfs storage driver as `btrfs` and the overall
Btrfs Filesystem as Btrfs.
> **Note**: The `btrfs` storage driver is only supported on Docker Engine - Community on SLES, Ubuntu or Debian.
> **Note**
>
> The `btrfs` storage driver is only supported with Docker Engine CE on SLES,
> Ubuntu, and Debian systems.
## Prerequisites
`btrfs` is supported if you meet the following prerequisites:
- **Docker Engine - Community**: For Docker Engine - Community, `btrfs` is only recommended on Ubuntu or Debian.
- `btrfs` is only recommended with Docker CE on Ubuntu or Debian systems.
- Changing the storage driver makes any containers you have already
created inaccessible on the local system. Use `docker save` to save containers,
@ -34,7 +37,7 @@ Btrfs Filesystem as Btrfs.
- `btrfs` requires a dedicated block storage device such as a physical disk. This
block device must be formatted for Btrfs and mounted into `/var/lib/docker/`.
The configuration instructions below walk you through this procedure. By
default, the SLES `/` filesystem is formatted with BTRFS, so for SLES, you do
default, the SLES `/` filesystem is formatted with Btrfs, so for SLES, you do
not need to use a separate block device, but you can choose to do so for
performance reasons.
@ -47,94 +50,96 @@ Btrfs Filesystem as Btrfs.
btrfs
```
- To manage BTRFS filesystems at the level of the operating system, you need the
`btrfs` command. If you do not have this command, install the `btrfsprogs`
- To manage Btrfs filesystems at the level of the operating system, you need the
`btrfs` command. If you don't have this command, install the `btrfsprogs`
package (SLES) or `btrfs-tools` package (Ubuntu).
## Configure Docker to use the btrfs storage driver
This procedure is essentially identical on SLES and Ubuntu.
1. Stop Docker.
1. Stop Docker.
2. Copy the contents of `/var/lib/docker/` to a backup location, then empty
the contents of `/var/lib/docker/`:
2. Copy the contents of `/var/lib/docker/` to a backup location, then empty
the contents of `/var/lib/docker/`:
```console
$ sudo cp -au /var/lib/docker /var/lib/docker.bk
$ sudo rm -rf /var/lib/docker/*
```
```console
$ sudo cp -au /var/lib/docker /var/lib/docker.bk
$ sudo rm -rf /var/lib/docker/*
```
3. Format your dedicated block device or devices as a Btrfs filesystem. This
example assumes that you are using two block devices called `/dev/xvdf` and
`/dev/xvdg`. Double-check the block device names because this is a
destructive operation.
3. Format your dedicated block device or devices as a Btrfs filesystem. This
example assumes that you are using two block devices called `/dev/xvdf` and
`/dev/xvdg`. Double-check the block device names because this is a
destructive operation.
```console
$ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg
```
```console
$ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg
```
There are many more options for Btrfs, including striping and RAID. See the
[Btrfs documentation](https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices).
There are many more options for Btrfs, including striping and RAID. See the
[Btrfs documentation](https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices).
4. Mount the new Btrfs filesystem on the `/var/lib/docker/` mount point. You
can specify any of the block devices used to create the Btrfs filesystem.
4. Mount the new Btrfs filesystem on the `/var/lib/docker/` mount point. You
can specify any of the block devices used to create the Btrfs filesystem.
```console
$ sudo mount -t btrfs /dev/xvdf /var/lib/docker
```
```console
$ sudo mount -t btrfs /dev/xvdf /var/lib/docker
```
Don't forget to make the change permanent across reboots by adding an
entry to `/etc/fstab`.
> **Note**
>
> Make the change permanent across reboots by adding an entry to
> `/etc/fstab`.
5. Copy the contents of `/var/lib/docker.bk` to `/var/lib/docker/`.
5. Copy the contents of `/var/lib/docker.bk` to `/var/lib/docker/`.
```console
$ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/
```
```console
$ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/
```
6. Configure Docker to use the `btrfs` storage driver. This is required even
though `/var/lib/docker/` is now using a Btrfs filesystem.
Edit or create the file `/etc/docker/daemon.json`. If it is a new file, add
the following contents. If it is an existing file, add the key and value
only, being careful to end the line with a comma if it is not the final
line before an ending curly bracket (`}`).
6. Configure Docker to use the `btrfs` storage driver. This is required even
though `/var/lib/docker/` is now using a Btrfs filesystem.
Edit or create the file `/etc/docker/daemon.json`. If it is a new file, add
the following contents. If it is an existing file, add the key and value
only, being careful to end the line with a comma if it isn't the final
line before an ending curly bracket (`}`).
```json
{
"storage-driver": "btrfs"
}
```
```json
{
"storage-driver": "btrfs"
}
```
See all storage options for each storage driver in the
[daemon reference documentation](/engine/reference/commandline/dockerd/#options-per-storage-driver)
See all storage options for each storage driver in the
[daemon reference documentation](/engine/reference/commandline/dockerd/#options-per-storage-driver)
7. Start Docker. After it is running, verify that `btrfs` is being used as the
storage driver.
7. Start Docker. When it's running, verify that `btrfs` is being used as the
storage driver.
```console
$ docker info
```console
$ docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.03.1-ce
Storage Driver: btrfs
Build Version: Btrfs v4.4
Library Version: 101
<...>
```
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 17.03.1-ce
Storage Driver: btrfs
Build Version: Btrfs v4.4
Library Version: 101
<...>
```
8. When you are ready, remove the `/var/lib/docker.bk` directory.
8. When you are ready, remove the `/var/lib/docker.bk` directory.
## Manage a Btrfs volume
One of the benefits of Btrfs is the ease of managing Btrfs filesystems without
the need to unmount the filesystem or restart Docker.
When space gets low, Btrfs automatically expands the volume in *chunks* of
When space gets low, Btrfs automatically expands the volume in chunks of
roughly 1 GB.
To add a block device to a Btrfs volume, use the `btrfs device add` and
@ -146,9 +151,10 @@ $ sudo btrfs device add /dev/svdh /var/lib/docker
$ sudo btrfs filesystem balance /var/lib/docker
```
> **Note**: While you can do these operations with Docker running, performance
> suffers. It might be best to plan an outage window to balance the Btrfs
> filesystem.
> **Note**
>
> While you can do these operations with Docker running, performance suffers.
> It might be best to plan an outage window to balance the Btrfs filesystem.
## How the `btrfs` storage driver works
@ -185,7 +191,7 @@ snapshot sharing data.
![Snapshot and subvolume sharing data](images/btfs_pool.webp?w=450&h=200)
For maximum efficiency, when a container needs more space, it is allocated in
*chunks* of roughly 1 GB in size.
chunks of roughly 1 GB in size.
Docker's `btrfs` storage driver stores every image layer and container in its
own Btrfs subvolume or snapshot. The base layer of an image is stored as a
@ -197,16 +203,16 @@ This is shown in the diagram below.
The high level process for creating images and containers on Docker hosts
running the `btrfs` driver is as follows:
1. The image's base layer is stored in a Btrfs *subvolume* under
`/var/lib/docker/btrfs/subvolumes`.
1. The image's base layer is stored in a Btrfs _subvolume_ under
`/var/lib/docker/btrfs/subvolumes`.
2. Subsequent image layers are stored as a Btrfs *snapshot* of the parent
layer's subvolume or snapshot, but with the changes introduced by this
layer. These differences are stored at the block level.
2. Subsequent image layers are stored as a Btrfs _snapshot_ of the parent
layer's subvolume or snapshot, but with the changes introduced by this
layer. These differences are stored at the block level.
3. The container's writable layer is a Btrfs snapshot of the final image layer,
with the differences introduced by the running container. These differences
are stored at the block level.
3. The container's writable layer is a Btrfs snapshot of the final image layer,
with the differences introduced by the running container. These differences
are stored at the block level.
## How container reads and writes work with `btrfs`
@ -219,92 +225,112 @@ same as reads performed against a subvolume.
### Writing files
- **Writing new files**: Writing a new file to a container invokes an allocate-on-demand
operation to allocate new data block to the container's snapshot. The file is
then written to this new space. The allocate-on-demand operation is native to
all writes with Btrfs and is the same as writing new data to a subvolume. As a
result, writing new files to a container's snapshot operates at native Btrfs
speeds.
As a general caution, writing and updating a large number of small files with
Btrfs can result in slow performance.
- **Modifying existing files**: Updating an existing file in a container is a copy-on-write
operation (*redirect-on-write* is the Btrfs terminology). The original data is
read from the layer where the file currently exists, and only the modified
blocks are written into the container's writable layer. Next, the Btrfs driver
updates the filesystem metadata in the snapshot to point to this new data.
This behavior incurs very little overhead.
Consider three scenarios where a container opens a file for write access with
Btrfs.
- **Deleting files or directories**: If a container deletes a file or directory
that exists in a lower layer, Btrfs masks the existence of the file or
directory in the lower layer. If a container creates a file and then deletes
it, this operation is performed in the Btrfs filesystem itself and the space
is reclaimed.
#### Writing new files
With Btrfs, writing and updating lots of small files can result in slow
performance.
Writing a new file to a container invokes an allocate-on-demand operation to
allocate new data block to the container's snapshot. The file is then written
to this new space. The allocate-on-demand operation is native to all writes
with Btrfs and is the same as writing new data to a subvolume. As a result,
writing new files to a container's snapshot operates at native Btrfs speeds.
#### Modifying existing files
Updating an existing file in a container is a copy-on-write operation
(redirect-on-write is the Btrfs terminology). The original data is read from
the layer where the file currently exists, and only the modified blocks are
written into the container's writable layer. Next, the Btrfs driver updates the
filesystem metadata in the snapshot to point to this new data. This behavior
incurs minor overhead.
#### Deleting files or directories
If a container deletes a file or directory that exists in a lower layer, Btrfs
masks the existence of the file or directory in the lower layer. If a container
creates a file and then deletes it, this operation is performed in the Btrfs
filesystem itself and the space is reclaimed.
## Btrfs and Docker performance
There are several factors that influence Docker's performance under the `btrfs`
storage driver.
> **Note**: Many of these factors are mitigated by using Docker volumes for
> write-heavy workloads, rather than relying on storing data in the container's
> writable layer. However, in the case of Btrfs, Docker volumes still suffer
> from these draw-backs unless `/var/lib/docker/volumes/` is **not** backed by
> Btrfs.
> **Note**
>
> Many of these factors are mitigated by using Docker volumes for write-heavy
> workloads, rather than relying on storing data in the container's writable
> layer. However, in the case of Btrfs, Docker volumes still suffer from these
> draw-backs unless `/var/lib/docker/volumes/` isn't backed by Btrfs.
- **Page caching**. Btrfs does not support page cache sharing. This means that
each process accessing the same file copies the file into the Docker hosts's
memory. As a result, the `btrfs` driver may not be the best choice
high-density use cases such as PaaS.
### Page caching
- **Small writes**. Containers performing lots of small writes (this usage
pattern matches what happens when you start and stop many containers in a short
period of time, as well) can lead to poor use of Btrfs chunks. This can
prematurely fill the Btrfs filesystem and lead to out-of-space conditions on
your Docker host. Use `btrfs filesys show` to closely monitor the amount of
free space on your Btrfs device.
Btrfs doesn't support page cache sharing. This means that each process
accessing the same file copies the file into the Docker host's memory. As a
result, the `btrfs` driver may not be the best choice high-density use cases
such as PaaS.
- **Sequential writes**. Btrfs uses a journaling technique when writing to disk.
This can impact the performance of sequential writes, reducing performance by
up to 50%.
### Small writes
- **Fragmentation**. Fragmentation is a natural byproduct of copy-on-write
filesystems like Btrfs. Many small random writes can compound this issue.
Fragmentation can manifest as CPU spikes when using SSDs or head thrashing
when using spinning disks. Either of these issues can harm performance.
Containers performing lots of small writes (this usage pattern matches what
happens when you start and stop many containers in a short period of time, as
well) can lead to poor use of Btrfs chunks. This can prematurely fill the Btrfs
filesystem and lead to out-of-space conditions on your Docker host. Use `btrfs
filesys show` to closely monitor the amount of free space on your Btrfs device.
If your Linux kernel version is 3.9 or higher, you can enable the `autodefrag`
feature when mounting a Btrfs volume. Test this feature on your own workloads
before deploying it into production, as some tests have shown a negative
impact on performance.
### Sequential writes
- **SSD performance**: Btrfs includes native optimizations for SSD media.
To enable these features, mount the Btrfs filesystem with the `-o ssd` mount
option. These optimizations include enhanced SSD write performance by avoiding
optimization such as *seek optimizations* which do not apply to solid-state
media.
Btrfs uses a journaling technique when writing to disk. This can impact the
performance of sequential writes, reducing performance by up to 50%.
- **Balance Btrfs filesystems often**: Use operating system utilities such as a
`cron` job to balance the Btrfs filesystem regularly, during non-peak hours.
This reclaims unallocated blocks and helps to prevent the filesystem from
filling up unnecessarily. You cannot rebalance a totally full Btrfs
filesystem unless you add additional physical block devices to the filesystem.
See the
[BTRFS Wiki](https://btrfs.wiki.kernel.org/index.php/Balance_Filters#Balancing_to_fix_filesystem_full_errors).
### Fragmentation
- **Use fast storage**: Solid-state drives (SSDs) provide faster reads and
writes than spinning disks.
Fragmentation is a natural byproduct of copy-on-write filesystems like Btrfs.
Many small random writes can compound this issue. Fragmentation can manifest as
CPU spikes when using SSDs or head thrashing when using spinning disks. Either
of these issues can harm performance.
- **Use volumes for write-heavy workloads**: Volumes provide the best and most
predictable performance for write-heavy workloads. This is because they bypass
the storage driver and do not incur any of the potential overheads introduced
by thin provisioning and copy-on-write. Volumes have other benefits, such as
allowing you to share data among containers and persisting even when no
running container is using them.
If your Linux kernel version is 3.9 or higher, you can enable the `autodefrag`
feature when mounting a Btrfs volume. Test this feature on your own workloads
before deploying it into production, as some tests have shown a negative impact
on performance.
### SSD performance
Btrfs includes native optimizations for SSD media. To enable these features,
mount the Btrfs filesystem with the `-o ssd` mount option. These optimizations
include enhanced SSD write performance by avoiding optimization such as seek
optimizations that don't apply to solid-state media.
### Balance Btrfs filesystems often
Use operating system utilities such as a `cron` job to balance the Btrfs
filesystem regularly, during non-peak hours. This reclaims unallocated blocks
and helps to prevent the filesystem from filling up unnecessarily. You can't
rebalance a totally full Btrfs filesystem unless you add additional physical
block devices to the filesystem.
See the [Btrfs
Wiki](https://btrfs.wiki.kernel.org/index.php/Balance_Filters#Balancing_to_fix_filesystem_full_errors).
### Use fast storage
Solid-state drives (SSDs) provide faster reads and writes than spinning disks.
### Use volumes for write-heavy workloads
Volumes provide the best and most predictable performance for write-heavy
workloads. This is because they bypass the storage driver and don't incur any
of the potential overheads introduced by thin provisioning and copy-on-write.
Volumes have other benefits, such as allowing you to share data among
containers and persisting even when no running container is using them.
## Related Information
- [Volumes](../volumes.md)
- [Understand images, containers, and storage drivers](index.md)
- [Select a storage driver](select-storage-driver.md)
- [Select a storage driver](select-storage-driver.md)

View File

@ -3,13 +3,17 @@ description: Learn how to optimize your use of OverlayFS driver.
keywords: container, storage, driver, OverlayFS, overlay2, overlay
title: Use the OverlayFS storage driver
aliases:
- /engine/userguide/storagedriver/overlayfs-driver/
- /engine/userguide/storagedriver/overlayfs-driver/
---
OverlayFS is a modern *union filesystem*. This topic refers to the Linux kernel
driver as `OverlayFS` and to the Docker storage driver as `overlay2`.
OverlayFS is a union filesystem.
> **Note**: For `fuse-overlayfs` driver, check [Rootless mode documentation](../../engine/security/rootless.md).
This page refers to the Linux kernel driver as `OverlayFS` and to the Docker
storage driver as `overlay2`.
> **Note**
>
> For `fuse-overlayfs` driver, check [Rootless mode documentation](../../engine/security/rootless.md).
## Prerequisites
@ -21,23 +25,22 @@ prerequisites:
- The `overlay2` driver is supported on `xfs` backing filesystems,
but only with `d_type=true` enabled.
Use `xfs_info` to verify that the `ftype` option is set to `1`. To format an
`xfs` filesystem correctly, use the flag `-n ftype=1`.
Use `xfs_info` to verify that the `ftype` option is set to `1`. To format an
`xfs` filesystem correctly, use the flag `-n ftype=1`.
- Changing the storage driver makes existing containers and images inaccessible
on the local system. Use `docker save` to save any images you have built or
push them to Docker Hub or a private registry before changing the storage driver,
so that you do not need to re-create them later.
so that you don't need to re-create them later.
## Configure Docker with the `overlay2` storage driver
<a name="configure-docker-with-the-overlay-or-overlay2-storage-driver"></a>
Before following this procedure, you must first meet all the
[prerequisites](#prerequisites).
The steps below outline how to configure the `overlay2` storage driver.
The following steps outline how to configure the `overlay2` storage driver.
1. Stop Docker.
@ -45,48 +48,48 @@ The steps below outline how to configure the `overlay2` storage driver.
$ sudo systemctl stop docker
```
2. Copy the contents of `/var/lib/docker` to a temporary location.
2. Copy the contents of `/var/lib/docker` to a temporary location.
```console
$ cp -au /var/lib/docker /var/lib/docker.bk
```
```console
$ cp -au /var/lib/docker /var/lib/docker.bk
```
3. If you want to use a separate backing filesystem from the one used by
`/var/lib/`, format the filesystem and mount it into `/var/lib/docker`.
Make sure add this mount to `/etc/fstab` to make it permanent.
3. If you want to use a separate backing filesystem from the one used by
`/var/lib/`, format the filesystem and mount it into `/var/lib/docker`.
Make sure to add this mount to `/etc/fstab` to make it permanent.
4. Edit `/etc/docker/daemon.json`. If it does not yet exist, create it. Assuming
that the file was empty, add the following contents.
4. Edit `/etc/docker/daemon.json`. If it doesn't yet exist, create it. Assuming
that the file was empty, add the following contents.
```json
{
"storage-driver": "overlay2"
}
```
```json
{
"storage-driver": "overlay2"
}
```
Docker does not start if the `daemon.json` file contains badly-formed JSON.
Docker doesn't start if the `daemon.json` file contains invalid JSON.
5. Start Docker.
5. Start Docker.
```console
$ sudo systemctl start docker
```
```console
$ sudo systemctl start docker
```
6. Verify that the daemon is using the `overlay2` storage driver.
Use the `docker info` command and look for `Storage Driver` and
`Backing filesystem`.
6. Verify that the daemon is using the `overlay2` storage driver.
Use the `docker info` command and look for `Storage Driver` and
`Backing filesystem`.
```console
$ docker info
```console
$ docker info
Containers: 0
Images: 0
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
<...>
```
Containers: 0
Images: 0
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
<...>
```
Docker is now using the `overlay2` storage driver and has automatically
created the overlay mount with the required `lowerdir`, `upperdir`, `merged`,
@ -98,12 +101,9 @@ its compatibility with different backing filesystems.
## How the `overlay2` driver works
If you are still using the `overlay` driver rather than `overlay2`, see
[How the overlay driver works](#how-the-overlay2-driver-works) instead.
OverlayFS layers two directories on a single Linux host and presents them as
a single directory. These directories are called _layers_ and the unification
process is referred to as a _union mount_. OverlayFS refers to the lower directory
a single directory. These directories are called layers, and the unification
process is referred to as a union mount. OverlayFS refers to the lower directory
as `lowerdir` and the upper directory a `upperdir`. The unified view is exposed
through its own directory called `merged`.
@ -117,8 +117,11 @@ filesystem.
After downloading a five-layer image using `docker pull ubuntu`, you can see
six directories under `/var/lib/docker/overlay2`.
> **Warning**: Do not directly manipulate any files or directories within
> **Warning**
>
> Don't directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.
{ .warning }
```console
$ ls -l /var/lib/docker/overlay2
@ -200,24 +203,17 @@ workdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/work)
The `rw` on the second line shows that the `overlay` mount is read-write.
OverlayFS layers multiple directories on a single Linux host and presents them as
a single directory. These directories are called _layers_ and the unification
process is referred to as a _union mount_. OverlayFS refers to the lower directory
as `lowerdirs` and the upper directory a `upperdir`. The unified view is exposed
through its own directory called `merged`.
The diagram below shows how a Docker image and a Docker container are layered.
The image layer is the `lowerdir` and the container layer is the `upperdir`.
If the image has multiple layers, multiple `lowerdir` directories are used.
The unified view is exposed through a directory called `merged` which is
effectively the containers mount point. The diagram shows how Docker constructs
map to OverlayFS constructs.
The following diagram shows how a Docker image and a Docker container are
layered. The image layer is the `lowerdir` and the container layer is the
`upperdir`. If the image has multiple layers, multiple `lowerdir` directories
are used. The unified view is exposed through a directory called `merged` which
is effectively the containers mount point.
![How Docker constructs map to OverlayFS constructs](images/overlay_constructs.webp)
Where the image layer and the container layer contain the same files, the
container layer "wins" and obscures the existence of the same files in the image
layer.
container layer (`upperdir`) takes precedence and obscures the existence of the
same files in the image layer.
To create a container, the `overlay2` driver combines the directory representing
the image's top layer plus a new directory for the container. The image's
@ -247,11 +243,14 @@ Status: Downloaded newer image for ubuntu:latest
#### The image layers
Each image layer has its own directory within `/var/lib/docker/overlay/`, which
contains its contents, as shown below. The image layer IDs do not correspond to
the directory IDs.
contains its contents, as shown in the following example. The image layer IDs
don't correspond to the directory IDs.
> **Warning**: Do not directly manipulate any files or directories within
> **Warning**
>
> Don't directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.
{ .warning }
```console
$ ls -l /var/lib/docker/overlay/
@ -265,8 +264,8 @@ drwx------ 3 root root 4096 Jun 20 16:11 edab9b5e5bf73f2997524eebeac1de4cf9c8b90
```
The image layer directories contain the files unique to that layer as well as
hard links to the data that is shared with lower layers. This allows for
efficient use of disk space.
hard links to the data shared with lower layers. This allows for efficient use
of disk space.
```console
$ ls -i /var/lib/docker/overlay2/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls
@ -312,7 +311,8 @@ comprises the view of the filesystem from within the running container.
The `work` directory is internal to OverlayFS.
To view the mounts which exist when you use the `overlay2` storage driver with
Docker, use the `mount` command. The output below is truncated for readability.
Docker, use the `mount` command. The following output is truncated for
readability.
```console
$ mount | grep overlay
@ -325,8 +325,8 @@ workdir=/var/lib/docker/overlay2/l/ec444863a55a.../work)
The `rw` on the second line shows that the `overlay` mount is read-write.
## How container reads and writes work with `overlay2`
<a name="how-container-reads-and-writes-work-with-overlay-or-overlay2"></a>
### Reading files
@ -334,100 +334,113 @@ The `rw` on the second line shows that the `overlay` mount is read-write.
Consider three scenarios where a container opens a file for read access with
overlay.
- **The file does not exist in the container layer**: If a container opens a
file for read access and the file does not already exist in the container
(`upperdir`) it is read from the image (`lowerdir`). This incurs very little
performance overhead.
#### The file does not exist in the container layer
- **The file only exists in the container layer**: If a container opens a file
for read access and the file exists in the container (`upperdir`) and not in
the image (`lowerdir`), it is read directly from the container.
If a container opens a file for read access and the file does not already exist
in the container (`upperdir`) it is read from the image (`lowerdir`). This
incurs very little performance overhead.
- **The file exists in both the container layer and the image layer**: If a
container opens a file for read access and the file exists in the image layer
and the container layer, the file's version in the container layer is read.
Files in the container layer (`upperdir`) obscure files with the same name in
the image layer (`lowerdir`).
#### The file only exists in the container layer
If a container opens a file for read access and the file exists in the
container (`upperdir`) and not in the image (`lowerdir`), it's read directly
from the container.
#### The file exists in both the container layer and the image layer
If a container opens a file for read access and the file exists in the image
layer and the container layer, the file's version in the container layer is
read. Files in the container layer (`upperdir`) obscure files with the same
name in the image layer (`lowerdir`).
### Modifying files or directories
Consider some scenarios where files in a container are modified.
- **Writing to a file for the first time**: The first time a container writes
to an existing file, that file does not exist in the container (`upperdir`).
The `overlay2` driver performs a *copy_up* operation to copy the file
from the image (`lowerdir`) to the container (`upperdir`). The container then
writes the changes to the new copy of the file in the container layer.
#### Writing to a file for the first time
However, OverlayFS works at the file level rather than the block level. This
means that all OverlayFS copy_up operations copy the entire file, even if the
file is very large and only a small part of it is being modified. This can
have a noticeable impact on container write performance. However, two things
are worth noting:
The first time a container writes to an existing file, that file does not
exist in the container (`upperdir`). The `overlay2` driver performs a
`copy_up` operation to copy the file from the image (`lowerdir`) to the
container (`upperdir`). The container then writes the changes to the new copy
of the file in the container layer.
- The copy_up operation only occurs the first time a given file is written
to. Subsequent writes to the same file operate against the copy of the file
already copied up to the container.
However, OverlayFS works at the file level rather than the block level. This
means that all OverlayFS `copy_up` operations copy the entire file, even if
the file is large and only a small part of it's being modified. This can have
a noticeable impact on container write performance. However, two things are
worth noting:
- OverlayFS works with multiple layers. This means that performance can be
impacted when searching for files in images with many layers.
- The `copy_up` operation only occurs the first time a given file is written
to. Subsequent writes to the same file operate against the copy of the file
already copied up to the container.
- **Deleting files and directories**:
- OverlayFS works with multiple layers. This means that performance can be
impacted when searching for files in images with many layers.
- When a _file_ is deleted within a container, a *whiteout* file is created in
the container (`upperdir`). The version of the file in the image layer
(`lowerdir`) is not deleted (because the `lowerdir` is read-only). However,
the whiteout file prevents it from being available to the container.
#### Deleting files and directories
- When a _directory_ is deleted within a container, an _opaque directory_ is
created within the container (`upperdir`). This works in the same way as a
whiteout file and effectively prevents the directory from being accessed,
even though it still exists in the image (`lowerdir`).
- When a _file_ is deleted within a container, a _whiteout_ file is created in
the container (`upperdir`). The version of the file in the image layer
(`lowerdir`) is not deleted (because the `lowerdir` is read-only). However,
the whiteout file prevents it from being available to the container.
- **Renaming directories**: Calling `rename(2)` for a directory is allowed only
when both the source and the destination path are on the top layer.
Otherwise, it returns `EXDEV` error ("cross-device link not permitted").
Your application needs to be designed to handle `EXDEV` and fall back to a
"copy and unlink" strategy.
- When a _directory_ is deleted within a container, an _opaque directory_ is
created within the container (`upperdir`). This works in the same way as a
whiteout file and effectively prevents the directory from being accessed,
even though it still exists in the image (`lowerdir`).
#### Renaming directories
Calling `rename(2)` for a directory is allowed only when both the source and
the destination path are on the top layer. Otherwise, it returns `EXDEV` error
("cross-device link not permitted"). Your application needs to be designed to
handle `EXDEV` and fall back to a "copy and unlink" strategy.
## OverlayFS and Docker Performance
The `overlay2` driver is more performant than `devicemapper`. In certain circumstances,
`overlay2` may perform better than `btrfs` as well. However, be aware of the following details.
`overlay2` may perform better than `btrfs`. However, be aware of the following details:
- **Page Caching**. OverlayFS supports page cache sharing. Multiple containers
accessing the same file share a single page cache entry for that file. This
makes the `overlay2` drivers efficient with memory and a good
option for high-density use cases such as PaaS.
### Page caching
- **copy_up**. As with other copy-on-write filesystems, OverlayFS performs copy-up operations
whenever a container writes to a file for the first time. This can add latency
into the write operation, especially for large files. However, once the file
has been copied up, all subsequent writes to that file occur in the upper
layer, without the need for further copy-up operations.
OverlayFS supports page cache sharing. Multiple containers accessing the same
file share a single page cache entry for that file. This makes the `overlay2`
drivers efficient with memory and a good option for high-density use cases such
as PaaS.
### Copyup
As with other copy-on-write filesystems, OverlayFS performs copy-up operations
whenever a container writes to a file for the first time. This can add latency
into the write operation, especially for large files. However, once the file
has been copied up, all subsequent writes to that file occur in the upper
layer, without the need for further copy-up operations.
### Performance best practices
The following generic performance best practices apply to OverlayFS.
- **Use fast storage**: Solid-state drives (SSDs) provide faster reads and
writes than spinning disks.
#### Use fast storage
- **Use volumes for write-heavy workloads**: Volumes provide the best and most
predictable performance for write-heavy workloads. This is because they bypass
the storage driver and do not incur any of the potential overheads introduced
by thin provisioning and copy-on-write. Volumes have other benefits, such as
allowing you to share data among containers and persisting your data even if
no running container is using them.
Solid-state drives (SSDs) provide faster reads and writes than spinning disks.
#### Use volumes for write-heavy workloads
Volumes provide the best and most predictable performance for write-heavy
workloads. This is because they bypass the storage driver and don't incur any
of the potential overheads introduced by thin provisioning and copy-on-write.
Volumes have other benefits, such as allowing you to share data among
containers and persisting your data even if no running container is using them.
## Limitations on OverlayFS compatibility
To summarize the OverlayFS's aspect which is incompatible with other
filesystems:
- **open(2)**: OverlayFS only implements a subset of the POSIX standards.
[`open(2)`](https://linux.die.net/man/2/open)
: OverlayFS only implements a subset of the POSIX standards.
This can result in certain OverlayFS operations breaking POSIX standards. One
such operation is the *copy-up* operation. Suppose that your application calls
such operation is the copy-up operation. Suppose that your application calls
`fd1=open("foo", O_RDONLY)` and then `fd2=open("foo", O_RDWR)`. In this case,
your application expects `fd1` and `fd2` to refer to the same file. However, due
to a copy-up operation that occurs after the second calling to `open(2)`, the
@ -444,6 +457,7 @@ filesystems:
before running `yum install`. This package implements the `touch` workaround
referenced above for `yum`.
- **rename(2)**: OverlayFS does not fully support the `rename(2)` system call.
Your application needs to detect its failure and fall back to a "copy and
unlink" strategy.
[`rename(2)`](https://linux.die.net/man/2/rename)
: OverlayFS does not fully support the `rename(2)` system call. Your
application needs to detect its failure and fall back to a "copy and unlink"
strategy.

View File

@ -3,9 +3,9 @@ title: Docker storage drivers
description: Learn how to select the proper storage driver for your container.
keywords: container, storage, driver, btrfs, devicemapper, zfs, overlay, overlay2
aliases:
- /engine/userguide/storagedriver/
- /engine/userguide/storagedriver/selectadriver/
- /storage/storagedriver/selectadriver/
- /engine/userguide/storagedriver/
- /engine/userguide/storagedriver/selectadriver/
- /storage/storagedriver/selectadriver/
---
Ideally, very little data is written to a container's writable layer, and you
@ -18,15 +18,15 @@ storage driver controls how images and containers are stored and managed on your
Docker host. After you have read the [storage driver overview](index.md), the
next step is to choose the best storage driver for your workloads. Use the storage
driver with the best overall performance and stability in the most usual scenarios.
The Docker Engine provides the following storage drivers on Linux:
| Driver | Description |
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `overlay2` | `overlay2` is the preferred storage driver for all currently supported Linux distributions, and requires no extra configuration. |
| `fuse-overlayfs` | `fuse-overlayfs`is preferred only for running Rootless Docker on a host that does not provide support for rootless `overlay2`. On Ubuntu and Debian 10, the `fuse-overlayfs` driver does not need to be used, and `overlay2` works even in rootless mode. Refer to the [rootless mode documentation](../../engine/security/rootless.md) for details. |
| `btrfs` and `zfs` | The `btrfs` and `zfs` storage drivers allow for advanced options, such as creating "snapshots", but require more maintenance and setup. Each of these relies on the backing filesystem being configured correctly. |
| `vfs` | The `vfs` storage driver is intended for testing purposes, and for situations where no copy-on-write filesystem can be used. Performance of this storage driver is poor, and is not generally recommended for production use. |
| Driver | Description |
| ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `overlay2` | `overlay2` is the preferred storage driver for all currently supported Linux distributions, and requires no extra configuration. |
| `fuse-overlayfs` | `fuse-overlayfs`is preferred only for running Rootless Docker on a host that does not provide support for rootless `overlay2`. On Ubuntu and Debian 10, the `fuse-overlayfs` driver does not need to be used, and `overlay2` works even in rootless mode. Refer to the [rootless mode documentation](../../engine/security/rootless.md) for details. |
| `btrfs` and `zfs` | The `btrfs` and `zfs` storage drivers allow for advanced options, such as creating "snapshots", but require more maintenance and setup. Each of these relies on the backing filesystem being configured correctly. |
| `vfs` | The `vfs` storage driver is intended for testing purposes, and for situations where no copy-on-write filesystem can be used. Performance of this storage driver is poor, and is not generally recommended for production use. |
| `devicemapper` ([deprecated](../../../engine/deprecated.md#device-mapper-storage-driver)) | The `devicemapper` storage driver requires `direct-lvm` for production environments, because `loopback-lvm`, while zero-configuration, has very poor performance. `devicemapper` was the recommended storage driver for CentOS and RHEL, as their kernel version did not support `overlay2`. However, current versions of CentOS and RHEL now have support for `overlay2`, which is now the recommended driver. |
<!-- markdownlint-disable reference-links-images -->
@ -40,32 +40,32 @@ can see the order in the [source code for Docker Engine {{% param "docker_ce_ver
<!-- markdownlint-enable reference-links-images -->
Some storage drivers require you to use a specific format for the backing filesystem.
If you have external requirements to use a specific backing filesystem, this may
If you have external requirements to use a specific backing filesystem, this may
limit your choices. See [Supported backing filesystems](#supported-backing-filesystems).
After you have narrowed down which storage drivers you can choose from, your choice
is determined by the characteristics of your workload and the level of stability
is determined by the characteristics of your workload and the level of stability
you need. See [Other considerations](#other-considerations) for help in making
the final decision.
## Supported storage drivers per Linux distribution
> Docker Desktop, and Docker in Rootless mode
> **Note**
>
> Modifying the storage-driver is not supported on Docker Desktop for Mac and
> Docker Desktop for Windows, and only the default storage driver can be used.
> The comparison table below is also not applicable for Rootless mode. For the
> drivers available in rootless mode, see the [Rootless mode documentation](../../engine/security/rootless.md).
> Modifying the storage driver by editing the daemon configuration file isn't
> supported on Docker Desktop. Only the default `overlay2` driver or the
> [containerd storage](../../desktop/containerd.md) are supported. The
> following table is also not applicable for the Docker Engine in rootless
> mode. For the drivers available in rootless mode, see the [Rootless mode
> documentation](../../engine/security/rootless.md).
Your operating system and kernel may not support every storage driver. For
instance, `aufs` is only supported on Ubuntu and Debian, and may require extra
packages to be installed, while `btrfs` is only supported if your system uses
`btrfs` as storage. In general, the following configurations work on recent
versions of the Linux distribution:
example, `btrfs` is only supported if your system uses `btrfs` as storage. In
general, the following configurations work on recent versions of the Linux
distribution:
| Linux distribution | Recommended storage drivers | Alternative drivers |
|:-------------------|:----------------------------|:------------------------------|
| :----------------- | :-------------------------- | :---------------------------- |
| Ubuntu | `overlay2` | `devicemapper`¹, `zfs`, `vfs` |
| Debian | `overlay2` | `devicemapper`¹, `vfs` |
| CentOS | `overlay2` | `devicemapper`¹, `zfs`, `vfs` |
@ -89,7 +89,7 @@ Before using the `vfs` storage driver, be sure to read about
The recommendations in the table above are known to work for a large number of
users. If you use a recommended configuration and find a reproducible issue,
it is likely to be fixed very quickly. If the driver that you want to use is
it's likely to be fixed very quickly. If the driver that you want to use is
not recommended according to this table, you can run it at your own risk. You
can and should still report any issues you run into. However, such issues
have a lower priority than issues encountered when using a recommended
@ -108,7 +108,7 @@ With regard to Docker, the backing filesystem is the filesystem where
backing filesystems.
| Storage driver | Supported backing filesystems |
|:-----------------|:------------------------------|
| :--------------- | :---------------------------- |
| `overlay2` | `xfs` with ftype=1, `ext4` |
| `fuse-overlayfs` | any filesystem |
| `devicemapper` | `direct-lvm` |
@ -137,10 +137,10 @@ in the documentation for each storage driver.
### Shared storage systems and the storage driver
If your enterprise uses SAN, NAS, hardware RAID, or other shared storage
systems, they may provide high availability, increased performance, thin
If you use SAN, NAS, hardware RAID, or other shared storage systems, those
systems may provide high availability, increased performance, thin
provisioning, deduplication, and compression. In many cases, Docker can work on
top of these storage systems, but Docker does not closely integrate with them.
top of these storage systems, but Docker doesn't closely integrate with them.
Each Docker storage driver is based on a Linux filesystem or volume manager. Be
sure to follow existing best practices for operating your storage driver
@ -186,9 +186,9 @@ driver. Some drivers require additional configuration, including configuration
to physical or logical disks on the Docker host.
> **Important**
>
>
> When you change the storage driver, any existing images and containers become
> inaccessible. This is because their layers cannot be used by the new storage
> inaccessible. This is because their layers can't be used by the new storage
> driver. If you revert your changes, you can access the old images and containers
> again, but any that you pulled or created using the new driver are then
> inaccessible.
@ -196,8 +196,8 @@ to physical or logical disks on the Docker host.
## Related information
* [About images, containers, and storage drivers](index.md)
* [`devicemapper` storage driver in practice](device-mapper-driver.md)
* [`overlay2` storage driver in practice](overlayfs-driver.md)
* [`btrfs` storage driver in practice](btrfs-driver.md)
* [`zfs` storage driver in practice](zfs-driver.md)
- [About images, containers, and storage drivers](index.md)
- [`devicemapper` storage driver in practice](device-mapper-driver.md)
- [`overlay2` storage driver in practice](overlayfs-driver.md)
- [`btrfs` storage driver in practice](btrfs-driver.md)
- [`zfs` storage driver in practice](zfs-driver.md)

View File

@ -6,7 +6,7 @@ aliases:
- /engine/userguide/storagedriver/vfs-driver/
---
The VFS storage driver is not a union filesystem; instead, each layer is a
The VFS storage driver isn't a union filesystem. Each layer is a
directory on disk, and there is no copy-on-write support. To create a new
layer, a "deep copy" is done of the previous layer. This leads to lower
performance and more space used on disk than other storage drivers. However, it
@ -21,7 +21,7 @@ mechanism to verify other storage back-ends against, in a testing environment.
$ sudo systemctl stop docker
```
2. Edit `/etc/docker/daemon.json`. If it does not yet exist, create it. Assuming
2. Edit `/etc/docker/daemon.json`. If it doesn't yet exist, create it. Assuming
that the file was empty, add the following contents.
```json
@ -40,7 +40,7 @@ mechanism to verify other storage back-ends against, in a testing environment.
}
```
Docker does not start if the `daemon.json` file contains badly-formed JSON.
Docker doesn't start if the `daemon.json` file contains invalid JSON.
3. Start Docker.
@ -62,16 +62,15 @@ Docker is now using the `vfs` storage driver. Docker has automatically
created the `/var/lib/docker/vfs/` directory, which contains all the layers
used by running containers.
## How the `vfs` storage driver works
VFS is not a union filesystem. Instead, each image layer and the writable
container layer are represented on the Docker host as subdirectories within
`/var/lib/docker/`. The union mount provides the unified view of all layers. The
directory names do not directly correspond to the IDs of the layers themselves.
Each image layer and the writable container layer are represented on the Docker
host as subdirectories within `/var/lib/docker/`. The union mount provides the
unified view of all layers. The directory names don't directly correspond to
the IDs of the layers themselves.
VFS does not support copy-on-write (COW), so each time a new layer is created,
it is a deep copy of its parent layer. These layers are all located under
VFS doesn't support copy-on-write (COW). Each time a new layer is created,
it's a deep copy of its parent layer. These layers are all located under
`/var/lib/docker/vfs/dir/`.
### Example: Image and container on-disk constructs
@ -122,12 +121,12 @@ $ du -sh /var/lib/docker/vfs/dir/*
104M /var/lib/docker/vfs/dir/e92be7a4a4e3ccbb7dd87695bca1a0ea373d4f673f455491b1342b33ed91446b
```
The above output shows that three layers each take 104M and two take 125M. These
directories have only small differences from each other, but take up nearly the
same amount of room on disk. This is one of the disadvantages of using the
`vfs` storage driver.
The above output shows that three layers each take 104M and two take 125M.
These directories have only small differences from each other, but they all
consume the same amount of disk space. This is one of the disadvantages of
using the `vfs` storage driver.
## Related information
- [Understand images, containers, and storage drivers](index.md)
- [Select a storage driver](select-storage-driver.md)
- [Select a storage driver](select-storage-driver.md)