使用绑定挂载

第4部分中,您使用了卷挂载来持久化数据库中的数据。当您需要一个持久的地方来存储应用程序数据时,卷挂载是一个很好的选择。

绑定挂载是另一种类型的挂载,它允许你将主机文件系统中的目录共享到容器中。在开发应用程序时,你可以使用绑定挂载将源代码挂载到容器中。容器会立即看到你对代码所做的更改,只要你保存了文件。这意味着你可以在容器中运行进程,这些进程会监视文件系统的更改并对其作出响应。

在本章中,您将看到如何使用绑定挂载和一个名为nodemon的工具来监视文件更改,然后自动重新启动应用程序。在大多数其他语言和框架中也有类似的工具。

快速卷类型比较

以下是使用--mount的命名卷和绑定挂载的示例:

  • 命名卷:type=volume,src=my-volume,target=/usr/local/data
  • 绑定挂载:type=bind,src=/path/to/data,target=/usr/local/data

下表概述了卷挂载和绑定挂载之间的主要区别。

Named volumesBind mounts
Host locationDocker choosesYou decide
Populates new volume with container contentsYesNo
Supports Volume DriversYesNo

尝试绑定挂载

在了解如何使用绑定挂载来开发应用程序之前,您可以运行一个快速实验,以实际理解绑定挂载的工作原理。

  1. 请确认您的 getting-started-app 目录位于 Docker Desktop 文件共享设置中定义的目录内。此设置定义了您可以与容器共享的文件系统的哪些部分。有关访问此设置的详细信息,请参阅 文件共享

  2. 打开终端并切换到getting-started-app目录。

  3. 运行以下命令以在带有绑定挂载的ubuntu容器中启动bash


    $ docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
    
    $ docker run -it --mount "type=bind,src=%cd%,target=/src" ubuntu bash
    
    $ docker run -it --mount type=bind,src="/$(pwd)",target=/src ubuntu bash
    
    $ docker run -it --mount "type=bind,src=$($pwd),target=/src" ubuntu bash
    

    --mount type=bind 选项告诉 Docker 创建一个绑定挂载,其中 src 是您主机上的当前工作目录(getting-started-app),而 target 是该目录在容器内应出现的位置(/src)。

  4. 运行命令后,Docker 在容器文件系统的根目录中启动一个交互式的 bash 会话。

    root@ac1237fad8db:/# pwd
    /
    root@ac1237fad8db:/# ls
    bin   dev  home  media  opt   root  sbin  srv  tmp  var
    boot  etc  lib   mnt    proc  run   src   sys  usr
    
  5. 更改目录到 src 目录。

    这是启动容器时挂载的目录。列出此目录的内容将显示与主机上getting-started-app目录中相同的文件。

    root@ac1237fad8db:/# cd src
    root@ac1237fad8db:/src# ls
    Dockerfile  node_modules  package.json  spec  src  yarn.lock
    
  6. 创建一个名为 myfile.txt 的新文件。

    root@ac1237fad8db:/src# touch myfile.txt
    root@ac1237fad8db:/src# ls
    Dockerfile  myfile.txt  node_modules  package.json  spec  src  yarn.lock
    
  7. 打开主机上的getting-started-app目录,并观察myfile.txt文件是否在目录中。

    ├── getting-started-app/
    │ ├── Dockerfile
    │ ├── myfile.txt
    │ ├── node_modules/
    │ ├── package.json
    │ ├── spec/
    │ ├── src/
    │ └── yarn.lock
  8. 从主机中删除myfile.txt文件。

  9. 在容器中,再次列出app目录的内容。观察发现文件现在已经消失了。

    root@ac1237fad8db:/src# ls
    Dockerfile  node_modules  package.json  spec  src  yarn.lock
    
  10. 使用 Ctrl + D 停止交互式容器会话。

以上就是对绑定挂载的简要介绍。这个过程展示了如何在主机和容器之间共享文件,以及更改如何立即在双方反映。现在你可以使用绑定挂载来开发软件了。

