0%

Docker容器数据卷

image-20220405151429046

什么是数据卷

数据不应该放在容器中,如果容器删除,数据就会丢失!==需求:数据 持久化==

MYSQL,容器删了=删库跑路!==需求:MYSQL数据可以存储在本地==

==> 需要容器之间有一个数据共享的技术!Docker容器中产生的数据,同步到本地!

这就是卷技术!说白了就是目录的挂载,将容器内的目录,挂载到 Linux 上

image-20220405151429046

总结:容器的持久化和同步操作! 容器间也可以数据共享!

使用数据卷

方式一:直接使用命令来挂载 -V

1
2
3
4
5
6
7
8
9
10
11
12
13
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口 

# 测试
xxx@data:~$ sudo docker run -it -v /home/dutir/xxx/ceshi:/home centos /bin/bash

# 查看容器id
xxx@data:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43b6593461e7 centos "/bin/bash" 2 minutes ago Up 2 minutes quizzical_varahamihira
# 查看容器详细信息
xxx@data:~$ sudo docker inspect 43b6593461e7

# 看到挂载

image-20220405153329429

测试文件的同步

image-20220405183512106

再来测试

1
2
3
4
5
6
7
# 1.停止容器

# 2.宿主机上修改文件

# 3.启动容器

# 4.容器内的数据依旧是同步的

image-20220405183540730

好处:我们以后修改只需要在本地修改即可,容器内会自动同步!

实战:安装MySQL

思考:MySQL 的数据持久化问题,

image-20220405160002622

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 获取镜像
docker pull mysql:5.7

# 运行容器,需要做数据挂载! # 安装启动mysql。需要配置密码,这是要注意的,去docker hub官方文档看(上图)
# 官方测试 $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# -e 配置环境,这里要配置密码


# 启动我们的
-d 后台运行
-p 端口映射
-v 数据卷挂载,可挂载多个
-e 环境配置
--name 容器名字

xxx@data:~$ sudo docker run -d -p 3310:3306 -v /home/dutir/xxx/mysql_test/conf:/etc/mysql/conf.d -v /home/dutir/xxx/mysql_test/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

# 启动成功之后,我们在本地使用 sqlyog 连接测试
# sqlyog 连接到本地的3310,本地3310侦听服务器宿主机的3310,宿主机的3310和容器内的3306映射,这个时候就可以连接上了

# 在本地sqlyog测试创建一个数据库,查看一下我们映射的路径是否ok!
# test_for_docker以后,docker里多出这个数据库

image-20220405183614297

即使把容器删除

image-20220405183721449

发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器持久化功能!

具名和匿名挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 匿名挂载(不指定主机名)
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有本地volume(数据卷) 乱码的都是匿名卷
xxx@data:~$ sudo docker volume ls
DRIVER VOLUME NAME
local 51ed233d17e5c740a92f70e075335dd59cbcf913dd03390d64880893a6a6b043
local mysql_lawbda_my-db

# 这里发现,这种就是匿名挂在,我们在 -v 时只写了容器内的路径,没有写容器外的路径!


# 具名挂载
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx nginx

xxx@data:~$ sudo docker volume ls
DRIVER VOLUME NAME
local 51ed233d17e5c740a92f70e075335dd59cbcf913dd03390d64880893a6a6b043
local juming-nginx
local mysql_lawbda_my-db

