使用 bind mounts 快速搭建本地开发环境
zr - 2024-02-04 22:52:41 - 所属文档:Docker 快速入门文档
在上一节中,我们讨论并使用了 **named volume** 将数据持久保存在数据库中。如果我们只想简单的存储数据,那么 **named volume** 就够用了,因为我们不必关心数据的存储位置。
这一节,将在介绍另外一种 `volume` 类型,即:`bind mounts`
使用 **bind mounts** 我们可以控制主机上的准确挂载点。虽然也可以用它来保存数据,但是通常是用它来向容器提供额外数据。比如:我们可以使用 **bind mounts** 将主机上的源代码挂载到容器中,以便容器可以及时感知源代码的变更。
对于基于 Node.js 的应用程序,[nodemon](https://npmjs.com/package/nodemon)是监视文件更改然后重新启动应用程序的好工具。大多数其他语言和框架都有类似的工具。
## 两种不同 Volume 类型的比较
`named volumes` 和 `bind mounts` 是 Docker 引擎内置的两种主要 `Volume` 类型。也可以使用其他类型的 Volume 驱动程序来支持其他使用场景,如 [SFTP](https://github.com/vieux/docker-volume-sshfs)、[Ceph](https://ceph.com/geen-categorie/getting-started-with-the-docker-rbd-volume-plugin/)、[NetApp](https://netappdvp.readthedocs.io/en/stable/)、[S3](https://github.com/elementar/docker-s3-volume) 等...
| | Named Volumes | Bind Mounts |
| ---------------------------------------------- | --------------------------- | ------------------------------- |
| 在主机上的位置 | 由 Docker 自动选择 | 由你自己决定 |
| 挂载示例 (使用 `-v` 标记) | my-volume:/usr/local/data | /path/to/data:/usr/local/data |
| 使用容器内容填充新 volume | 是 | 否 |
| 支持 Volume 驱动程序 | 是 | 否 |
## 启动一个开发模式的容器
为了运行一个支持开发工作流程的容器,我们将执行以下操作:
* 将我们的源代码挂载到容器中
* 安装所有依赖项,包括 `dev` 依赖项
* 启动 `nodemon` 来监听文件变化
让我们开始吧:
1. 删除之前启动的 `todo-app` 容器
2. 执行以下命令:
```
docker run -dp 3000:3000 \
-w /app \
-v "$(pwd):/app" \
node:12-alpine \
sh -c "yarn install && yarn run dev"
```
如果使用的是 PowerShell,执行下面这条命令(只是 `多行输入` 的分隔符不一样而已)
```
docker run -dp 3000:3000 `
-w /app `
-v "$(pwd):/app" `
node:12-alpine `
sh -c "yarn install && yarn run dev"
```
* `-dp 3000:3000` - 之前遇到过了,表示让容器保持在后台运行并做好端口映射
* `-w /app` - 设置 "working directory" - 工作目录
* `-v "$(pwd):/app"` - `bind mount` 主机上的当前目录挂载到容器上的 `/app` 目录
* `node:12-alpine` - 使用的镜像
* `sh -c "yarn install && yarn run dev"` - 在容器中执行两条命令。由于 alpine 没有 bash,所以通过 sh 执行这两条命令,第一条:`yarn install` 安装我们程序用到的依赖;第二条:`yarn run dev` 启动服务。如果我们查看 `package.json` 文件就会发现 `dev` 脚本正是使用能够监听文件变化并自动重启服务的 `nodemon`(一旦主机上的源码有变化,它能及时监听到,并自动重启 todo-app 服务)
3. 由于上一条命令会在容器中执行安装依赖的操作,在不同的网络环境下的执行时间可能快也可能慢,因此需要等待一会才能访问我们的服务。可以通过 `docker logs` 命令查看容器日志,先执行 `docker image ls` 查看容器 ID,再执行 `docker logs -f <container-id>` 命令,如果看到日志输出了 `Listening on port 3000` 就代表我们的程序已经启动成功。
```
docker logs -f <container-id>
yarn install ...
[1/4] Resolving packages...
[2/4] Fetching packages...
......
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 93.42s.
......
$ nodemon src/index.js
[nodemon] 1.19.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Using SQLite database at /etc/todos/todo.db
Listening on port 3000
```
看完日志后,按 `Ctrl + C` 退出。
4. 现在,让我们来再一次修改源代码。将 `src/static/js/app.js` 文件第 109 行的 "Add Item" 改成 "Add"
5. 只需刷新应用的首页,几乎就能立即在浏览器中看到更改。容器内部自动重新启动 Node 服务器可能需要花费几秒钟的时间,因此,如果访问页面出现错误,可以稍等几秒钟后再试。

6. 至此,你可以随时在本机对应用程序源码进行任何更改。完成后,停止容器并使用 `docker build -t todo-app .` 重新构建新镜像。
在本地开发模式下,使用 `bind mounts` 非常普遍。它的优点是使得本地开发机器不需要安装所有构建工具和环境。只需一条 docker run 命令,开发环境就准备就绪了。
## 回顾
本节我们学习了如何通过 `bind mounts` 快速搭建本地开发环境。
下一节我们准备将数据库从 SQLite 改成更适合生产环境使用的 MySQL。那么问题来了,我们该如何运行 MySQL? 如何让不同容器之间彼此通信?下节再详细说明。
> 原始资料:[Using Bind Mounts](https://docs.docker.com/get-started/06_bind_mounts/)