mirror of https://github.com/docker/docs.git
storage(storagedrivers): q4 tier 1 refresh
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
parent
a1015ad58d
commit
31a16f1da2
|
@ -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.
|
||||
|
|
|
@ -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.
|
|||
|
||||

|
||||
|
||||
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)
|
||||
|
|
|
@ -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.
|
|||

|
||||
|
||||
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)
|
||||
|
|
|
@ -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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue