案例一需求:
编辑
数据卷
容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题:
- 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
- MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?
- 我想要让Nginx代理我的静态资源怎么办?
因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
什么是数据卷
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。
以Nginx为例,我们知道Nginx中有两个关键的目录:
-
html
:放置一些静态资源
-
conf
:放置配置文件
如果我们要让Nginx代理我们的静态资源,最好是放到html
目录;如果我们要修改Nginx的配置,最好是找到conf
下的nginx.conf
文件。
但遗憾的是,容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:
编辑
在上图中:
- 我们创建了两个数据卷:
conf
、html
- Nginx容器内部的
conf
目录和html
目录分别与两个数据卷关联。
- 而数据卷conf和html分别指向了宿主机的
/var/lib/docker/volumes/conf/_data
目录和/var/lib/docker/volumes/html/_data
目录
这样以来,容器内的conf
和html
目录就 与宿主机的conf
和html
目录关联起来,我们称为挂载。此时,我们操作宿主机的/var/lib/docker/volumes/html/_data
就是在操作容器内的/usr/share/nginx/html/_data
目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。
小提示:
/var/lib/docker/volumes
这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为/数据卷名/_data
。
为什么不让容器目录直接指向宿主机目录呢?
- 因为直接指向宿主机目录就与宿主机强耦合了,如果切换了环境,宿主机目录就可能发生改变了。由于容器一旦创建,目录挂载就无法修改,这样容器就无法正常工作了。
- 但是容器指向数据卷,一个逻辑名称,而数据卷再指向宿主机目录,就不存在强耦合。如果宿主机目录发生改变,只要改变数据卷与宿主机目录之间的映射关系即可。
不过,我们通过由于数据卷目录比较深,不好寻找,通常我们也允许让容器直接与宿主机目录挂载而不使用数据卷
数据卷命令
数据卷的相关命令有
docker volume create |
创建数据卷 |
docker volume ls |
查看所有数据卷 |
docker volume rm |
删除指定数据卷 |
docker volume inspect |
查看某个数据卷的详情 |
docker volume prune |
清除数据卷 |
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
也可以通过docker volume --help命令查看所有的数据卷命令
编辑
演示一下nginx的html目录挂载:
# 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷 docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx # 2.然后查看数据卷 docker volume ls # 结果 DRIVER VOLUME NAME local 29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f local html # 3.查看数据卷详情 docker volume inspect html # 结果 [ { "CreatedAt": "2024-05-17T19:57:08+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/html/_data", "Name": "html", "Options": null, "Scope": "local" } ] # 4.查看/var/lib/docker/volumes/html/_data目录 ll /var/lib/docker/volumes/html/_data # 可以看到与nginx的html目录内容一样,结果如下: 总用量 8 -rw-r--r--. 1 root root 497 12月 28 2021 50x.html -rw-r--r--. 1 root root 615 12月 28 2021 index.html # 5.进入该目录,并随意修改index.html内容 cd /var/lib/docker/volumes/html/_data vi index.html # 6.打开页面,查看效果 # 7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化 docker exec -it nginx bash
编辑
通过docker volume inspect html查看卷的详细信息
编辑
案例2:mysql容器的数据挂载
编辑
演示一下MySQL的匿名数据卷:
# 1.查看MySQL容器详细信息 docker inspect mysql # 关注其中.Config.Volumes部分和.Mounts部分
编辑
可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义。这就是匿名卷。
然后,我们再看结果中的.Mounts
部分:
"Mounts": [ { "Type": "volume", "Name": "9ee75ea3ab90cfd5abcca1bd8c5b24e90aacdd05ced48d8d5c6ac678cb827489", "Source": "/var/lib/docker/volumes/9ee75ea3ab90cfd5abcca1bd8c5b24e90aacdd05ced48d8d5c6ac678cb827489/_data", "Destination": "/var/lib/mysql", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ],
可以发现,其中有几个关键属性:
- Name:数据卷名称。由于定义容器未设置容器名,这里的就是匿名卷自动生成的名字,一串hash值。
- Source:宿主机目录
- Destination : 容器内的目录
上述配置是将容器内的/var/lib/mysql
这个目录,与数据卷9ee75ea3ab90cfd5abcca1bd8c5b24e90aacdd05ced48d8d5c6ac678cb827489
挂载。于是在宿主机中就有了/var/lib/docker/volumes/9ee75ea3ab90cfd5abcca1bd8c5b24e90aacdd05ced48d8d5c6ac678cb827489/_data
这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。
接下来,可以查看该目录下的MySQL的data文件:
编辑
编辑
挂载本地目录或文件
可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:
# 挂载本地目录 -v 本地目录:容器内目录 # 挂载本地文件 -v 本地文件:容器内文件
注意:本地目录或文件必须以 /
或 ./
开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
例如:
-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷 -v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
演示,删除并重新创建mysql容器,并完成本地目录挂载:
- 挂载
/root/mysql/data
到容器内的/var/lib/mysql
目录
- 挂载
/root/mysql/init
到容器内的/docker-entrypoint-initdb.d
目录(初始化的SQL脚本目录)
- 挂载
/root/mysql/conf
到容器内的/etc/mysql/conf.d
目录(这个是MySQL配置文件目录)