介绍
Docker 容器一旦删除,那么我们在容器内的一切操作将不复存在,比如我们在容器内存储的数据等;为了解决这个问题,Docker 提出了数据卷概念,就像我们运行一个mysql容器,我们需要存储我们的数据,日志之类,想要他们不会随着容器的删除而销毁,或者我们需要在各个容器间共享数据,那么这些数据卷或者数据卷容器都能做到。
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新,不会影响镜像
- 数据卷默认会一直存在,即使容器被删除
- 数据卷的生命周期一直持续到没有容器使用它为止
数据卷的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的数据卷
Docker提供了两种方式管理数据
- 数据卷
- 数据卷容器
数据卷
添加数据卷
在 docker run 命令中 使用 -v 标识给容器内添加一个或者多个数据卷
在容器内创建一个新的数据卷 /data/shop
1 | $ docker run -d -P --name my-shop-web -v /data/shop sqgulj/shop-web |
这种方式我们也可以在Dockerfile中使用VOLUME指令来给创建的容器添加一个或者多个数据卷,比如官方的 mysql 的 Dockerfile 中用 VOLUME 指定了数据卷
1 | ......... |
其中 VOLUME /var/lib/mysql 指定了mysql的数据卷
将宿主机的一个目录,挂在到容器里
使用 -v,除了可以创建一个数据卷,还可以挂载本地主机目录到容器中
1 | $ docker run -d -P --name my-shop-web -v /local/data/shop:/data/shop sqgulj/shop-web |
这将会把本地目录/local/data/shop挂载到容器的/data/shop目录,宿主机上的目录必须是绝对路径,如果目录不存在docker会自动创建它。
出于可移植和分享的考虑,在Dockerfile中这种方式不支持
docker默认情况下是对数据卷有读写权限,但是我们通过这样的方式让数据卷只读:
1 | $ docker run -d -P --name my-shop-web -v /local/data/shop:/data/shop:ro sqgulj/shop-web |
这里我们同样挂载了/local/data/shop目录,只是添加了 ro 选项来限制它只读。
将宿主机上单个文件挂载到容器中
除了能挂载目录外,-v 标识还可以将宿主机的一个特定文件挂载为数据卷
1 | $ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash |
这样就可以记录在容器输入过的命令了
如果直接挂载一个文件,很多文件编辑工具,包括 vi 或者 sed –in-place,可能会造成文件 inode 的改变,从 Docker 1.1.0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。
查看数据卷
- 使用命令 docker volume 可以查看我们生成的数据卷
1 | $ docker volume ls |
我们可以看到我们添加的数据卷 /data/shop ,当我们查看的时候并不是我们提供的名称,而是生成一系列的随机串,当我们为多个容器添加数据卷的时候,它也会为其生成一系列的随机串,这样不利于我们辨识哪些数据卷挂在哪个容器中,为了解决这个问题,我们可以在添加数据数据卷的时候,为数据卷起个辨识的名称,比如
1 | $ docker run -d -P --name my-shop-web -v shopwebdata:/data/shop sqgulj/shop-web |
我们发现,这次我们为容器添加一个数据的时候我们在前面加了一个 shopwebdata ,注意shopwebdata前面没有斜杠( / ),如果有斜杠那是把本地的一个目录挂载到容器内的一个目录
1 | $ docker volume ls |
这次我们就能看到我们添加的数据卷就是我们起的名称,而不是一些列的随机串
- 使用命令 docker inspect 查看数据卷
1 | # my-shop-web 为容器的名称 |
这里只列出了其中的 Mounts 属性,从中可以看到Source字段显示了数据卷存放的位置
删除数据卷
数据卷是被设计来持久化数据的,因此,删除容器并不会删除数据卷。如果想要在删除容器时同时删除数据卷,可使用如下命令:
1 | $ docker rm -v 容器ID |
这样既可在删除容器的同时也将数据卷删除。
我们还可以使用 docker volume rm 命令删除数据卷
1 | # 查看数据卷 |
删除所有的数据卷
1 | docker volume rm $(docker volume ls -f dangling=true -q) |
数据卷容器
如果有些数据,需要在多个容器之间进行共享,这时候可以使用数据卷容器
创建数据卷容器
1 | docker run --name mysql-volume -v /data mysql |
其它容器可以使用–volumes-from标识,来使用通过刚刚创建的数据卷容器,来挂载对应的数据卷
1 | $ docker run -d --volumes-from mysql-volume --name db1 mysql |
这样 db1 和 db2 两个容器都共享 mysql-volume 这个容器中的文件
挂载相同数据卷的容器,容器的停止和删除,不会对数据卷产生影响
我们也还可以对一个容器使用多个 –volumes-from 标识,来将多个数据卷桥接到这个容器中