掌握 Docker 卷

2025-06-09

掌握 Docker 卷

对于刚开始使用 Docker 的人,我写了一些关于如何像容器一样思考的文章,我相信这是使用 Docker 的重要思维方式,也是在开发中正确使用 Docker 的重要思维方式

但是,如果您想进一步掌握 Docker,那么了解Docker 中的网络如何工作非常重要。

在这篇文章中,我将引导您了解卷的基础知识,而网络部分则留到另一篇文章中介绍

容器是短暂的

需要注意的是,容器是短暂的。只要容器执行完命令它就会彻底“关闭”。

=> docker run node ls

bin
boot
dev
etc
home
lib
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Enter fullscreen mode Exit fullscreen mode

它使用图像节点启动一个新容器,并ls在容器内执行命令(列出文件和目录)。

该命令给出输出并完成。命令完成后,容器将关闭,其所有数据将丢失

执行 Javascript 程序

假设我们有一个包含非常基本的 Javascript 程序的文件:

helloWorld.js

greeting = (message) => {
  console.log(message)
}

greeting("Hello, world")
Enter fullscreen mode Exit fullscreen mode

我们如何使用容器运行这个程序?可以尝试这样做:

docker run node node helloWorld.js
Enter fullscreen mode Exit fullscreen mode

...这引发了错误:

Error: Cannot find module '/app/helloWorld.js'
...
Enter fullscreen mode Exit fullscreen mode

这是因为容器是隔离的并且不共享相同的主机文件系统。

在主机和容器之间同步数据

我们必须将文件helloWorld.js与容器同步。Docker 提供了一种挂载卷的方法,这意味着:

我想将目录或文件主机挂载到容器,这样在主机中所做的每个更改都将镜像到容器,反之亦然

你在主机中更改文件/目录,容器也会看到这些变化。你在容器中更改文件/目录,主机也会看到这些变化。

helloWorld.js让我们与容器同步:

docker run 
  -v $(pwd)/docker-101/helloWorld.js:/app/helloWorld.js 
  node 
  node /app/helloWorld.js
Enter fullscreen mode Exit fullscreen mode
Hello, world
Enter fullscreen mode Exit fullscreen mode

...在哪里:

  • pwd指的是当前目录的完整路径名
  • -v {hostPath}:{containerPath}将文件/目录挂载到容器
  • 节点是图像
  • node /app/helloWorld.js使用容器内定义的路径执行命令,/app/helloWorld.js

一个真实的项目

假设我们有一个这样的项目树:

/docker-101
  /src
    /components
    components.js
  index.js
Enter fullscreen mode Exit fullscreen mode

从目录内部docker-101,我们想要使用该文件运行一个容器,但文件夹index.js中的所有文件也必须位于容器应用程序中。src

docker run 
  -v $(pwd):/app
  node
  node /app/index.js
Enter fullscreen mode Exit fullscreen mode

当前目录中的所有文件都pwd将挂载到/app容器内。

如果我们想进入容器并从那里操作文件怎么办?

docker run 
  -it
  -v $(pwd):/app
  node
  bash
Enter fullscreen mode Exit fullscreen mode

...在哪里:

  • -它指示 Docker 保持容器终端(bash/shell)打开
  • bash在容器内打开一个新的 bash/shell
root@8dcbfa6d777c:/# cd /app

root@8dcbfa6d777c:/app# ls
index.js  src

root@8dcbfa6d777c:/app# touch new-file.js

root@8dcbfa6d777c:/app# ls
index.js  new-file.js src

root@8dcbfa6d777c:/app# exit
exit
Enter fullscreen mode Exit fullscreen mode

现在,退出容器后,如果我们ls 从主机执行,我们会得到:

index.js    new-file.js src
Enter fullscreen mode Exit fullscreen mode

这种类型的体积称为路径体积

使用挂载选项

挂载卷的另一种方法是使用--mount选项,该选项指定挂载的类型、目标

docker run 
  --mount type=bind,source=$(pwd),target=/app
  node
  node /app/helloWorld.js
Enter fullscreen mode Exit fullscreen mode

mount明确,但在大多数情况下使用-v就足够了。

另一个真实的例子

假设我们想打印当前时间的时间戳。有很多方法可以实现,但现在我们将使用Underscore库。

index.js

var _ = require('underscore');

console.log(_.now())
Enter fullscreen mode Exit fullscreen mode

我们执行docker run -it -v $(pwd):/app node node /app/index.js,得到以下错误:

Error: Cannot find module 'underscore'
Enter fullscreen mode Exit fullscreen mode

显然,我们必须将underscore依赖项添加到我们的项目中。让我们使用以下命令来完成npm

docker run 
  -v $(pwd):/app 
  -w /app
  node
  npm add underscore
Enter fullscreen mode Exit fullscreen mode
added 1 package, and audited 2 packages in 2s
Enter fullscreen mode Exit fullscreen mode

注意-w /app,它表示工作目录,我们告诉 Docker 从该目录内执行命令。在我们的例子中,该命令将在容器内的目录npm add underscore中执行。/app

现在,我们可以运行index.js

docker run 
  -v $(pwd):/app 
  -w /app
  node
  node index.js
Enter fullscreen mode Exit fullscreen mode
1644018496251
Enter fullscreen mode Exit fullscreen mode

想要一些 NPM 缓存吗?

有时我们需要使用缓存来加速 npm 进程。在容器内部,默认情况下,npm存储缓存在/root/.npm。你可以运行以下命令进行检查:

npm config get cache

=> /root/.npm
Enter fullscreen mode Exit fullscreen mode

目前,我们仅同步-v $(pwd):/app卷。当容器将 npm 缓存写入时/root/.npm,我们不会同步回主机。

我们了解到我们可以将多个卷安装到容器中,所以让我们这样做:

docker run 
  -v $(pwd):/app 
  -v $(pwd)/npm_cache:/root/.npm <---- sync the NPM cache
  -w /app
  node
  npm install underscore
Enter fullscreen mode Exit fullscreen mode

当我们ls从主机执行时,我们得到以下内容:

index.js          node_modules      npm_cache         package-lock.json package.json      src
Enter fullscreen mode Exit fullscreen mode

但是,我们不想在项目中跟踪“npm_cache”文件夹。这不关我们的事。

如果我们想将这样的缓存存储在主机的另一个路径中,因此我们不关心它存储在哪里,该怎么办?

Docker 提供了一种特殊类型的 Volume,它在 Host 中的路径由 Docker 选择,因此我们唯一需要知道的就是它的名称。Docker 知道它的位置,但我们并不关心。

是的,它们被称为命名卷

docker volume create my-volume

docker volume inspect my-volume
Enter fullscreen mode Exit fullscreen mode
[
    {
        "CreatedAt": "2022-02-05T00:47:59Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
        "Name": "my-volume",
        "Options": {},
        "Scope": "local"
    }
]
Enter fullscreen mode Exit fullscreen mode

Mountpoint是主机中的确切路径。因此,每个使用此卷的容器都会将其数据直接同步到此挂载点,而我们则可以通过在其他地方使用其名称“my-volume”来管理和了解该卷。

在我们的下划线示例中,我们也可以使用命名卷启动容器:

docker run 
  -v $(pwd):/app 
  -v npm_cache:/root/.npm <---- named volume in the Host
  -w /app
  node
  npm install underscore
Enter fullscreen mode Exit fullscreen mode

这样,Docker 将创建一个名为的卷npm_cache并将其挂载到容器中/root/.npm

不相信?你自己去看看吧:

docker volume inspect npm_cache
Enter fullscreen mode Exit fullscreen mode
[
    {
        "CreatedAt": "2022-02-05T00:51:24Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/npm_cache/_data",
        "Name": "npm_cache",
        "Options": null,
        "Scope": "local"
    }
]
Enter fullscreen mode Exit fullscreen mode

太棒了!现在清晰多了,因为我们保持了 npm 进程的加速。

docker run 
  -v $(pwd):/app 
  -v npm_cache:/root/.npm
  -w /app
  node
  node index.js
Enter fullscreen mode Exit fullscreen mode
1644022388847
Enter fullscreen mode Exit fullscreen mode

总结

在本文中,我们学习了如何在 Docker 中使用路径卷命名卷。

当我们想要跟踪主机中的路径(即安装我们正在处理的整个项目)时,路径卷非常有用。

当我们不想跟踪主机中的路径,而是利用 Docker 为我们选择路径时,命名卷非常方便mountpoint,即使用 NPM、Yarn、Ruby bundler、Python 包等的缓存。

鏂囩珷鏉ユ簮锛�https://dev.to/leandronsp/mastering-docker-volumes-j7m
PREV
在开发中正确使用 Docker
NEXT
不到 20 行代码即可在 PostgreSQL 中实现强大的全文搜索