docker的镜像是由多个只读的文件系统叠加在一起形成的。当我们在我启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。
两种方式:
为了很好的实现数据保存和数据共享,Docker提出了Volume这个概念,简单的说就是绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。又被称作数据卷。
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:
Docker中提供了两种挂载方式,-v和-mount。
下面展开介绍。
格式:
docker run -it --name c1 -v /宿主机目录:/docker目录 -d imagename
--name: 为容器起名字
-p:宿主机端口:docker端口 (端口映射)
-v:宿主机目录:docker目录 (必须为绝对路径)
如:
docker run -it --name xxxx -p 8888:8888 -v /my:/docker -d imagename
/my:宿主机目录
/docker:容器的数据目录
匿名挂载,具名挂载,指定路径挂载的命令区别如下:
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
1.创建数据卷
docker volume create my-vol
2.查看所有的数据卷
$ docker volume ls
local my-vol
3.查看指定数据卷的信息
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
4.删除数据卷 docker volume rm …
$ docker volume rm my-vol
5.删除容器之时删除相关的卷
$ docker rm -v ...
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷 。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。
*无主的数据卷可能会占据很多空间,要清理请使用以下命令
$ docker volume prune
6.使用数据卷来挂载:
具名挂载&匿名挂载
(1)匿名挂载:-v 容器内路径
docker run -it -p 3306:3306 \
--name mysql \
-v /var/lib/mysql \
-d mysql:8.0.21
当你docker volume ls,会看到如下:
local c5ed47ea84c7ccb620d97a2cfecdcfb8944720526afc7295e5bb26023dada859(匿名)
这种数据都是匿名挂载的,因为 我们在 -v 挂载数据卷的时候 没有指定 容器外的路径。
(2)具名挂载:docker -v 卷名:容器内路径
docker run -it -p 3306:3306 \
--name mysql \
-v mysql_volume:/var/lib/mysql \
-d mysql:8.0.21
当你docker volume ls,会看到如下:
DRIVER VOLUME NAME
local mysql_volume(具名挂载)
mysql_volume就是我的数据卷名,它在docker默认位置。
7.使用 --mount创建数据卷
挂载一个主机目录作为数据卷。
使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去。
$ docker run -it -p 3306:3306 \
--name mysql \
# -v /src/mysql:/var/lib/mysql \
--mount type=bind,source=/src/mysql,target=/var/lib/mysql \
-d mysql:8.0.21
上面的命令挂载主机的/src/mysql目录到容器的/var/lib/mysql目录。用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。
8.Docker 挂载主机目录的默认权限是读写 ,用户也可以通过添加readonly 参数指定为只读 。
$ docker run -it -p 3306:3306 \
--name mysql \
# -v /src/mysql:/var/lib/mysql \
--mount type=bind,source=/src/mysql,target=/var/lib/mysql,readonly \
-d mysql:8.0.21
加了readonly之后,就挂载为只读了。如果你在容器内/src/mysql目录新建文件,会显示如下错误
/src/mysql # touch new.txt
touch: new.txt: Read-only file system
小结:
平时使用的时候 尽量使用 指定路径挂载和 具名挂载,
-v /容器内路径 匿名挂载
-v 卷名:/容器内路径 具名挂载
-v /宿主机路径:/容器内路径 指定路径挂载
数据卷权限:
-v 容器内路径:ro Readonly 只读
-v 容器内路径:rw Readwrite 可读可写
默认是可读可写
如果我们有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。
常见的使用场景是使用纯数据容器来持久化数据库、配置文件或者数据文件等。
数据卷容器:其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
数据共享: 如果想要实现容器间的数据共享,那么需要授权一个容器访问另一个容器的Volume。我们可以在使用docker run时使用-volumes-from参数来进行指定。
如:docker run -it -h NEWCONTAINER --volumes-from shanlei-nginx ubuntu /bin/bash
注意:值得注意的是不管shanlei-nginx是否运行,它都会起作用。只要有容器连接Volume,它就不会被删除。
1.首先我们需要先创建一个数据卷容器
docker run -d -v /dbdata --name dbdata mysql:8.0.21 echo Data-only container for mysql
2.然后通过–volumes-from指令参数来挂载 dbdata 容器中的数据卷。
docker run -d --volumes-from dbdata --name data1 mysql:8.0.21
也可以使用多个 --volumes-from 参数来从多个容器挂载多个数据卷。也可以从其他已经挂载了数据卷的容器来挂载数据卷。
docker run -d --name data3 --volumes-from data1 mysql:8.0.21
3.查看数据卷容器是否挂载成功:
docker exec -it data1 /bin/bash
注意:如果删除了挂载的容器(包括 dbdata、data1 和 data2等),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 docker rm -v 命令来指定同时删除关联的容器。
利用数据卷对其中的数据进行进行备份、恢复和迁移。
备份:
使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从本地主机挂载当前到容器的 /backup 目录。命令如下:
docker run --volumes-from dbdata -v $(pwd):/backup ubuntu
tar cvf /backup/backup.tar /dbdata
容器启动后,使用了 tar 命令来将 dbdata 卷备份为本地的 /backup/backup.tar 。
恢复:
如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。
docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后创建另一个容器,挂载 dbdata2 的容器,并使用 untar 解压备份文件到挂载的容器卷中。
docker run --volumes-from dbdata2 -v $(pwd):/backup busybox
tar xvf /backup/backup.tar