# 通过 -v 卷名:容器内路径
# 查看一下这个卷(这里查看mysql_lawbda_my-db)
xxx@data:~$ sudo docker volume inspect mysql_lawbda_my-db
[
{
"CreatedAt": "2022-04-04T17:14:49+08:00",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "mysql_lawbda",
"com.docker.compose.version": "1.27.4",
"com.docker.compose.volume": "my-db"
},
"Mountpoint": "/var/lib/docker/volumes/mysql_lawbda_my-db/_data",
"Name": "mysql_lawbda_my-db",
"Options": null,
"Scope": "local"

所有达到docker容器内的卷,没有指定目录的情况下都是在/val/lib/docker/volumes/xxxx/_data

image-20220405164118444

我们通过具名挂载 可以方便找到我们的一个卷,大多数情况在使用具名挂载

1
2
3
4
5
# 如何确定是具名挂载还是匿名挂在,还是指定路径挂载!

-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载

拓展:

1
2
3
4
5
6
7
8
9
10
# 通过 -v 容器内路径:ro  rw  改变读写权限
ro read only # 只读
rw readwrite # 可读可写

# 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:rw nginx

# ro 只要看到ro,就说明这个路径只能通过宿主机来改变,容器内部是无法操作的

初识Dockerfile

方式二:生成镜像的时候就挂载出来

Dockerfile 就是用来构建 docker 镜像的构建文件! 就是一段命令脚本!先体验一下!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本就是一个一个的命令,每个命令就是一层。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建一个dockerfile文件,名字可以随机, 建议 Dockerfile
# 文件中的内容 指令(都是大写) 参数

FROM centos

VOLUME ["volume01","volume02"]

CMD echo "----end----"

CMD /bin/bash

# 这里的每个命令,就是镜像的一层!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# docker build 构建镜像
root@data:/home/dutir/xxx/docker-test-volume# docker build -f /home/dutir/xxx/docker-test-volume/dockerfile1 -t wjm/centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in eedc2cf7a5b3
Removing intermediate container eedc2cf7a5b3
---> 80396b388983
Step 3/4 : CMD echo "----end----"
---> Running in 734dc31604b0
Removing intermediate container 734dc31604b0
---> 5ef9da00ac40
Step 4/4 : CMD /bin/bash
---> Running in 593084c92533
Removing intermediate container 593084c92533
---> 8edda645979e
Successfully built 8edda645979e
Successfully tagged wjm/centos:1.0
root@data:/home/dutir/xxx/docker-test-volume#


# 启动一下自己生成的镜像
root@data:/home/dutir/xxx/docker-test-volume# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
wjm/centos 1.0 8edda645979e 4 minutes ago 231MB
root@data:/home/dutir/xxx/docker-test-volume# docker run -it 8edda645979e /bin/bash

image-20220405170430808

这个目录就是我们生成镜像时自动挂载的,数据卷目录。

这个和外部一定有一个同步的目录!dockerfile里只指定了容器内目录,一定是匿名挂载,所以容器外、宿主机上肯定有乱码的挂载。

image-20220405170800369

1
2
# docker inspect 查看容器信息
# 找到 Mounts,查看卷挂载的路径,符合匿名挂载的默认路径/var/lib/docker/volumes/xxx/

image-20220405171126981

在容器里的 volume01 下新建一个 container.txt 文件。

1
2
3
4
5
6
7
8
9
[root@4b4b467cf777 /]# ls
bin etc lib lost+found mnt proc run srv tmp var volume02
dev home lib64 media opt root sbin sys usr volume01
[root@4b4b467cf777 /]# cd volume01
[root@4b4b467cf777 volume01]# ls
[root@4b4b467cf777 volume01]# touch container.txt
[root@4b4b467cf777 volume01]# ls
container.txt
[root@4b4b467cf777 volume01]#

测试一下刚才的文件是否同步出去。

1
2
3
4
5
6
7
8
9
# 复制 Mounts 下的路径 /var/lib/docker/volumes/951ce898d681397c29606b61bb9da1102d7594f4d0cd069c4b63fbd96b171f96/_data

# cd 到这里

root@data:~# cd /var/lib/docker/volumes/951ce898d681397c29606b61bb9da1102d7594f4d0cd069c4b63fbd96b171f96/_data
root@data:/var/lib/docker/volumes/951ce898d681397c29606b61bb9da1102d7594f4d0cd069c4b63fbd96b171f96/_data# ls
container.txt # 发现新建的 container.txt 文件
root@data:/var/lib/docker/volumes/951ce898d681397c29606b61bb9da1102d7594f4d0cd069c4b63fbd96b171f96/_data#

这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!

假设构建镜像时没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径

数据卷容器

即容器和容器间同步

多个 Mysql 数据如何同步?

==所有 docker 之间共享的卷都是独立的,每个docker有自己的数据卷。新建时拷贝父容器的备份。所以只要有一份存在,数据都不会丢失。==

image-20220405172422841

1
2
3
# 启动3个容器,通过我们刚才自己写的镜像启动

# 首先启动 docker01

image-20220405172959557

1
2
3
# 启动 docker02,volume 从 docker01 继承

# docker01 就叫做数据卷容器

image-20220405173218738

在 docker01 修改数据, docker02 会同步吗?测试一下。

image-20220405173548023

回到 docker02 查看

image-20220405173743825

docker01 创建的内容同步到 docker02 了

再从 docker01 继承,启动 docker03,新建 docker03.txt

image-20220405174426597

在 docker03 里创建的文件,在 docker01 和 docker02 里都同步了。

image-20220405175122829

只要是通过 —volume-from ,我们就可以实现容器间的数据共享。

把 docker01 整个 rm 掉,docker02 和 docker03 的文件都还在。

1
2
3
4
5
6
7
8
9
# 测试:可以删除docker01,查看一下docker02和docker03是否还可以访问这个文件

# 依旧可以访问

# 测试:查看宿主机的volume,还是存在
root@data:~# cd /var/lib/docker/volumes/2bdf8b38df84ffea344d0f758e7be2c2045c54f270a9da362b12246a1d78d636/_data
root@data:/var/lib/docker/volumes/2bdf8b38df84ffea344d0f758e7be2c2045c54f270a9da362b12246a1d78d636/_data# ls
docker01.txt docker03.txt

==所有 docker 之间共享的卷都是独立的,每个docker有自己的数据卷。新建时 拷贝 父容器的备份。所以只要有一份存在,数据都不会丢失。==

回到问题:多个 Mysql 数据如何同步?

1
2
3
4
5
6
7
# -v 容器内路径,匿名挂载

xxx@data:~$ sudo docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7


# 用 --volumes-from 可以实现两个容器同步
xxx@data:~$ sudo docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 --volumes-from mysql01 mysql:5.7

结论

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止(所有容器都停止)。

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的。所以重要的文件存在宿主机上就好啦。

参考

以上是看 b 站教学视频记的笔记。

教程地址:【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili