Docker利用数据卷实现容器数据持久化
docker容器的分层
容器的数据分层目录
LowerDir: image 镜像层,即镜像本身,只读
UpperDir: 容器的上层,可读写,容器变化的数据存放在此处,创建好容器,修改了数据,新生的的修改数据放在此处
MergedDir: 容器的文件系统,使用Union FS(联合文件系统)将lowerdir 和 upperdir 合并完成后给容器使用,最终呈现给用户的统一视图
WorkDir: 容器在宿主机的工作目录,挂载后内容会被清空,且在使用过程中其内容用户不可见
查看分层信息
[root@ubuntu2004 ~]#docker inspect nginx
哪些数据需要持久化
有状态的协议:通信双方要记住双方,并且共享一些信息
无状态的协议:通信每次都是独立的,与上一次的通讯没什么关系
容器数据持久保存方式
数据卷(Data Volume): 直接将宿主机目录挂载至容器的指定的目录,推荐使用此种方式,此方式较常用
数据卷容器(Data Volume Container): 间接使用宿主机空间,数据卷容器是将宿主机的目录挂载至 一个专门的数据卷容器,然后让其他容器通过数据卷容器读写宿主机的数据 ,此方式不常用
数据卷分类
启动容器时,可以指定使用数据卷实现容器数据的持久化,数据卷有三种
1、指定宿主机目录或文件: 指定宿主机的具体路径和容器路径的挂载关系,此方式不会创建数据卷
2、匿名卷: 不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载,此方式会创建匿名数据卷,Dockerfile中VOLUME指定的卷即为此种
3、命名卷: 指定数据卷的名称和容器路径的挂载关系,此方式会创建命名数据卷
数据卷使用方法
ro 从容器内对此数据卷是只读,不写此项默认为可读可写
rw 从容器内对此数据卷可读可写,此为默认值
-v 指定方式
方式一:
#指定宿主机目录或文件格式:
-v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro] #将宿主机目录挂载容器目录,两个目录都可自动创建
案例:
[root@ubuntu2004 nginx]#docker run -d -p 80:80 --name nginx01 -v /opt/test:/data/test/ nginx:v1.22.0-1
目录自动生成
[root@ubuntu2004 nginx]#ls /opt/test/
进入容器查看是否生成目录
[root@ubuntu2004 nginx]#docker exec -it nginx01 bash
root@ef408ca4a833:/# ls /data/test/
在宿主机建文件去容器查看是否有这个文件
[root@ubuntu2004 nginx]#cd /opt/test/
[root@ubuntu2004 test]#ls
[root@ubuntu2004 test]#touch a.txt
[root@ubuntu2004 test]#ls
a.txt
容器查看
root@ef408ca4a833:/# ls /data/test/
a.txt
如果容器内目录有数据,宿主机数据一旦挂载,容器内的数据将和宿主机数据一样
容器内的数据和宿主机数据保持一致
Dockerfile就可以省略 ADD index.html.tar.gz /apps/nginx/html/ 直接放在宿主机下就可以
例如:把Dockerfile中的ADD注释#ADD index.html.tar.gz /apps/nginx/html/
重新打镜像跑容器
[root@ubuntu2004 nginx]#bash build.sh v1.22.0-1
[root@ubuntu2004 nginx]#docker run -d -p 80:80 --name nginx01 -v /opt/test:/apps/nginx/html nginx:v1.22.0-1
在宿主机写页面
[root@ubuntu2004 nginx]#cd /opt/test/
[root@ubuntu2004 test]#echo website on host > index.html
[root@ubuntu2004 test]#pwd
/opt/test
[root@ubuntu2004 test]#ls
a.txt index.html
访问
[root@ubuntu2004 test]#curl 10.0.0.101
website on host
在宿主机上更新,容器上的也更新了
方式二:匿名卷
#匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷ID>/_data目录,并挂载至容器指定路径
-v <容器内路径>
示例:
[root@ubuntu2004]#docker run -d -p 80:80 --name nginx01 -v /nginx/www nginx:v1.22.0-1
查看宿主机生成的匿名卷
[root@ubuntu2004 test]#ls /var/lib/docker/volumes/ -lt
total 36
drwx-----x 3 root root 4096 Oct 20 10:45 7a52ae7e7fc8baa0fab14e5e7db823ce2ead5723748de3d89068b8685c958daa
-rw------- 1 root root 32768 Oct 20 10:45 metadata.db
brw------- 1 root root 253, 0 Oct 20 08:48 backingFsBlockDev
drwx-----x 3 root root 4096 Oct 18 15:23 2d5607da3961bb796525b1f87d1990b75ba7c301d4ddddab7492e158f1876679
drwx-----x 3 root root 4096 Oct 18 15:16 8b58cbcb56357951d6d084fd235ab878f69b58e7f05ab0b10f73478c144f79e8
在宿主机这个目录下建个文件
[root@ubuntu2004 volumes]#touch 7a52ae7e7fc8baa0fab14e5e7db823ce2ead5723748de3d89068b8685c958daa/_data/123.txt
[root@ubuntu2004 volumes]#ls 7a52ae7e7fc8baa0fab14e5e7db823ce2ead5723748de3d89068b8685c958daa/_data/
123.txt
去容器查看
[root@ubuntu2004 volumes]#docker exec nginx01 ls -l /nginx/www
total 0
-rw-r--r-- 1 root root 0 Oct 20 10:49 123.txt
在容器建文件
root@77dfdfc3d189:/# echo hehe > /nginx/www/abc.txt
root@77dfdfc3d189:/# ls /nginx/www/
123.txt abc.txt
去宿主机查看
[root@ubuntu2004 ~]#cat /var/lib/docker/volumes/7a52ae7e7fc8baa0fab14e5e7db823ce2ead5723748de3d89068b8685c958daa/_data/abc.txt
hehe
docker rm 的-v选项可以删除容器时,同时删除相关联的匿名卷
[root@ubuntu2004 ~]#docker rm -f -v 77dfdfc3d189
方式三:命名卷
#命名卷将固定的存放在/var/lib/docker/volume/<卷名>/_data
-v <卷名>:<容器目录路径>
#可以通过以下命令事先创建,如可没有事先创建卷名,docker run时也会自动创建卷
[root@ubuntu2004 ~]#docker volume create volume1(卷名)
volume1
[root@ubuntu2004 ~]#docker inspect volume1
[
{
"CreatedAt": "2022-10-20T11:04:22+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/volume1/_data", (文件路径)
"Name": "volume1",
"Options": {},
"Scope": "local"
}
]
或[root@ubuntu2004 ~]#docker volume ls
DRIVER VOLUME NAME
local 2d5607da3961bb796525b1f87d1990b75ba7c301d4ddddab7492e158f1876679
local 8b58cbcb56357951d6d084fd235ab878f69b58e7f05ab0b10f73478c144f79e8
local volume1
创建容器关联volume1
[root@ubuntu2004 ~]#docker run -d -p 80:80 --name nginx01 -v volume1:/nginx/www nginx:v1.22.0-1
在容器下建文件
[root@ubuntu2004 ~]#docker exec nginx01 touch /nginx/www/1.txt
去/var/lib/docker/volumes/volume1/_data查看
[root@ubuntu2004 ~]#ls /var/lib/docker/volumes/volume1/_data/
1.txt
删除容器volume下的内容不会消失
#示例:docker volume create vol1 也可以是事先不创建
docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx 自动创建vol1
删除命名卷
docker volume prune (不再使用的)
docker volume rm (删除一个)
两个容器共享一个文件夹
[root@ubuntu2004 ~]#docker run -d -p 80:80 --name nginx01 -v volume1:/apps/nginx/html/ nginx:v1.22.0-1
ffd36b25c8079a3554697cc41612bfd24a323295fc71bfd7f188284c79d53b86
[root@ubuntu2004 ~]#docker run -d -p 81:80 --name nginx02 -v volume1:/apps/nginx/html/ nginx:v1.22.0-1
0e64b3c46f02ab38657928329c80737e37e41872e04b8d694e8d99b538d4e8a0
查看volume1文件下数据
[root@ubuntu2004 ~]#ls /var/lib/docker/volumes/volume1/_data/
50x.html index.html
更改index.html页面
[root@ubuntu2004 ~]#curl 10.0.0.101
share website
[root@ubuntu2004 ~]#curl 10.0.0.101:81
share website
[root@ubuntu2004 ~]#
可看出两个容器共享一个文件夹
支持只读ro
[root@ubuntu2004 ~]#docker run -d -p 82:80 --name nginx03 -v volume1:/apps/nginx/html/:ro nginx:v1.22.0-1
宿主机更改html页面
[root@ubuntu2004 ~]#curl 10.0.0.101
share websit v2
[root@ubuntu2004 ~]#curl 10.0.0.101:81
share websit v2
[root@ubuntu2004 ~]#curl 10.0.0.101:82
share websit v2
进入nginx03并更改index.html改不了数据,因为设置了只读
进入nginx02并更改index.html
[root@ubuntu2004 ~]#curl 10.0.0.101
share websit v3
[root@ubuntu2004 ~]#curl 10.0.0.101:81
share websit v3
[root@ubuntu2004 ~]#curl 10.0.0.101:82
share websit v3
大家是共享的,访问加过都变
实战案例:实现wordpress持久化
[root@ubuntu2004 ~]#docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -d -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.29-oracle
[root@ubuntu2004 ~]#docker run -d -p 80:80 --name wordpress -v /data/wordpess:/var/www/html --restart=always wordpress:php7.4-apache
[root@ubuntu2004 ~]#docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b531502419c6 wordpress:php7.4-apache "docker-entrypoint.s…" 29 seconds ago Up 28 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp wordpress
4da9913ca386 mysql:8.0.29-oracle "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql
访问宿主机IP10.0.0.101
数据库地址:10.0.0.101
数据卷容器
先创建一个容器,带数据卷功能,其他容器调用前一个容器的数据卷
第一个容器有挂载关系,剩下的容器和第一个挂载相同,直接挂载第一个容器即可,即使删除第一个容器也不影响下的的容器
例如:
docker run -d --name nginx01 -p 80:80 -v volume1:/apps/nginx/html/ -v /data1:/data1 -v /data2:/data2 nginx:v1.22.0-1
docker run -d --name nginx02 -p 81:80 --volumes-from nginx01 nginx:v1.22.0-1
docker run -d --name nginx03 -p 82:80 --volumes-from nginx01 nginx:v1.22.0-1
如果容器用的是匿名卷挂载,并且不知道其所在宿主机的volumeID,如何将容器内的数据备份下来
创建需要备份的匿名卷容器
docker run -it -v /datavolume1 --name volume-server centos bash
进入容器在/datavolume1目录下创建数据
touch /datavolume1/centos.txt
退出容器并基于前面的匿名数据卷容器创建执行备份操作的容器
docker run -it --rm --volumes-from volume-server -v ~/backup:/backup --name backup-server ubuntu
进入该容器查看/datavolume1目录下的文件
root@9ad8be4b5810:/# ls /datavolume1/
centos.txt
把/datavolume1/目录下的数据打包到容器内的/backup目录下
root@9ad8be4b5810:/# cd /datavolume1/
root@9ad8be4b5810:/datavolume1# tar cvf /backup/data.tar .
./
./centos.txt
退出容器查看当前家目录下的/backup目录
ls ~/backup/
data.tar
数据卷有几种存储方式
1、指定宿主机目录和指定容器目录
2、匿名卷:只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷ID>/_data目录,并挂载至容器指定路径
3、命名卷: <卷名>:<容器目录路径>命名卷将固定的存放在/var/lib/docker/volume/<卷名>/_data
标签:容器,ubuntu2004,10,root,宿主机,nginx,docker,数据
From: https://blog.51cto.com/mfc001/6457192