Docker学习04:数据管理
一、概述
默认情况下,在容器内创建的所有文件都存储在可写容器层上。这意味着:
- 当该容器不再存在时,数据将不会持久保存,并且如果另一个进程需要它,则可能很难从容器中取出数据。
- 容器的可写层与运行容器的主机紧密耦合。您不能轻易地将数据移动到其他地方。
- 写入容器的可写层需要 存储驱动程序来管理文件系统。存储驱动程序使用Linux内核提供联合文件系统。与使用直接写入主机文件系统的数据卷相比,这种额外的抽象降低了性能 。
Docker为容器提供了两个选项来将文件存储在主机中,以便即使容器停止后文件也可以持久存储:卷和 绑定安装。如果您在Linux上运行Docker,则还可以使用tmpfs挂载。如果您在Windows上运行Docker,则还可以使用命名管道。
二、Docker 支持的存储类型
Volumes
存储在主机文件系统的一部分中,该文件系统由Docker管理(/var/lib/docker/volumes/
在Linux上)。非Docker进程不应修改文件系统的这一部分。卷是在Docker中持久保存数据的最佳方法。
Bind mounts
可以存储在主机系统上的任何位置。它们甚至可能是重要的系统文件或目录。Docker主机或Docker容器上的非Docker进程可以随时对其进行修改
tmpfs mounts
仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统中。容器在其生存期内可以使用它来存储非持久状态或敏感信息。
三、类型的适用场景
Volumes
将数据持久保存在Docker容器和服务中的首选方法。卷的一些用例包括:
-
在多个运行中的容器之间共享数据。如果未显式创建卷,则在首次将卷安装到容器中时将创建该卷。当该容器停止或卸下时,该卷仍然存在。多个容器可以同时装载相同的卷(读写或只读)。仅在显式删除卷时才将它们删除。
-
不保证Docker主机具有给定的目录或文件结构时。卷可帮助您将Docker主机的配置与容器运行时解耦。
-
当您要将容器的数据存储在远程主机或云提供商上时,而不是在本地。
-
当您需要将数据从一个Docker主机备份,还原或迁移到另一个Docker主机时,卷是一个更好的选择。您可以停止使用该卷的容器,然后备份该卷的目录(例如
/var/lib/docker/volumes/
)。
Bind mounts
通常应尽可能使用Volumes
。Bind mounts适用于以下类型的用例:
- 将配置文件从主机共享到容器。
- 在Docker主机上的开发环境和容器之间共享源代码或构建工件。例如,您可以将Maven
target/
目录安装到容器中,并且每次在Docker主机上构建Maven项目时,该容器都可以访问重建的工件。 - 当确保Docker主机的文件或目录结构与容器所需的
bind mounts
一致时。
tmpfs mounts
最适合用于不希望数据在主机上或容器中持久存储的情况。
如果使用Bind mounts或volumes
- 如果将空卷装入存在文件或目录的容器中的目录中,则这些文件或目录将传播(复制)到该卷中。同样,如果启动一个容器并指定一个尚不存在的卷,则会为您创建一个空卷。这是预填充另一个容器所需数据的好方法。
- 如果将bind mount或非空的volumes卷到存在某些文件或目录的容器中的目录中,则这些文件或目录会被安装遮盖,就像您将文件保存到
/mnt
Linux主机上然后再安装时一样。 USB驱动器插入/mnt
。的内容/mnt
将由USB驱动器,直至USB驱动器的内容被遮蔽被卸载。不会删除或更改被遮盖的文件,但是在装入绑定安装或卷时将无法访问这些文件。
四、volume的基本使用
volume
是存储Docker容器生成和使用的数据的首选机制。
最初,
-v
or--volume
标志用于独立容器,而--mount
标志用于集群服务。但是,从Docker 17.06开始,您还可以使用--mount
独立容器。总的来说,--mount
是更明确和冗长的。最大的区别是该-v
语法将所有选项合并在一个字段中,而--mount
语法将它们分开。官方更推荐使用--mount
4.1 管理卷
创建卷
# docker volume create my-vol
my-vol
卷清单
# docker volume ls
DRIVER VOLUME NAME
local my-vol
卷信息
# docker volume inspect my-vol
[
{
"CreatedAt": "2020-04-02T19:15:03+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
清除卷
# docker volume rm my-vol
my-vol
删除本地未使用的卷
// 删除所有容器
[aaa@qq.com ~]# docker rm -f `docker ps -a -q`
13447424224e
5c1bbb404fc9
4775f33b42fd
// 查看本地卷
[aaa@qq.com ~]# docker volume ls
DRIVER VOLUME NAME
local nginx-vol
local nginx-vol01
// 删除未使用的卷,因为所有容器都删除了。现在所有卷都未被使用
[aaa@qq.com ~]# docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
nginx-vol
nginx-vol01
Total reclaimed space: 2.212kB
4.2 创建使用指定卷的容器
如果使用不存在的卷启动容器,Docker将自动创建该卷。
// 使用 --mount 创建容器
[aaa@qq.com ~]# docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
// 使用 -v 创建
[aaa@qq.com ~]# docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
检验卷是否创建与挂载正确
[aaa@qq.com ~]# docker inspect nginx-vol
//查找mounts 字段
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol",
"Source": "/var/lib/docker/volumes/nginx-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": false,
"Propagation": ""
}
],
删除正在使用卷的方法
//停止运行使用该卷的容器,container可以省去
[aaa@qq.com ~]# docker stop nginx-vol
//删除容器
[aaa@qq.com ~]# docker container rm nginx-vol
//删除卷
[aaa@qq.com ~]# docker volume rm nginx-vol
4.3 设置只读卷
// --mount方式
[aaa@qq.com ~]# docker run -d \
--name=nginxtest01 \
--mount source=nginx-vol01,destination=/usr/share/nginx/html,readonly \
nginx:latest
// -v方式
[aaa@qq.com ~]# docker run -d \
--name=nginxtest01 \
-v nginx-vol01:/usr/share/nginx/html:ro \
nginx:latest
检验是否正确创建
[aaa@qq.com ~]# docker inspect nginxtest01
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol01",
"Source": "/var/lib/docker/volumes/nginx-vol01/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "ro", //权限,ro只读
"RW": false,
"Propagation": ""
}
],
4.4 使用共享卷
创建一个容器
//容器名称webapp,映射端口81,使用webapp卷
[aaa@qq.com ~]# docker run -d -p 81:80 \
--name=webapp \
--mount source=webapp,destination=/usr/share/nginx/html \
nginx:latest
往卷中写入一个html文件
[aaa@qq.com ~]# echo "Hello Docker" >/var/lib/docker/volumes/webapp/_data/hello.html
[aaa@qq.com ~]# ls /var/lib/docker/volumes/webapp/_data/
50x.html hello.html index.html
访问容器测试
[aaa@qq.com ~]# curl 127.0.0.1:81/hello.html
Hello Docker
创建一个新的容器,使用webapp卷
//容器名称webapp01,映射端口82,使用webapp卷
[aaa@qq.com ~]# docker run -d -p 82:80 \
--name=webapp01 \
--mount source=webapp,destination=/usr/share/nginx/html \
nginx:latest
访问容器测试
[aaa@qq.com ~]# curl 127.0.0.1:82/hello.html
Hello Docker
五、bind volume的基本使用
使用bind volume
时,会将主机上的文件或目录安装到容器中,文件或目录由主机上的完整或相对路径引用。
使用bind volume时,绑定目录必须存在。
如果挂载目标在容器中为非空目录,则该目录现有内容将被隐藏。
5.1 使用 bind mount启动容器
创建容器挂载目录
[aaa@qq.com ~]# mkdir -p /code/www
[aaa@qq.com ~]# echo 'this is bind volume!!!' >/code/www/index.html
启动容器(–mount 方式)
[aaa@qq.com ~]# docker run -d -it -p8081:80 --name devtest --mount type=bind,source=/code/www,target=/usr/share/nginx/html/ nginx:latest
进容器查看
[aaa@qq.com ~]# docker exec -it devtest bash
aaa@qq.com:/# cat /usr/share/nginx/html/idenx.html
this is bind volume!!!
访问测试
[aaa@qq.com ~]# curl 127.0.0.1:8081
this is bind volume!!!
在启动一个容器(-v方式)
[aaa@qq.com ~]# docker run -d -it -p8082:80 --name devtest01 -v /code/www:/usr/share/nginx/html/ nginx:latest
访问测试
[aaa@qq.com ~]# curl 127.0.0.1:8082
this is bind volume!!!
修改/code/www
下的index文件
[aaa@qq.com ~]# echo 'onelpc.com docker ' >/code/www/index.html
[aaa@qq.com ~]# cat /code/www/index.html
onelpc.com docker
访问容器测试
[aaa@qq.com ~]# curl 127.0.0.1:8081
onelpc.com docker
[aaa@qq.com ~]# curl 127.0.0.1:8082
onelpc.com docker
5.2 验证绑定
[aaa@qq.com ~]# docker inspect devtest
"Mounts": [
{
"Type": "bind", //类型
"Source": "/code/www", //宿主机目录
"Destination": "/usr/share/nginx/html", //挂载到容器中的目录
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],