引言
数据卷是一种持久化的解决方案,用于存储容器内应用程序的数据。数据卷允许容器之间共享数据
,并提供了可靠的数据存储
和备份机制
。由于容器是隔离环境,容器内程序的文件、配置等都在容器的内部,要读写容器内的文件非常不方便。因此容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器进行解耦。
Docker
默认将卷存储在 /var/lib/docker/volumes/
这是Docker
管理卷的内部路径,通常由Docker
自动创建和管理。不建议直接操作这个目录,除非你非常了解Docker
的内部机制。
在实际使用中,开发者通常会根据需要将容器卷挂载到特定的目录,常见的挂载路径包括:
- 适用于存储应用程序的持久化数据,如数据库文件、日志文件等。
/opt/<app-name>/data
- 适用于挂载应用程序的配置文件。
/etc/<app-name>/config
- 适用于存储应用程序的日志文件。
/var/log/<app-name>
- 适用于存储用户相关的数据。
/home/<user>/<app-name>/data
什么是数据卷
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。
以Nginx为例,我们知道Nginx中有两个关键的目录:
html
:放置一些静态资源;conf
:放置配置文件;如果我们要让Nginx代理我们的静态资源,最好是放到
html
目录;如果我们要修改Nginx的配置,最好是找到conf
下的nginx.conf
文件。
从DockerHub的nginx说明处,我们可以看到nginx静态文件的位置:
不过,容器运行的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代理了。
数据卷命令
数据卷的相关命令有:
命令 | 说明 | 文档地址 |
---|---|---|
docker volume create | 创建数据卷 | docker volume create |
docker volume ls | 查看所有数据卷 | docs.docker.com |
docker volume rm | 删除指定数据卷 | docs.docker.com |
docker volume inspect | 查看某个数据卷的详情 | docs.docker.com |
docker volume prune | 清除数据卷 | docker volume prune |
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。
数据卷的三种挂载方式
方式一:匿名挂载
匿名挂载是指没有指定特定名称的挂载方式。当您在创建容器时没有明确指定数据卷的路径名称时,Docker会在该目录/var/lib/docker/volumes
下为该数据卷创建一个匿名的、临时的卷。匿名挂载适用于临时存储或一次性使用的场景,因为它们在容器被删除后将被自动清理。
1.运行nginx容器
//以后台方式运行容器,并使用-v 匿名挂载容器数据卷 (推荐)
docker run --rm -d -p 80:80 --name nginx_volume -v /usr/share/nginx/html nginx:latest
//--rm:退出容器以后,这个容器就被删除了
//-d:表示该容器在后台运行
//-p 80:80:将容器的80接口与宿主机的80端口进行映射
//--name nginx_volume:容器名称
//-v /usr/share/nginx/html:将nginx目录中/usr/share/nginx/html挂在到宿主机/var/lib/docker/volumes下。
//注意:如果出现Docker挂载宿主机目录显示cannot open directory .:Permission denied
解决办法:在挂载目录后面 多加一个--privileged=true参数即可。
2.访问Nginx
3.查看Nginx容器详细信息
// 查看Nginx容器详细信息
docker inspect nginx_volume
// 执行结果
...
"Mounts": [
{
"Type": "volume",
"Name": "eb169266220c48dd13dee21dd41700e00f19da8d757de91b127cdda09d70e2b9",
//挂载到宿主机目录
"Source": "/var/lib/docker/volumes/eb169266220c48dd13dee21dd41700e00f19da8d757de91b127cdda09d70e2b9/_data",
//将nginx下的文件
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
// 进入宿主机的目录下
cd /var/lib/docker/volumes/eb169266220c48dd13dee21dd41700e00f19da8d757de91b127cdda09d70e2b9/_data
// 列表展示
ll
//执行结果
-rw-r--r-- 1 root root 497 Dec 28 2021 50x.html
-rw-r--r-- 1 root root 615 Dec 28 2021 index.html
//将index.html中的所有东西替换为'Hello Docker'
echo 'Hello Docker' > index.html
4.再次访问Nginx
5.进入Nginx容器内部
//进入Nginx容器内部
docker exec -it nginx_volume /bin/bash
//查看 Nginx 容器的 index.html
cat /usr/share/nginx/html/index.html
//执行结果
Hello Docker
//我们在Nginx容器中创建一个test.html并修改index.html
echo 'Test' > test.html
echo 'Hello Container' > index.html
//进入宿主机的Nginx文件目录中
cd /var/lib/docker/volumes/eb169266220c48dd13dee21dd41700e00f19da8d757de91b127cdda09d70e2b9/_data
// 查看文件列表
ls
//执行结果
50x.html index.html test.html
//查看文件
cat index.html
//执行结果
Hello Container
6.再次访问Nginx
- 默认访问的是index.html
- 访问test.html
- 停止容器
// 停止容器
docker stop nginx
//查看数据卷
docker volume ls
//因为我们启动容器使用`docker run --rm -d -p 80:80 --name nginx_volume -v /usr/share/nginx/html nginx:latest`进行启动,rm表示退出容器以后,这个容器就被删除了。但是数据卷也是随之删除。
由以上案例可知,在使用匿名卷时,会在宿主机目录
/var/lib/docker/volumes
路径下自动生成目录(或文件),当我们修改宿主机的文件时,容器中的的文件也会被修改。当我们修改容器中的文件时,宿主机的文件也会被修改。且匿名绑定的volume在容器被删除的时候,数据卷也会被删除。
方式二:具名挂载
具名挂载是指通过指定一个唯一的名称来挂载数据卷的方式。使用具名挂载,您可以为数据卷提供一个明确的、可预测的名称,以便在多个容器之间共享和重用。具名挂载的数据卷在容器删除后仍然存在,除非您明确删除该卷。
1.运行nginx容器
// 1.以后台方式运行容器
docker run --rm -d -p 80:80 --name nginx_volume -v nginx-volume:/usr/share/nginx/html nginx:latest
//--rm:退出容器以后,这个容器就被删除了
//-d:表示该容器在后台运行
//-p 80:80:将容器的80接口与宿主机的80端口进行映射
//--name nginx_volume:容器名称
//-v nginx-volume:/usr/share/nginx/html :将nginx目录中/usr/share/nginx/html挂在到宿主机/var/lib/docker/volumes/nginx-volume/_data下。并将数据卷名称改为nginx-volume
// 2.查看已启动的容器信息
docker ps
//执行结果
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a50508c919bc nginx:latest "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx_volume
// 3.查看数据卷列表
docker volume ls
//执行结果
DRIVER VOLUME NAME
local nginx-volume
// 4.查看容器详细信息
docker inspect nginx_volume
//执行结果
...
"Mounts": [
{
"Type": "volume",
"Name": "nginx-volume",
//将容器中该路径/usr/share/nginx/html下的文件挂载到"/var/lib/docker/volumes/nginx-volume/_data"下
"Source": "/var/lib/docker/volumes/nginx-volume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
...
//进入该路径/var/lib/docker/volumes/nginx-volume/_data下
cd /var/lib/docker/volumes/nginx-volume/_data
//查看该路径下的文件列表
ls
//执行结果
50x.html index.html
//echo "Hello Host" > test.html
//echo "Hello Index" > index.html
访问Nginx页面
- 访问 index.html
- 访问 test.html
3.进入容器修改文件
//进入Nginx容器中
docker exec -it nginx_volume /bin/bash
//进入该目录下
cd /usr/share/nginx/html
//将"Hello Container Test"写入 test.html 中
echo "Hello Container Test" > test.html
//将"Hello Container Index"写入 index.html 中
echo "Hello Container Index" > index.html
4.访问Nginx页面
- 访问 index.html
- 访问 test.html
5.删除容器
//强制删除数据卷时,不会删除数据卷,而是会删除这个容器本身的东西
docker rm -f nginx_volume
//查看已启动容器,查询不到nginx_volume容器
docker ps
//数据卷列表
docker volume ls
//执行结果:
DRIVER VOLUME NAME
local nginx-volume
//删除数据卷
docker volume rm nginx-volume
docker volume ls//查询不到数据卷
//执行一下命令重新运行这个容器,然后停止这个容器,查询数据卷时发现数据卷还在
docker run --rm -d -p 80:80 --name nginx_volume -v nginx-volume:/usr/share/nginx/html nginx:latest
docker stop nginx_volume
docker ps
docker volume ls
由以上案例可知,在使用具名卷时,会在宿主机目录
/var/lib/docker/volumes
路径下自动生成目录(或文件),当我们修改宿主机的文件时,容器中的的文件也会被修改。当我们修改容器中的文件时,宿主机的文件也会被修改。且具名绑定的volume在容器被删除的时候,数据卷不会被删除,除非指定docker volume rm 数据卷名称
删除数据卷。
方式三:Bind Mount(推荐)
绑定并加载主机的某一个文件目录到容器中,这种方式是最平常最常用的。这种绑定方式与前面两种一样。
//将"Hello Host"写入到/wuke/wolfcode/index.html下面
echo "Hello Host" > /wuke/wolfcode/index.html
//以后台方式运行容器,并将/usr/share/nginx/html的所有目录文件替换为/wuke/wolfcode下的index.html
docker run --rm -d -p 80:80 --name nginx_volume -v /wuke/wolfcode:/usr/share/nginx/html nginx:latest
//--rm:退出容器以后,这个容器就被删除了
//-d:表示该容器在后台运行
//-p 80:80:将容器的80接口与宿主机的80端口进行映射
//--name nginx_volume:容器名称
//-v /wuke/wolfcode:/usr/share/nginx/html:将宿主机/wuke/wolfcode下的目录文件映射到容器/usr/share/nginx/html下。
访问Nginx页面
//停掉nginx_volume容器
docker stop nginx_volume
//停掉nginx_volume容器,但是主机/wuke/wolfcode/index.html下的文件是不会被删除的。
docker ps
cd /wuke/wolfcode
ls
该Bind Mount是开发过程中使用最多的,即使我们容器被删除了,而主机中的数据文件是不会被删除的。