开发容器

使用绑定挂载在本地开发设置中很常见。其优势在于开发机器不需要安装所有的构建工具和环境。通过一个简单的docker run命令,Docker可以拉取依赖和工具。

在开发容器中运行您的应用程序

以下步骤描述了如何使用绑定挂载运行开发容器,该绑定挂载执行以下操作:

  • 将您的源代码挂载到容器中
  • 安装所有依赖项
  • 启动 nodemon 以监视文件系统的更改

您可以使用CLI或Docker Desktop来运行带有绑定挂载的容器。


  1. 确保当前没有运行任何getting-started容器。

  2. getting-started-app目录运行以下命令。

    $ docker run -dp 127.0.0.1:3000:3000 \
        -w /app --mount type=bind,src="$(pwd)",target=/app \
        node:18-alpine \
        sh -c "yarn install && yarn run dev"
    

    以下是命令的分解:

    • -dp 127.0.0.1:3000:3000 - same as before. Run in detached (background) mode and create a port mapping
    • -w /app - sets the "working directory" or the current directory that the command will run from
    • --mount type=bind,src="$(pwd)",target=/app - bind mount the current directory from the host into the /app directory in the container
    • node:18-alpine - the image to use. Note that this is the base image for your app from the Dockerfile
    • sh -c "yarn install && yarn run dev" - the command. You're starting a shell using sh (alpine doesn't have bash) and running yarn install to install packages and then running yarn run dev to start the development server. If you look in the package.json, you'll see that the dev script starts nodemon.
  3. 你可以使用docker logs 查看日志。当你看到以下内容时,你就知道已经准备好了:

    $ docker logs -f <container-id>
    nodemon -L src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    

    当你完成日志查看后,通过按下Ctrl+C退出。

  1. 确保当前没有运行任何getting-started容器。

  2. getting-started-app目录运行以下命令。

    $ docker run -dp 127.0.0.1:3000:3000 `
        -w /app --mount "type=bind,src=$pwd,target=/app" `
        node:18-alpine `
        sh -c "yarn install && yarn run dev"

    以下是该命令的详细解析:

    • -dp 127.0.0.1:3000:3000 - same as before. Run in detached (background) mode and create a port mapping
    • -w /app - sets the "working directory" or the current directory that the command will run from
    • --mount "type=bind,src=$pwd,target=/app" - bind mount the current directory from the host into the /app directory in the container
    • node:18-alpine - the image to use. Note that this is the base image for your app from the Dockerfile
    • sh -c "yarn install && yarn run dev" - the command. You're starting a shell using sh (alpine doesn't have bash) and running yarn install to install packages and then running yarn run dev to start the development server. If you look in the package.json, you'll see that the dev script starts nodemon.
  3. 你可以使用docker logs 查看日志。当你看到以下内容时,你就知道已经准备好了:

    $ docker logs -f <container-id>
    nodemon -L src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    

    当你查看完日志后,通过按下Ctrl+C退出。

  1. 确保当前没有运行任何getting-started容器。

  2. getting-started-app目录运行以下命令。

    $ docker run -dp 127.0.0.1:3000:3000 ^
        -w /app --mount "type=bind,src=%cd%,target=/app" ^
        node:18-alpine ^
        sh -c "yarn install && yarn run dev"
    

    以下是命令的分解:

    • -dp 127.0.0.1:3000:3000 - same as before. Run in detached (background) mode and create a port mapping
    • -w /app - sets the "working directory" or the current directory that the command will run from
    • --mount "type=bind,src=%cd%,target=/app" - bind mount the current directory from the host into the /app directory in the container
    • node:18-alpine - the image to use. Note that this is the base image for your app from the Dockerfile
    • sh -c "yarn install && yarn run dev" - the command. You're starting a shell using sh (alpine doesn't have bash) and running yarn install to install packages and then running yarn run dev to start the development server. If you look in the package.json, you'll see that the dev script starts nodemon.
  3. 你可以使用docker logs 查看日志。当你看到以下内容时,你就知道已经准备好了:

    $ docker logs -f <container-id>
    nodemon -L src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    

    当你完成日志查看后,通过按下Ctrl+C退出。

  1. 确保当前没有运行任何getting-started容器。

  2. getting-started-app目录运行以下命令。

    $ docker run -dp 127.0.0.1:3000:3000 \
        -w //app --mount type=bind,src="/$(pwd)",target=/app \
        node:18-alpine \
        sh -c "yarn install && yarn run dev"
    

    以下是命令的分解:

    • -dp 127.0.0.1:3000:3000 - same as before. Run in detached (background) mode and create a port mapping
    • -w //app - sets the "working directory" or the current directory that the command will run from
    • --mount type=bind,src="/$(pwd)",target=/app - bind mount the current directory from the host into the /app directory in the container
    • node:18-alpine - the image to use. Note that this is the base image for your app from the Dockerfile
    • sh -c "yarn install && yarn run dev" - the command. You're starting a shell using sh (alpine doesn't have bash) and running yarn install to install packages and then running yarn run dev to start the development server. If you look in the package.json, you'll see that the dev script starts nodemon.
  3. 您可以使用docker logs 查看日志。当您看到以下内容时,您就知道已经准备好了:

    $ docker logs -f <container-id>
    nodemon -L src/index.js
    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node src/index.js`
    Using sqlite database at /etc/todos/todo.db
    Listening on port 3000
    

    当你完成日志查看后,通过按下Ctrl+C退出。

