Docker 存储管理
小丫么小牛马 人气:0前言
在本文内容中,我们将讨论 Docker 中管理数据的几种方式,涉及将数据从 Docker 主机挂载到容器中的不同方法。
一、存储
通过之前的学习,我们学习了有关于容器和镜像的一些知识。对于数据来说,我们可以将其保存在容器中,但是会存在一些缺点:
- 当容器不再运行时,我们无法使用数据,并且容器被删除时,数据并不会被保存。
- 数据保存在容器中的可写层中,我们无法轻松的将数据移动到其他地方。
针对上述的缺点而言,有些数据信息,例如我们的数据库文件,我们不应该将其保存在镜像或者容器的可写层中。Docker 提供三种不同的方式将数据从 Docker 主机挂载到容器中,分别为卷(volumes
),绑定挂载(bind mounts
),临时文件系统(tmpfs
)。很多时候,volumes 总是正确的选择。
volumes
卷存储在 Docker 管理的主机文件系统的一部分中(/var/lib/docker/volumes/
)中,完全由 Docker 管理。bind mounts
绑定挂载,可以将主机上的文件或目录挂载到容器中。tmpfs
仅存储在主机系统的内存中,而不会写入主机的文件系统。
无论使用上述的哪一种方式,数据在容器内看上去都是一样的。它被认为容器文件系统中的目录或单个文件。
二、卷列表
对于三种不同的存储数据的方式来说,卷是唯一完全由 Docker 管理的。它更容易备份或迁移,并且我们可以使用 Docker CLI
命令来管理卷。
列出本地可用的卷列表可以使用如下命令:
docker volume ls
运行之后,你可能会看到一些环境中预置镜像对应的卷,或者显示为空。
创建卷
创建卷我们可以直接使用如下命令:
docker volume create
上述命令会创建一个数据卷,并且会随机生成一个名称。创建之后我们可以查看卷列表:
docker volume ls
这种由系统随机生成名称的创建卷的方式被称为 匿名卷,直接使用该卷需要指定卷名,即自动生成的 ID,所以创建卷时一般手动指定其 name,例如我们创建一个名为 volume1 的卷。
docker volume create volume1
挂载卷
创建卷之后,我们可以用卷来启动一个容器,这里首先需要学习 docker container run 命令的两个参数:
-v
或--volume
由三个由冒号(:)分隔的字段组成,[HOST-DIR:]CONTAINER-DIR[:OPTIONS]
。
HOST-DIR
代表主机上的目录或数据卷的名字。省略该部分时,会自动创建一个匿名卷。如果是指定主机上的目录,需要使用绝对路径。CONTAINER-DIR
代表将要挂载到容器中的目录或文件,即表现为容器中的某个目录或文件。OPTIONS
代表配置,例如设置为只读权限(ro
),此卷仅能被该容器使用(Z
),或者可以被多个容器使用(z
)。多个配置项由逗号分隔。
例如,我们使用 -v volume1:/volume1:ro,z
。代表的是意思是将卷 volume1
挂载到容器中的 /volume1
目录。ro,z
代表该卷被设置为只读(ro
),并且可以多个容器使用该卷(z
)。
--mount
由多个键值对组成,键值对之间由逗号分隔。
例如:type=volume,source=volume1,destination=/volume1,ro=true
。
type
,指定类型,可以指定为bind
,volume
,tmpfs
。source
,当类型为volume
时,指定卷名称,匿名卷时省略该字段。- 当类型为
bind
,指定路径。可以使用缩写src
。 destination
,挂载到容器中的路径。可以使用缩写dst
或target
。ro
为配置项,多个配置项直接由逗号分隔一般使用 true 或false
。
针对上述创建的卷 volume1
,用其来运行一个容器就可以使用如下命令:
docker container run \ -it \ --name niuma001 \ -v volume1:/volume1 \ --rm ubuntu /bin/bash
或者我们也可以使用 --mount
,其语法格式如下:
docker container run \ -it --name niuma002 \ --mount type=volume,src=volume1,target=/volume1 \ --rm ubuntu /bin/bash
从命令中,可以很明显的得出,--mount
的可读性更好。所以,推荐大家使用 --mount
。
在 docker container run
中我们使用了参数 --rm
,它的作用在容器退出时删除容器。这里我们创建的镜像只是希望它短期运行,其用户数据并无保留的必要,因而可以在容器启动时设置 --rm
选项,这样在容器退出时就能够自动清理容器内部的文件系统。
值得注意的是,后台运行的容器无法使用 -d
与 --rm
选项。
上述操作,我们分别运行了两个容器,并分别挂载了一个卷,还可多次使用该参数挂载多个卷或目录。并且对于这两个容器来说,由于我们使用的是同一个卷,所以他们将共享该数据卷,但是对于多个容器共享数据卷时,需要注意并发性。大家可以分别连接到两个容器中,操作数据,验证其是同步的,这里就不再详细演示了。
三、绑定挂载
对于数据卷来说,其优点在于方便管理。而对于绑定挂载 bind-mounts
来说,通过将主机上的目录绑定到容器中,容器就可以操作和修改主机上该目录的内容。这既是其优点也是其缺点。
例如,我们将 /home/xiaoniuma
目录挂载到容器中的 `/home/xiaoniuma 目录下,使用的命令如下:
docker container run \ -it \ -v /home/xiaoniuma:/home/xiaoniuma \ --name xiaoniuma003 \ --rm ubuntu /bin/bash
而如果使用的是 --mount,相应的语句如下:
docker container run \ -it \ --mount type=bind,src=/home/xiaoniuma,target=/home/xiaoniuma \ --name xiaoniuma004 \ --rm ubuntu /bin/bash
如果绑定挂载时指定的容器目录是非空的,则该目录中的内容将会被覆盖。并且如果主机上的目录不存在,会自动创建该目录。
上述两个操作针对的是目录,而对于挂载文件来说,可能会出现一些特殊情况,涉及到绑定挂载和使用卷的区别。下面我们重现这一操作:
1.首先在当前目录,即 /home/xiaoniuma 目录下,创建一个 test.txt 文件。并向其中写入文本内容 “test1”:
echo "test1" > test.txt
2.接着创建一个容器 xiaoniuma005,将 test.txt 文件挂载到容器中的 /test.txt 文件,并查看容器中 /test.txt 文件的内容:
docker container run \ -it \ -v /home/xiaoniuma/test.txt:/test.txt \ --name xiaoniuma005 ubuntu /bin/bash
3.这时新打开一个终端,通过 echo
命令向 /home/xiaoniuma/test.txt
文件追加内容 “test2”,并在容器中查看 /test.txt
文件的内容:
echo "test2" >> test.txt
4.这时无论是在容器中还是主机上都能查看到该文件的内容。接下来在主机上查看 test.txt
的 inode 号。
使用 VIM 编辑该文件,添加 “test3”,并查看该文件的内容:
如上图所示,在主机上使用 VIM 编辑后,通过 VIM 做出的修改不能在容器中查看到。这是因为 VIM 编辑保存文件的时候,会将文件内容写入到一个新的文件中,保存好后,删除掉原来的文件,并将新文件重命名,从而完成保存的操作。但是我们标识文件是通过 inode
,因此 Docker 绑定的主机文件,依旧是 VIM 编辑之前的 inode
,即旧文件。所以容器中看到的,依然是旧的内容。
对于数据卷来说,由 Docker 完全管理,而绑定挂载,则需要我们自己去维护。我们需要自己手动去处理这些问题,这些问题并不仅仅是上面演示的内容,还可能有用户权限,SELINUX
等问题。
最后简单说一下临时文件系统 tmpfs
。它只存储在主机的内存中。当容器停止时,相应的数据就会被移除。
docker run \ -it \ --mount type=tmpfs,target=/test \ --name xiaoniuma008 \ --rm ubuntu bash
四、数据卷容器
如果容器之间需要共享一些持续更新的数据,最简单的方式就是使用用户数据卷容器。其他容器通过挂载这个容器实现数据共享,这个挂载数据卷的容器就叫做数据卷容器。数据卷容器就是一种普通容器,它专门提供数据卷供其它容器挂载使用。
首先,我们创建一个数据卷和数据卷容器,执行的命令如下:
# 创建一个名为 vdata 的数据卷 docker volume create vdata # 创建一个挂载了 vdata 的容器,这个容器就是数据卷容器 docker container run \ -it \ -v vdata:/vdata \ --name XiaoniumaVolume ubuntu /bin/bash # 在 /vdata 目录下创建一个文本文件 echo "I am XiaoniumaVolume" > /vdata/f.txt
接下来我们分别打开新的终端输入以下命令,创建两个容器,在执行 docker container run
时,我们添加参数 --volumes-from
继承数据卷容器 XiaoniumaVolume
挂载的数据卷。进入容器后分别创建文件
# 创建容器 test1 docker container run \ -it \ --volumes-from XiaoniumaVolume \ --name test1 ubuntu /bin/bash # 查看 vdata 目录是否存在 ls -dl /vdata/ # 创建一个文件,并写入内容 echo "I am test1" > /vdata/test1.txt
同样的,我们执行上述操作,创建容器 test2。
# 创建容器 test2 docker container run \ -it \ --volumes-from XiaoniumaVolume \ --name test2 ubuntu /bin/bash # 查看 vdata 目录是否存在 ls -dl /vdata/ # 创建一个文件,并写入内容 echo "I am test2" > /vdata/test2.txt
我们进入到 XiaoniumaVolume 容器所在的终端,在挂载的数据中查看文件的内容:
# 查看数据卷中的内容 ls -al /vdata/
从上图的结果中我们可以看到,数据卷在三个容器之间是共享的。
五、数据备份
数据存在于数据卷中,如果我们想要备份它,可以采用创建备份容器的方式。
docker container run \ --volumes-from XiaoniumaVolume \ -v /home/xiaoniuma/backup:/backup \ ubuntu tar cvf /backup/backup.tar /vdata/
--volumes-from XiaoniumaVolume
使得备份容器继承容器XiaoniumaVolumeVolume
的数据卷。-v /home/xiaoniuma/backup:/backup
把/home/xiaoniuma/backup
目录采用绑定挂载的方式,挂载到容器的/backup
目录上。tar cvf /backup/backup.tar /vdata
容器中执行了这么一条压缩归档命令,将/vdata
中的全部数据打包到了/backup/backup.tar
,而刚刚的数据绑定,使得整个压缩包存在于主机中,从而达到了数据备份的效果。
如上图所示,数据卷中的所有数据都被打包到了 /home/xiaoniuma/backup 目录中。
六、数据恢复
与数据备份相同的方式,我们可以使用如下命令创建恢复容器,来还原数据卷中的数据。
docker container run \ --volumes-from XiaoniumaVolume \ -v /home/xiaoniuma/backup:/backup \ ubuntu tar xvf /backup/backup.tar -C /
这里解压的路径为 / 即 /vdata 的上一级目录。由于与数据备份非常相似,这里不再给出结果分析。
总结
本文主要使用三种不同的方式将数据从 Docker 主机挂载到容器中,分别为卷(volumes
),绑定挂载(bind mounts
),临时文件系统(tmpfs
)。还介绍了数据卷容器、数据卷的备份与恢复。
下文讲解Docker网络管理。
加载全部内容