rewrite storage-driver section

- Reduce use of "Community Edition", and some sections that were written
  for Docker Enterprise.
- Add notes about deprecation of AuFS in the overview.
- Update the storage driver index page to use BuildKit, and rephrase some
  bits that made assumptions about each Dockerfile instruction producing
  a new layer.
- Updated some examples to be usable on Docker Desktop, which does not
  provide direct access to the daemon's storage directoreis.
- Add some notes linking to relevant sections about formatting output.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2021-07-28 12:17:13 +02:00
parent 74cb51dcc3
commit f5e49b158b
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
2 changed files with 342 additions and 254 deletions

View File

@ -14,14 +14,22 @@ stores images, and how these images are used by containers. You can use this
information to make informed choices about the best way to persist data from information to make informed choices about the best way to persist data from
your applications and avoid performance problems along the way. your applications and avoid performance problems along the way.
Storage drivers allow you to create data in the writable layer of your container. ## Storage drivers versus Docker volumes
The files won't be persisted after the container is deleted, and both read and
write speeds are lower than native file system performance.
> **Note**: Operations that are known to be problematic include write-intensive database storage, Docker uses storage drivers to store image layers, and to store data in the
particularly when pre-existing data exists in the read-only layer. More details are provided in this document. writable layer of a container. The container's writable layer does not 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
performance, especially for storage drivers that a use copy-on-write filesystem.
Write-intensive applications, such as database storage, are impacted by a
performance overhead, particularly if pre-existing data exists in the read-only
layer.
[Learn how to use volumes](../volumes.md) to persist data and improve performance. Use Docker volumes for write-intensive data, data that must persist beyond the
container's lifespan, and data that must be shared between containers. Refer to
the [volumes section](../volumes.md) to learn how to use volumes to persist data
and improve performance.
## Images and layers ## Images and layers
@ -32,24 +40,37 @@ read-only. Consider the following Dockerfile:
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ubuntu:18.04 FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app COPY . /app
RUN make /app RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py CMD python /app/app.py
``` ```
This Dockerfile contains four commands, each of which creates a layer. The This Dockerfile contains four commands. Commands that modify the filesystem create
`FROM` statement starts out by creating a layer from the `ubuntu:18.04` image. a layer. The`FROM` statement starts out by creating a layer from the `ubuntu:18.04`
The `COPY` command adds some files from your Docker client's current directory. image. The `LABEL` command only modifies the image's metadata, and does not produce
The `RUN` command builds your application using the `make` command. Finally, a new layer. The `COPY` command adds some files from your Docker client's current
the last layer specifies what command to run within the container. 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.
Each layer is only a set of differences from the layer before it. The layers are Each layer is only a set of differences from the layer before it. Note that both
stacked on top of each other. When you create a new container, you add a new _adding_, and _removing_ files will result in a new layer. In the example above,
writable layer on top of the underlying layers. This layer is often called the the `$HOME/.cache` directory is removed, but will still be available in the
"container layer". All changes made to the running container, such as writing previous layer and add up to the image's total size. Refer to the
new files, modifying existing files, and deleting files, are written to this thin [Best practices for writing Dockerfiles](../../develop/develop-images/dockerfile_best-practices.md)
writable container layer. The diagram below shows a container based on the Ubuntu and [use multi-stage builds](../../develop/develop-images/multistage-build.md)
15.04 image. sections to learn how to optimize your Dockerfiles for efficient images.
The layers are stacked on top of each other. When you create a new container,
you add a new writable layer on top of the underlying layers. This layer is often
called the "container layer". All changes made to the running container, such as
writing new files, modifying existing files, and deleting files, are written to
this thin writable container layer. The diagram below shows a container based
on an `ubuntu:15.04` image.
![Layers of a container based on the Ubuntu image](images/container-layers.jpg) ![Layers of a container based on the Ubuntu image](images/container-layers.jpg)
@ -71,15 +92,18 @@ multiple containers sharing the same Ubuntu 15.04 image.
![Containers sharing same image](images/sharing-layers.jpg) ![Containers sharing same image](images/sharing-layers.jpg)
> **Note**: If you need multiple images to have shared access to the exact
> same data, store this data in a Docker volume and mount it into your
> containers.
Docker uses storage drivers to manage the contents of the image layers and the Docker uses storage drivers to manage the contents of the image layers and the
writable container layer. Each storage driver handles the implementation writable container layer. Each storage driver handles the implementation
differently, but all drivers use stackable image layers and the copy-on-write differently, but all drivers use stackable image layers and the copy-on-write
(CoW) strategy. (CoW) strategy.
> **Note**
>
> Use Docker volumes if you need multiple containers to have shared access to
> the exact same data. Refer to the [volumes section](../volumes.md) to learn
> about volumes.
## Container size on disk ## Container size on disk
To view the approximate size of a running container, you can use the `docker ps -s` To view the approximate size of a running container, you can use the `docker ps -s`
@ -87,7 +111,6 @@ 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 is used for the writable layer of
each container. each container.
- `virtual size`: the amount of data used for the read-only image data - `virtual size`: the amount of data used for the read-only image data
used by the container plus the container's writable layer `size`. used by the container plus the container's writable layer `size`.
Multiple containers may share some or all read-only Multiple containers may share some or all read-only
@ -106,9 +129,9 @@ these containers would be SUM (`size` of containers) plus one image size
This also does not count the following additional ways a container can take up This also does not count the following additional ways a container can take up
disk space: disk space:
- Disk space used for log files if you use the `json-file` logging driver. This - Disk space used for log files stored by the [logging-driver](../../config/containers/logging/index.md).
can be non-trivial if your container generates a large amount of logging data This can be non-trivial if your container generates a large amount of logging
and log rotation is not configured. data and log rotation is not configured.
- Volumes and bind mounts used by the container. - Volumes and bind mounts used by the container.
- Disk space used for the container's configuration files, which are typically - Disk space used for the container's configuration files, which are typically
small. small.
@ -133,7 +156,7 @@ 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 usually `/var/lib/docker/` on Linux hosts. You can see these layers being pulled
in this example: in this example:
```bash ```console
$ docker pull ubuntu:18.04 $ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu 18.04: Pulling from library/ubuntu
f476d66f5408: Pull complete f476d66f5408: Pull complete
@ -149,7 +172,7 @@ local storage area. To examine the layers on the filesystem, list the contents
of `/var/lib/docker/<storage-driver>`. This example uses the `overlay2` of `/var/lib/docker/<storage-driver>`. This example uses the `overlay2`
storage driver: storage driver:
```bash ```console
$ ls /var/lib/docker/overlay2 $ ls /var/lib/docker/overlay2
16802227a96c24dcbeab5b37821e2b67a9f921749cd9a2e386d5a6d5bc6fc6d3 16802227a96c24dcbeab5b37821e2b67a9f921749cd9a2e386d5a6d5bc6fc6d3
377d73dbb466e0bc7c9ee23166771b35ebdbe02ef17753d79fd3571d4ce659d7 377d73dbb466e0bc7c9ee23166771b35ebdbe02ef17753d79fd3571d4ce659d7
@ -158,16 +181,15 @@ ec1ec45792908e90484f7e629330666e7eee599f08729c93890a7205a6ba35f5
l l
``` ```
The directory names do not correspond to the layer IDs (this has been true since The directory names do not correspond to the layer IDs.
Docker 1.10).
Now imagine that you have two different Dockerfiles. You use the first one to Now imagine that you have two different Dockerfiles. You use the first one to
create an image called `acme/my-base-image:1.0`. create an image called `acme/my-base-image:1.0`.
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ubuntu:18.04 FROM alpine
COPY . /app RUN apk add --no-cache bash
``` ```
The second one is based on `acme/my-base-image:1.0`, but has some additional The second one is based on `acme/my-base-image:1.0`, but has some additional
@ -176,16 +198,18 @@ layers:
```dockerfile ```dockerfile
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM acme/my-base-image:1.0 FROM acme/my-base-image:1.0
COPY . /app
RUN chmod +x /app/hello.sh
CMD /app/hello.sh CMD /app/hello.sh
``` ```
The second image contains all the layers from the first image, plus a new layer The second image contains all the layers from the first image, plus new layers
with the `CMD` instruction, and a read-write container layer. Docker already created by the `COPY` and `RUN` instructions, and a read-write container layer.
has all the layers from the first image, so it does not need to pull them again. Docker already has all the layers from the first image, so it does not need to
The two images share any layers they have in common. 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 If you build images from the two Dockerfiles, you can use `docker image ls` and
`docker history` commands to verify that the cryptographic IDs of the shared `docker image history` commands to verify that the cryptographic IDs of the shared
layers are the same. 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.
@ -193,16 +217,10 @@ layers are the same.
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 ```bash
#!/bin/sh #!/usr/bin/env bash
echo "Hello world" echo "Hello world"
``` ```
Save the file, and make it executable:
```bash
chmod +x hello.sh
```
3. Copy the contents of the first Dockerfile above into a new file called 3. Copy the contents of the first Dockerfile above into a new file called
`Dockerfile.base`. `Dockerfile.base`.
@ -215,14 +233,23 @@ layers are the same.
```console ```console
$ docker build -t acme/my-base-image:1.0 -f Dockerfile.base . $ docker build -t acme/my-base-image:1.0 -f Dockerfile.base .
Sending build context to Docker daemon 812.4MB [+] Building 6.0s (11/11) FINISHED
Step 1/2 : FROM ubuntu:18.04 => [internal] load build definition from Dockerfile.base 0.4s
---> d131e0fa2585 => => transferring dockerfile: 116B 0.0s
Step 2/2 : COPY . /app => [internal] load .dockerignore 0.3s
---> Using cache => => transferring context: 2B 0.0s
---> bd09118bcef6 => resolve image config for docker.io/docker/dockerfile:1 1.5s
Successfully built bd09118bcef6 => [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
Successfully tagged acme/my-base-image:1.0 => 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.
@ -230,15 +257,25 @@ layers are the same.
```console ```console
$ docker build -t acme/my-final-image:1.0 -f Dockerfile . $ docker build -t acme/my-final-image:1.0 -f Dockerfile .
Sending build context to Docker daemon 4.096kB [+] Building 3.6s (12/12) FINISHED
Step 1/2 : FROM acme/my-base-image:1.0 => [internal] load build definition from Dockerfile 0.1s
---> bd09118bcef6 => => transferring dockerfile: 156B 0.0s
Step 2/2 : CMD /app/hello.sh => [internal] load .dockerignore 0.1s
---> Running in a07b694759ba => => transferring context: 2B 0.0s
---> dbf995fc07ff => resolve image config for docker.io/docker/dockerfile:1 0.5s
Removing intermediate container a07b694759ba => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
Successfully built dbf995fc07ff => [internal] load .dockerignore 0.0s
Successfully tagged acme/my-final-image:1.0 => [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:
@ -246,47 +283,99 @@ layers are the same.
```console ```console
$ docker image ls $ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE REPOSITORY TAG IMAGE ID CREATED SIZE
acme/my-final-image 1.0 dbf995fc07ff 58 seconds ago 103MB acme/my-final-image 1.0 8bd85c42fa7f About a minute ago 7.75MB
acme/my-base-image 1.0 bd09118bcef6 3 minutes ago 103MB acme/my-base-image 1.0 da3cf8df55ee 2 minutes ago 7.75MB
``` ```
8. Check out the layers that comprise each image: 8. Check out the history of each image:
```console ```console
$ docker history bd09118bcef6 $ docker image history acme/my-base-image:1.0
IMAGE CREATED CREATED BY SIZE COMMENT
bd09118bcef6 4 minutes ago /bin/sh -c #(nop) COPY dir:35a7eb158c1504e... 100B IMAGE CREATED CREATED BY SIZE COMMENT
d131e0fa2585 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B da3cf8df55ee 5 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 3 months ago /bin/sh -c mkdir -p /run/systemd && echo '... 7B <missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 3 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 2.78kB <missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
<missing> 3 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 3 months ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 745B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:eef57983bd66e3a... 103MB
``` ```
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.
```console ```console
$ docker history dbf995fc07ff $ docker image history acme/my-final-image:1.0
IMAGE CREATED CREATED BY SIZE COMMENT IMAGE CREATED CREATED BY SIZE COMMENT
dbf995fc07ff 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/a... 0B 8bd85c42fa7f 3 minutes ago CMD ["/bin/sh" "-c" "/app/hello.sh"] 0B buildkit.dockerfile.v0
bd09118bcef6 5 minutes ago /bin/sh -c #(nop) COPY dir:35a7eb158c1504e... 100B <missing> 3 minutes ago RUN /bin/sh -c chmod +x /app/hello.sh # buil… 39B buildkit.dockerfile.v0
d131e0fa2585 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 3 minutes ago COPY . /app # buildkit 222B buildkit.dockerfile.v0
<missing> 3 months ago /bin/sh -c mkdir -p /run/systemd && echo '... 7B <missing> 4 minutes ago RUN /bin/sh -c apk add --no-cache bash # bui… 2.15MB buildkit.dockerfile.v0
<missing> 3 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 2.78kB <missing> 7 weeks ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 3 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 7 weeks ago /bin/sh -c #(nop) ADD file:f278386b0cef68136… 5.6MB
<missing> 3 months ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 745B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:eef57983bd66e3a... 103MB
``` ```
Notice that all the layers are identical except the top layer of the second Notice that all steps of the first image are also included in the final
image. All the other layers are shared between the two images, and are only image. The final image includes the two layers from the first image, and
stored once in `/var/lib/docker/`. The new layer actually doesn't take any two layers that were added in the second image.
room at all, because it is not changing any files, but only running a command.
> **Note**: The `<missing>` lines in the `docker history` output indicate > What are the `<missing>` steps?
> that those layers were built on another system and are not available >
> locally. This can be ignored. > 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 [build images with BuildKit](../../develop/develop-images/build_enhancements.md)
> to learn more about other enhancements made in BuildKit.
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:
{% raw %}
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-final-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a"
]
```
{% endraw %}
{% raw %}
```console
$ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-base-image:1.0
[
"sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
"sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a",
"sha256:cc644054967e516db4689b5282ee98e4bc4b11ea2255c9630309f559ab96562e",
"sha256:e84fb818852626e89a09f5143dbc31fe7f0e0a6a24cd8d2eb68062b904337af4"
]
```
{% endraw %}
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/){: target="_blank" rel="noopener" class="_" }
> for readability.
### Copying makes containers efficient ### Copying makes containers efficient
@ -297,16 +386,14 @@ 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 When an existing file in a container is modified, the storage driver performs a
copy-on-write operation. The specifics steps involved depend on the specific copy-on-write operation. The specifics steps involved depend on the specific
storage driver. For the `aufs`, `overlay`, and `overlay2` drivers, the storage driver. For the `overlay2`, `overlay`, and `aufs` drivers, the
copy-on-write operation follows this rough sequence: copy-on-write operation follows this rough sequence:
* Search through the image layers for the file to update. The process starts * 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. 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. 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 * Perform a `copy_up` operation on the first copy of the file that is found, to
copy the file to the container's writable layer. 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 cannot
see the read-only copy of the file that exists in the lower layer. see the read-only copy of the file that exists in the lower layer.
@ -316,13 +403,20 @@ descriptions.
Containers that write a lot of data consume more space than containers 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 do not. This is because most write operations consume new space in the
container's thin writable top layer. 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.
> **Note**: for write-heavy applications, you should not store the data in > Tip: Use volumes for write-heavy applications
> the container. Instead, use Docker volumes, which are independent of the >
> running container and are designed to be efficient for I/O. In addition, > For write-heavy applications, you should not store the data in the container.
> volumes can be shared among containers and do not increase the size of your > Applications, such as write-intensive database storage, are known to be
> container's writable layer. > 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.
A `copy_up` operation can incur a noticeable performance overhead. This overhead A `copy_up` operation can incur a noticeable performance overhead. This overhead
is different depending on which storage driver is in use. Large files, is different depending on which storage driver is in use. Large files,
@ -334,72 +428,107 @@ 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 containers based on the `acme/my-final-image:1.0` image we built earlier and
examines how much room they take up. examines how much room they take up.
> **Note**: This procedure doesn't work on Docker Desktop for Mac or Docker Desktop for Windows.
1. From a terminal on your Docker host, run the following `docker run` commands. 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. The strings at the end are the IDs of each container.
```bash ```console
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \ $ 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_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_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_4 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_5 acme/my-final-image:1.0 bash && docker run -dit --name my_container_5 acme/my-final-image:1.0 bash
c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409 40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513 a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c 3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544 939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765 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 to verify the 5 containers are running. {% raw %}
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
```bash CONTAINER ID IMAGE NAMES SIZE
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cddae31c314f acme/my-final-image:1.0 my_container_5 0B (virtual 7.75MB)
1a174fc216cc acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_5 939b3bf9e7ec acme/my-final-image:1.0 my_container_4 0B (virtual 7.75MB)
38fa94212a41 acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_4 3ed3c1a10430 acme/my-final-image:1.0 my_container_3 0B (virtual 7.75MB)
1e7264576d78 acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_3 a5ff32e2b551 acme/my-final-image:1.0 my_container_2 0B (virtual 7.75MB)
dcad7101795e acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_2 40ebdd763416 acme/my-final-image:1.0 my_container_1 0B (virtual 7.75MB)
c36785c423ec acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_1
``` ```
{% endraw %}
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.
3. List the contents of the local storage area. > 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 my 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.
```bash 3. Per-container storage
$ sudo ls /var/lib/docker/containers
1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765 To demonstrate this, run the following command to write the word 'hello' to
1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c a file on the container's writable layer in containers `my_container_1`,
38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544 `my_container_2`, and `my_container_3`:
c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513 ```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.
4. Now check out their sizes: {% raw %}
```console
$ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"
```bash CONTAINER ID IMAGE NAMES SIZE
$ sudo du -sh /var/lib/docker/containers/* 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)
32K /var/lib/docker/containers/1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765 3ed3c1a10430 acme/my-final-image:1.0 my_container_3 5B (virtual 7.75MB)
32K /var/lib/docker/containers/1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c a5ff32e2b551 acme/my-final-image:1.0 my_container_2 5B (virtual 7.75MB)
32K /var/lib/docker/containers/38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544 40ebdd763416 acme/my-final-image:1.0 my_container_1 5B (virtual 7.75MB)
32K /var/lib/docker/containers/c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
32K /var/lib/docker/containers/dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513
``` ```
{% endraw %}
Each of these containers only takes up 32k of space on the filesystem. 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
Not only does copy-on-write save space, but it also reduces start-up time. start-up time. When you create a container (or multiple containers from the same
When you start a container (or multiple containers from the same image), Docker image), Docker only needs to create the thin writable container layer.
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 If Docker had to make an entire copy of the underlying image stack each time it
started a new container, container start times and disk space used would be 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 significantly increased. This would be similar to the way that virtual machines
work, with one or more virtual disks per virtual machine. 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
driver, a full copy of the image's data is created for each container.
## Related information ## Related information

View File

@ -13,90 +13,63 @@ use Docker volumes to write data. However, some workloads require you to be able
to write to the container's writable layer. This is where storage drivers come to write to the container's writable layer. This is where storage drivers come
in. in.
Docker supports several different storage drivers, using a pluggable Docker supports several storage drivers, using a pluggable architecture. The
architecture. The storage driver controls how images and containers are stored storage driver controls how images and containers are stored and managed on your
and managed on your Docker host. 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
After you have read the [storage driver overview](index.md), the driver with the best overall performance and stability in the most usual scenarios.
next step is to choose the best storage driver for your workloads. In making
this decision, there are three high-level factors to consider:
If multiple storage drivers are supported in your kernel, Docker has a prioritized
list of which storage driver to use if no storage driver is explicitly configured,
assuming that the storage driver meets the prerequisites.
Use the storage driver with the best overall performance and stability in the most
usual scenarios.
Docker supports the following storage drivers: The Docker Engine provides the following storage drivers on Linux:
* `overlay2` is the preferred storage driver, for all currently supported | Driver | Description |
Linux distributions, and requires no extra configuration. |--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
* `aufs` was the preferred storage driver for Docker 18.06 and older, when | `overlay2` | `overlay2` is the preferred storage driver for all currently supported Linux distributions, and requires no extra configuration. |
running on Ubuntu 14.04 on kernel 3.13 which had no support for `overlay2`. | `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. |
* `fuse-overlayfs` is preferred only for running Rootless Docker | `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. |
on a host that does not provide support for rootless `overlay2`. | `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. |
On Ubuntu and Debian 10, the `fuse-overlayfs` driver does not need to be | `aufs` | The `aufs` storage driver Was the preferred storage driver for Docker 18.06 and older, when running on Ubuntu 14.04 on kernel 3.13 which had no support for `overlay2`. However, current versions of Ubuntu and Debian now have support for `overlay2`, which is now the recommended driver. |
used `overlay2` works even in rootless mode. | `devicemapper` | 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. |
See [Rootless mode documentation](../../engine/security/rootless.md). | `overlay` | The legacy `overlay` driver was used for kernels that did not support the "multiple-lowerdir" feature required for `overlay2` All currently supported Linux distributions now provide support for this, and it is therefore deprecated. |
* `devicemapper` is supported, but 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.
* The `btrfs` and `zfs` storage drivers are used if they are the backing
filesystem (the filesystem of the host on which Docker is installed).
These filesystems 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.
* 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.
Docker's source code defines the selection order. You can see the order at The Docker Engine has a prioritized list of which storage driver to use if no
[the source code for Docker Engine {{ site.docker_ce_version }}](https://github.com/moby/moby/blob/{{ site.docker_ce_version }}/daemon/graphdriver/driver_linux.go#L52-L53) storage driver is explicitly configured, assuming that the storage driver meets
the prerequisites, and automatically selects a compatible storage driver. You
If you run a different version of Docker, you can use the branch selector at the top of the file viewer to choose a different branch. can see the order in the [source code for Docker Engine {{ site.docker_ce_version }}](https://github.com/moby/moby/blob/{{ site.docker_ce_version }}/daemon/graphdriver/driver_linux.go#L52-L53).
{: id="storage-driver-order" } {: id="storage-driver-order" }
Some storage drivers require you to use a specific format for the backing filesystem. If you have external Some storage drivers require you to use a specific format for the backing filesystem.
requirements to use a specific backing filesystem, this may limit your choices. See [Supported backing filesystems](#supported-backing-filesystems). 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 After you have narrowed down which storage drivers you can choose from, your choice
characteristics of your workload and the level of stability you need. See [Other considerations](#other-considerations) is determined by the characteristics of your workload and the level of stability
for help in making the final decision. you need. See [Other considerations](#other-considerations) for help in making
the final decision.
> ***NOTE***: Your choice may be limited by your operating system and distribution.
> For instance, `aufs` is only supported on Ubuntu and Debian, and may require extra packages
> to be installed, while `btrfs` is only supported on SLES, which is only supported with Docker
> Enterprise. See [Support storage drivers per Linux distribution](#supported-storage-drivers-per-linux-distribution)
> for more information.
## Supported storage drivers per Linux distribution ## Supported storage drivers per Linux distribution
At a high level, the storage drivers you can use is partially determined by > Docker Desktop, and Docker in Rootless mode
the Docker edition you use. >
> 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).
In addition, Docker does not recommend any configuration that requires you to Your operating system and kernel may not support every storage driver. For
disable security features of your operating system, such as the need to disable instance, `aufs` is only supported on Ubuntu and Debian, and may require extra
`selinux` if you use the `overlay` or `overlay2` driver on CentOS. 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:
### Docker Engine - Community | Linux distribution | Recommended storage drivers | Alternative drivers |
|:--------------------|:------------------------------|:---------------------------------------------------|
For Docker Engine - Community, only some configurations are tested, and your operating | Ubuntu | `overlay2` | `overlay`¹, `devicemapper`², `aufs`³, `zfs`, `vfs` |
system's kernel may not support every storage driver. In general, the following | Debian | `overlay2` | `overlay`¹, `devicemapper`², `aufs`³, `vfs` |
configurations work on recent versions of the Linux distribution: | CentOS | `overlay2` | `overlay`¹, `devicemapper`², `zfs`, `vfs` |
| Fedora | `overlay2` | `overlay`¹, `devicemapper`², `zfs`, `vfs` |
| Linux distribution | Recommended storage drivers | Alternative drivers | | SLES 15 | `overlay2` | `overlay`¹, `devicemapper`², `vfs` |
|:--------------------|:-----------------------------------------------------------------------|:--------------------------------------------------| | RHEL | `overlay2` | `overlay`¹, `devicemapper`², `vfs` |
| Docker Engine - Community on Ubuntu | `overlay2` or `aufs` (for Ubuntu 14.04 running on kernel 3.13) | `overlay`¹, `devicemapper`², `zfs`, `vfs` |
| Docker Engine - Community on Debian | `overlay2` (Debian Stretch), `aufs` or `devicemapper` (older versions) | `overlay`¹, `vfs` |
| Docker Engine - Community on CentOS | `overlay2` | `overlay`¹, `devicemapper`², `zfs`, `vfs` |
| Docker Engine - Community on Fedora | `overlay2` | `overlay`¹, `devicemapper`², `zfs`, `vfs` |
| Docker Engine - Community on SLES 15 | `overlay2` | `overlay`¹, `devicemapper`², `vfs` |
| Docker Engine - Community on RHEL | `overlay2` | `overlay`¹, `devicemapper`², `vfs` |
¹) The `overlay` storage driver is deprecated, and will be removed in a future ¹) The `overlay` storage driver is deprecated, and will be removed in a future
release. It is recommended that users of the `overlay` storage driver migrate to `overlay2`. release. It is recommended that users of the `overlay` storage driver migrate to `overlay2`.
@ -105,49 +78,33 @@ release. It is recommended that users of the `overlay` storage driver migrate to
release. It is recommended that users of the `devicemapper` storage driver migrate release. It is recommended that users of the `devicemapper` storage driver migrate
to `overlay2`. to `overlay2`.
> **Note** ³) The `aufs` storage driver is deprecated, and will be removed in a future
> release. It is recommended that users of the `aufs` storage driver migrate
> The comparison table above is not applicable for Rootless mode. to `overlay2`.
> For the drivers available in Rootless mode, see [the Rootless mode documentation](../../engine/security/rootless.md).
When possible, `overlay2` is the recommended storage driver. When installing
Docker for the first time, `overlay2` is used by default. Previously, `aufs` was
used by default when available, but this is no longer the case. If you want to
use `aufs` on new installations going forward, you need to explicitly configure
it, and you may need to install extra packages, such as `linux-image-extra`.
See [aufs](aufs-driver.md).
On existing installations using `aufs`, it is still used.
When in doubt, the best all-around configuration is to use a modern Linux When in doubt, the best all-around configuration is to use a modern Linux
distribution with a kernel that supports the `overlay2` storage driver, and to distribution with a kernel that supports the `overlay2` storage driver, and to
use Docker volumes for write-heavy workloads instead of relying on writing data use Docker volumes for write-heavy workloads instead of relying on writing data
to the container's writable layer. to the container's writable layer.
The `vfs` storage driver is usually not the best choice. Before using the `vfs` The `vfs` storage driver is usually not the best choice, and primarily intended
storage driver, be sure to read about for debugging purposes in situations where no other storage-driver is supported.
Before using the `vfs` storage driver, be sure to read about
[its performance and storage characteristics and limitations](vfs-driver.md). [its performance and storage characteristics and limitations](vfs-driver.md).
> **Expectations for non-recommended storage drivers**: Commercial support is The recommendations in the table above are known to work for a large number of
> not available for Docker Engine - Community, and you can technically use any storage driver users. If you use a recommended configuration and find a reproducible issue,
> that is available for your platform. For instance, you can use `btrfs` with it is likely to be fixed very quickly. If the driver that you want to use is
> Docker Engine - Community, even though it is not recommended on any platform for not recommended according to this table, you can run it at your own risk. You
> Docker Engine - Community, and you do so at your own risk. can and should still report any issues you run into. However, such issues
> have a lower priority than issues encountered when using a recommended
> The recommendations in the table above are based on automated regression configuration.
> testing and the configurations that 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
> 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
> configuration.
### Docker Desktop for Mac and Docker Desktop for Windows Depending on your Linux distribution, other storage-drivers, such as `btrfs` may
be available. These storage drivers can have advantages for specific use-cases,
Docker Desktop for Mac and Docker Desktop for Windows are intended for development, rather but may require additional set-up or maintenance, which make them not recommended
than production. Modifying the storage driver on these platforms is not for common scenarios. Refer to the documentation for those storage drivers for
possible. details.
## Supported backing filesystems ## Supported backing filesystems
@ -205,8 +162,8 @@ specific shared storage system.
For some users, stability is more important than performance. Though Docker For some users, stability is more important than performance. Though Docker
considers all of the storage drivers mentioned here to be stable, some are newer considers all of the storage drivers mentioned here to be stable, some are newer
and are still under active development. In general, `overlay2`, `aufs`, `overlay`, and are still under active development. In general, `overlay2`, `aufs`, and
and `devicemapper` are the choices with the highest stability. `devicemapper` are the choices with the highest stability.
### Test with your own workloads ### Test with your own workloads
@ -223,7 +180,7 @@ set-up steps to use a given storage driver.
To see what storage driver Docker is currently using, use `docker info` and look To see what storage driver Docker is currently using, use `docker info` and look
for the `Storage Driver` line: for the `Storage Driver` line:
```bash ```console
$ docker info $ docker info
Containers: 0 Containers: 0
@ -237,11 +194,13 @@ To change the storage driver, see the specific instructions for the new storage
driver. Some drivers require additional configuration, including configuration driver. Some drivers require additional configuration, including configuration
to physical or logical disks on the Docker host. to physical or logical disks on the Docker host.
> **Important**: When you change the storage driver, any existing images and > **Important**
> containers become inaccessible. This is because their layers cannot be used >
> by the new storage driver. If you revert your changes, you can > When you change the storage driver, any existing images and containers become
> access the old images and containers again, but any that you pulled or > inaccessible. This is because their layers cannot be used by the new storage
> created using the new driver are then inaccessible. > 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.
{:.important} {:.important}
## Related information ## Related information