确保当前没有运行任何getting-started容器。

使用绑定挂载运行镜像。

  1. 选择Docker Desktop顶部的搜索框。

  2. 在搜索窗口中,选择图片标签。

  3. 在搜索框中,指定容器名称,getting-started

    提示

    使用搜索过滤器来过滤图像,仅显示本地图像

  4. 选择您的图像,然后选择运行

  5. 选择可选设置

  6. 主机路径中,指定主机机器上getting-started-app目录的路径。

  7. 容器路径中,指定/app

  8. 选择运行

您可以使用Docker Desktop查看容器日志。

  1. 在Docker桌面中选择Containers
  2. 选择您的容器名称。

当你看到这个时,你就知道你已经准备好了:

nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000

使用开发容器开发您的应用程序

在主机上更新您的应用程序,并查看容器中反映的更改。

  1. src/static/js/app.js文件的第109行,将“添加项目”按钮改为仅显示“添加”:

    - {submitting ? 'Adding...' : 'Add Item'}
    + {submitting ? 'Adding...' : 'Add'}
    

    保存文件。

  2. 在您的网页浏览器中刷新页面,由于绑定挂载,您应该几乎立即看到更改反映出来。Nodemon 检测到更改并重新启动服务器。Node 服务器可能需要几秒钟才能重新启动。如果出现错误,请几秒钟后再次刷新。

    Screenshot of updated label for Add button
  3. 请随意进行您想要的其他更改。每次您进行更改并保存文件时,由于绑定挂载,更改会在容器中反映出来。当Nodemon检测到更改时,它会自动重新启动容器内的应用程序。完成后,停止容器并使用以下命令构建新镜像:

    $ docker build -t getting-started .
    

摘要

此时,您可以持久化您的数据库,并在开发过程中查看应用程序中的更改,而无需重新构建镜像。

除了卷挂载和绑定挂载,Docker 还支持其他挂载类型和存储驱动程序,以处理更复杂和专门的用例。

相关信息:

下一步

为了让你的应用程序为生产环境做好准备,你需要将数据库从SQLite迁移到能够更好扩展的数据库。为了简化操作,你将继续使用关系型数据库,并将应用程序切换到使用MySQL。但是,你应该如何运行MySQL?如何让容器之间相互通信?你将在下一节中学习这些内容。