1. Overview
1.概述
Docker containers are used to run applications in an isolated environment. By default, all the changes inside the container are lost when the container stops. If we want to keep data between runs, Docker volumes and bind mounts can help.
Docker容器被用来在一个隔离的环境中运行应用程序。默认情况下,当容器停止时,容器内的所有变化都会丢失。如果我们想在运行期间保留数据,Docker卷和绑定挂载可以帮助我们。
, and how to manage and connect them to containers.
,以及如何管理和连接它们与容器。
2. What Is a Volume?
2.什么是体积?
2.1. The Docker File System
2.1 Docker文件系统
A docker container runs the software stack defined in an image. Images are made of a set of read-only layers that work on a file system called the Union File System. When we start a new container, Docker adds a read-write layer on the top of the image layers allowing the container to run as though on a standard Linux file system.
docker容器运行定义在image中的软件栈。图像是由一组只读层组成的,它们在一个称为联合文件系统的文件系统上工作。当我们启动一个新的容器时,Docker会在图像层的顶部添加一个读写层,使容器能够像在标准的Linux文件系统上运行一样。
So, any file change inside the container creates a working copy in the read-write layer. However, when the container is stopped or deleted, that read-write layer is lost.
因此,容器内的任何文件变化都会在读写层创建一个工作副本。然而,当容器被停止或删除时,该读写层就会丢失。
We can try this out by running a command that writes and then reads a file:
我们可以通过运行一个先写后读文件的命令来试试。
$ docker run bash:latest \
bash -c "echo hello > file.txt && cat file.txt"
The result is:
其结果是。
hello
But if we run the same image with just the command to output the file’s contents:
但如果我们运行同一个图像,只用命令来输出文件的内容。
$ docker run bash:latest bash -c "cat file.txt"
cat: can't open 'file.txt': No such file or directory
The second run of the container runs on a clean file system, so the file is not found.
容器的第二次运行是在一个干净的文件系统上进行的,所以没有找到该文件。
2.2. Bind Mounts
2.2.捆绑式安装
A Docker bind mount is a high-performance connection from the container to a directory on the host machine. It allows the host to share its own file system with the container, which can be made read-only or read-write.
Docker 绑定挂载是一个从容器到主机上一个目录的高性能连接。它允许主机与容器共享自己的文件系统,可以使其成为只读或读写。
This allows us to use a container to run tools that we don’t want to install on our host, and yet still work with our host’s files. For example, if we wanted to use a custom version of bash for a particular script, we might execute that script in a bash container, mounted to our current working directory:
这允许我们使用一个容器来运行我们不想安装在主机上的工具,但仍然可以使用我们主机的文件。例如,如果我们想使用一个自定义版本的bash来编写一个特定的脚本,我们可以在一个bash容器中执行该脚本,并挂载到我们当前的工作目录。
$ docker run -v $(pwd):/var/opt/project bash:latest \
bash -c "echo Hello > /var/opt/project/file.txt"
The –v option can be used for all forms of mounting and specifies, in this instance, the source on the host – the working directory in the output of $(pwd) – and the target mount point in the container – /var/opt/project.
选项-v可用于所有形式的挂载,在本例中指定主机上的源–$(pwd)输出的工作目录–和容器中的目标挂载点–/var/opt/project。
After running this command, we will find file.txt in the working directory of our host machine. This is a simple way to provide persistent files between invocations of a Docker container, though it is most useful for when the container is doing work on behalf of the host.
运行这个命令后,我们将在主机的工作目录中找到file.txt。这是一种在Docker容器的调用之间提供持久性文件的简单方法,尽管它在容器代表主机进行工作时最有用。
One good use case for this would be executing various versions of a language’s build tools in Docker to avoid having conflicting installations on a developer machine.
这方面的一个很好的用例是在Docker中执行一个语言的不同版本的构建工具,以避免在开发者机器上出现冲突的安装。
We should note that $(pwd -W) is sometimes needed on Windows bash shells to provide the working directory in a form that the bash shell can pass to Docker.
我们应该注意,$(pwd -W)在Windows bash shells上有时需要以bash shells可以传递给Docker的形式提供工作目录。
2.3. Docker Volumes
2.3 Docker Volumes
A bind mount uses the host file system, but Docker volumes are native to Docker. The data is kept somewhere on storage attached to the host – often the local filesystem. The volume itself has a lifecycle that’s longer than the container’s, allowing it to persist until no longer needed. Volumes can be shared between containers.
绑定挂载使用主机文件系统,但Docker卷是Docker的本机。数据被保存在连接到主机的某个存储设备上–通常是本地文件系统。卷本身的生命周期比容器的生命周期长,允许它持续存在直到不再需要。卷可以在容器之间共享。
In some cases, the volume is in a form that is not usable by the host directly.
在某些情况下,卷的形式是不能被主机直接使用的。
3. Managing Volumes
3.管理卷轴
Docker allows us to manage volumes via the docker volume set of commands. We can give a volume an explicit name (named volumes), or allow Docker to generate a random one (anonymous volumes).
Docker允许我们通过docker volume一组命令来管理卷。我们可以给卷一个明确的名字(命名的卷),或者允许Docker生成一个随机的名字(匿名的卷)。
3.1. Creating Volumes
3.1.创建卷
We can create a volume by using the create subcommand and passing a name as an argument:
我们可以通过使用create子命令并传递一个名称作为参数来创建一个卷。
$ docker volume create data_volume
data_volume
If a name is not specified, Docker generates a random name:
如果没有指定名字,Docker会生成一个随机的名字。
$ docker volume create
d7fb659f9b2f6c6fd7b2c796a47441fa77c8580a080e50fb0b1582c8f602ae2f
3.2. Listing Volumes
3.2.挂牌卷数
The ls subcommand shows all the volumes known to Docker:
ls子命令显示Docker已知的所有卷。
$ docker volume ls
DRIVER VOLUME NAME
local data_volume
local d7fb659f9b2f6c6fd7b2c796a47441fa77c8580a080e50fb0b1582c8f602ae2f
We can filter using the -f or –filter flag and passing key=value parameters for more precision:
我们可以使用-f或-filter标志进行过滤,并传递key=value参数以获得更多的精度。
$ docker volume ls -f name=data
DRIVER VOLUME NAME
local data_volume
3.3. Inspecting Volumes
3.3.检查卷宗
To display detailed information on one or more volumes, we use the inspect subcommand:
为了显示一个或多个卷的详细信息,我们使用inspect子命令。
$ docker volume inspect ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59
[
{
"CreatedAt": "2020-11-13T17:04:17Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59/_data",
"Name": "ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59",
"Options": null,
"Scope": "local"
}
]
We should note that the Driver of the volume describes how the Docker host locates the volume. Volumes can be on remote storage via nfs, for example. In this example, the volume is in local storage.
我们应该注意,卷的Driver描述了Docker主机如何定位该卷。例如,卷可以通过nfs在远程存储上。在这个例子中,卷是在本地存储。
3.4. Removing Volumes
3.4.移除卷轴
To remove one or more volumes individually, we can use the rm subcommand:
要单独删除一个或多个卷,我们可以使用rm子命令。
$ docker volume rm data_volume
data_volume
3.5. Pruning Volumes
3.5. 修剪量
We can remove all the unused volumes with the prune subcommand:
我们可以用prune子命令删除所有未使用的卷。
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
data_volume
4. Starting a Container with a Volume
4.用一个卷启动一个容器
4.1. Using -v
4.1.使用-v
As we saw with the earlier example, we can start a container with a bind mount using the -v option:
正如我们在前面的例子中所看到的,我们可以使用-v选项来启动一个绑定挂载的容器。
$ docker run -v $(pwd):/var/opt/project bash:latest \
bash -c "ls /var/opt/project"
This syntax also supports mounting a volume:
这个语法也支持挂载一个卷。
$ docker run -v data-volume:/var/opt/project bash:latest \
bash -c "ls /var/opt/project"
As our volume is empty, this lists nothing from the mount point. However, if we were to write to the volume during one invocation of the container:
由于我们的卷是空的,这没有从挂载点列出什么。然而,如果我们在调用容器的过程中向该卷写入数据,那么,我们就会发现,该卷是空的。
$ docker run -v data-volume:/var/opt/project bash:latest \
bash -c "echo Baeldung > /var/opt/project/Baeldung.txt"
Then our subsequent use of a container with this volume mounted would be able to access the file:
然后我们后续使用挂载了这个卷的容器就可以访问这个文件了。
$ docker run -v data-volume:/var/opt/project bash -c "ls /var/opt/project"
Baeldung.txt
The -v option contains three components, separated by colons:
-v选项包含三个部分,用冒号分隔。
- Source directory or volume name
- Mount point within the container
- (Optional) ro if the mount is to be read-only
4.2. Using the –mount Option
4.2.使用-mount选项
We may prefer to use the more self-explanatory –mount option to specify the volume we wish to mount:
我们可能更喜欢使用更容易解释的-mount选项来指定我们想要挂载的卷。
$ docker run --mount \
'type=volume,src=data-volume,\
dst=/var/opt/project,volume-driver=local,\
readonly' \
bash -c "ls /var/opt/project"
The input to –mount is a string of key-value pairs, separated by commas. Here we’ve set:
-mount的输入是一串键值对,用逗号分隔。这里我们设置了
- type – as volume to indicate a volume mount
- src – to the name of the volume, though this could have been a source directory if we’d been making a bind mount
- dst – as the destination mount point in the container
- volume-driver – the local driver in this case
- readonly – to make this mount read-only; we could have chosen rw for read/write
We should note that the above command will also create a volume if it does not already exist.
我们应该注意到,如果一个卷还不存在,上述命令也会创建一个卷。
4.3. Using –volumes-from to Share Volumes
4.3.使用-volumes-from来共享卷轴
We should note that attaching a volume to a container creates a long-term connection between the container and the volume. Even when the container has exited, the relationship still exists. This allows us to use a container that has exited as a template for mounting the same set of volumes to a new one.
我们应该注意到,将一个卷附加到一个容器上会在容器和卷之间建立一个长期的联系。即使容器已经退出了,这种关系仍然存在。这使得我们可以使用一个已经退出的容器作为模板,将同一组卷挂载到一个新的容器上。
Let’s say we ran our echo script in a container with the data-volume mount. Later on, we could list all containers we have used:
假设我们在一个带有data-volume挂载的容器中运行了我们的echo脚本。后来,我们可以列出我们使用过的所有容器。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4920602f8048 bash "docker-entrypoint.s…" 7 minutes ago Exited (0) 7 minutes ago exciting_payne
We could run our next container, by copying the volumes used by this one:
我们可以通过复制这个容器所使用的卷来运行我们的下一个容器。
$ docker run --volumes-from 4920 \
bash:latest \
bash -c "ls /var/opt/project"
Baeldung.txt
In practice –volumes-from is usually used to link volumes between running containers. Jenkins uses it to share data between agents running as Docker containers.
在实践中,-volumes-from通常用于连接正在运行的容器之间的卷。Jenkins用它来在作为Docker容器运行的代理之间共享数据。
5. Conclusion
5.总结
In this article, we saw how Docker normally creates a container with a fresh filesystem, but how bind mounts and volumes allow long-term storage of data beyond the container’s lifecycle.
在这篇文章中,我们看到了Docker通常是如何用一个新的文件系统来创建一个容器的,但是绑定挂载和卷允许在容器的生命周期之外长期存储数据。
We saw how to list and manage Docker volumes, and how to connect volumes to a running container via the command line.
我们看到了如何列出和管理Docker卷,以及如何通过命令行将卷连接到运行中的容器。