Skip to content

Docker Storage

默认情况下,在容器内创建的所有文件都存储在可写容器层(writable container layer)上,这意味着:

  • 当该容器不存在时,数据不会保留
  • 容器中可写层与运行的容器紧密耦合,无法导出和共享数据

因此需要一种机制来实现数据的持久化,而 Docker 提供了卷和绑定挂载(Volumes and bind mounts)两种机制来实现这一点。

Volumes

卷(Volumes)由 Docker 创建和管理(通过 docker volume 命令)。创建的卷实际上就是主机中的一个特定目录,但是他由 Docker 来管理。给定的卷可以同时挂载到多个容器中。

一些容器会自动创建卷,他们通常是匿名的,Docker 会自动赋予一个随机的名称。注意卷是持久化的,即使删除了创建他的容器他也会保留除非指定 --rm 表示在容器销毁删除卷。

docker volume

docker volume是管理卷的命令:

子命令 描述
docker volume create 创建卷
docker volume inspect 检查卷
docker volume ls 列出卷
docker volume prune 删除未使用的卷
docker volume rm 删除指定卷
docker volume update 更新卷(仅限集群使用)

创建和管理卷

Bash
# 创建卷
docker volume create my-vol

# 列出卷
docker volume ls

local               my-vol

# 删除卷
docker volume rm my-vol

Tips

删除卷是一个独立的任务,这意味着删除容器等其他操作都不会影响卷。

备份、还原和迁移卷

首先我们创建一个名为 dbstore 的新容器:

Bash
docker run -v /dbdata --name dbstore ubuntu /bin/bash

备份

备份执行下面的命令:

Bash
docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

它整个执行流程是:

  1. 启动一个新的 ubuntu 容器,并且通过 --volumes-from 参数来挂载 dbstore 容器中的卷
  2. 新容器(ubuntu)会将当前目录挂载到容器的 /backup
  3. 通过 tar 打包 --volumes-from 指定的容器的卷并放置到 /backup 目录下
  4. 这样就能够在当前目录下看到备份的卷内容

还原

还原执行下面的路径,基本上就是备份的反操作:

Bash
# 首先创建一个新容器,该容器挂载了一个匿名卷到 /dbdata 中
docker run -v /dbdata --name dbstore2 ubuntu /bin/bash

之后就是还原数据到 dbstore2 容器中:

Bash
docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

Bind mounts

所谓的绑定挂载(Bind mounts)就是将主机上已经存在的目录挂载到容器中(如果目录不存在会自动创建)。

绑定挂载的目录是由本机管理的,因此会出现一些问题,例如容器是可以通过命令来更改挂载的文件系统的,这可能会产生安全隐患。但是他是直接与本机进行文件交互的最便捷的方式。

Tips

如果更多是在容器和本机之间传递文件,Bind mounts 是最佳的方式,如果是多个容器之间传递数据 Volumes 是最佳的选择,官方推荐是尽可能的使用 Volumes

挂载: -v/--volume | --mount

有两种方式来为容器挂载卷和 bind mounts:

  • -v/--volume VOLUME_NAME:TARGET_PATH:OPTIONS: 由三个字段组成,他们之间使用 : 分隔。第一个是卷名,第二个是容器中的挂载路径,第三个是以逗号分隔的选项列表,例如 ro 来只读
  • --mount key1=value1,key2=value2...: 通过键值对组成,多个由逗号分隔,它要比 -v 语法更加规范和详细,可能的字段包括:
    • type: bind|volume|tmpfs: 指定挂载类型, bind 对应的就是 Bind mounts, 而 volume 对应的就是 Volumes
    • source: volume_name: 对于命名卷就是卷名,对于匿名卷可以省略(会自动创建匿名卷),对于 bind 就是主机路径
    • destination/target: 容器中的挂载路径
    • readonly: 只读

Tips

挂载映射到容器内的 mount 命令

通常 -v--mount 仅语法上的区别,如果在启动容器时指定了卷而卷不存在 Docker 会自动创建该卷:

=== --mount

Text Only
```bash
docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest
```

=== -v

Text Only
```bash
docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest
```

Volumes vs Bind mounts

这是两种不同的挂载方式,尽管他们都使用 -v --mount 来实现挂载,但是有本质不同:

  • Volumes: 由 Docker 管理的存储卷,在宿主机上的位置对于用户来说是透明的,由 Docker 自动管理。在 Linux 中,Docker 会在 /var/lib/docker/volumes 下生成相应目录,将容器内目录挂载在其中,如果不指定 volume 名称,将随机生成一个
  • Bind mounts:将宿主机上的文件或目录直接挂载到容器中,文件或目录在宿主机上的位置是由用户指定的

我们可以直接通过 type=bind|volume 来指定要挂载卷的类型,也可以使用自动识别:

Bash
-v /to/path:/data # 如果 : 是路径(绝对或相对路径)那么默认使用 bind 挂载类型
-v volume_name:/data # 如果 : 仅仅是一个字符串将使用 volumes 挂载类型

参考