Docker 学习笔记(六)-- 容器数据卷

docker的理念回顾:

将应用和运行的环境一起打包形成一个镜像发布出去。

存在问题:

如果我们的数据都在容器中,那么我们把容器删除之后,数据就会丢失。假如有个MySQL容器,如果将这个容器删了,那存的数据也没有了。

解决方案:

所以我们想要数据持久化。我们需要**容器的持久化和同步操作,容器间也是可以数据共享的。**就出现了容器数据卷的技术,容器之间有一个数据共享的技术。docker容器产生的数据同步到本地。说白了就是目录的挂载,将我们容器的目录挂载到Linux上面。

Docker 学习笔记(六)-- 容器数据卷_第1张图片

1、什么是容器数据卷?

数据卷(Data Volumes)是宿主机中的一个目录或文件,数据卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。当容器目录和数据卷目录绑定后,对方的修改会立即同步,一个数据卷可以被多个容器同时挂载,一个容器也可以被挂载多个数据卷。

数据卷特性

  • 数据卷可以在容器之间共享和重用,本地与容器间传递数据更高效
  • 对数据卷的修改会立马有效,在容器内部与本地目录均可对数据卷进行修改
  • 对数据卷的更新,不会影响镜像,对数据与应用进行了解耦操作
  • 卷会一直存在,直到没有容器使用

2、挂载方式

目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中:

1)volumes(最常用的方式)

Docker管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录中;

Docker 学习笔记(六)-- 容器数据卷_第2张图片

如果在创建时没有指定卷,Docker会默认创建许多匿名(就上面这一堆很长ID的名字)卷。

2)bind mounts比较常用的方式

意为着可以存储在宿主机系统的任意位置;

但是 bind mount 在不同的宿主机系统时不可移植的,比如 Windows 和 Linux 的目录结构是不一样的,bind mount 所指向的 host 目录也不能一样。

这也是为什么 bind mount 不能出现在 Dockerfile 中的原因,因为这样 Dockerfile 就不可移植了。

3)tmpfs(一般都不会用的方式)

挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统;

示意图如下:

Docker 学习笔记(六)-- 容器数据卷_第3张图片

3、使用数据卷

Volume 的基本使用

# 创建一个自定义容器卷
$ docker volume create [容器卷名]
# 查看所有容器卷
$ docker volume ls
# 查看指定容器卷详情信息
$ docker volume inspect [容器卷名]  
# 删除自定义数据卷
$ docker volume rm [容器卷名]

直接使用命令来挂载 -v

# -v 代表挂载数据卷 目录以 / 开头
docker run -it -v [主机目录|容器卷名]:[容器内目录]

# 如果没有通过 -v 指定,那么Docker会默认帮我们创建匿名数据卷进行映射和挂载。

测试

[root@localhost volumes]$ docker run -id -v /home/ceshi:/home centos /bin/bash 
c525e970834d3e4b97fdb696151b9fd9d6c35cfab3c723db6bc3e8de4e1a581e
[root@localhost volumes]$ docker ps
CONTAINER ID   IMAGE   	COMMAND             CREATED             STATUS             PORTS                   NAMES
c525e970834d   centos   "/bin/bash"         16 seconds ago      Up 14 seconds                           unruffled_sammet
[root@localhost volumes]$ docker inspect c525e970834d
.....
        "Mounts": [			# 挂载
            {
                "Type": "bind",
                "Source": "/home/ceshi",	# 主机内目录
                "Destination": "/home",		# 容器内目录
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
....

Docker 学习笔记(六)-- 容器数据卷_第4张图片

再次测试

1、停止容器

2、宿主机上修改文件

3、启动容器

4、容器的数据依旧是同步的

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

4、练习 MySQL数据同步

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

# 下载镜像
docker pull mysql:5.7

-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字

# 运行容器,需要做数据挂载
# 注意:安装MySQL的时候是需要配置密码的
# 官方例子:https://hub.docker.com/_/mysql
# $ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 启动命令  
docker run -d -p 3306:3306 --name mysql \
-v /home/mysql/conf:/etc/mysql \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=root mysql:5.7

# 启动成功之后,使用 Navicat 连接测试
# 防火墙记得开启 3306 端口 账号:root

新建 test 数据库做测试,可以看到生成的数据库的文件被挂载出了:

Docker 学习笔记(六)-- 容器数据卷_第5张图片

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

5、具名挂载和匿名挂载

5.1、匿名挂载

不指定挂载到主机上的路径,只指定容器内部需要挂载的目录。

例如:

docker run -d -P --name nginx -v /etc/nginx nginx
5.2、具名挂载

给挂载位置添加名字

例如:

# -v 卷名:容器内目录
docker run -d -P --name nginx -v juming-nginx:/etc/nginx nginx

默认位于 /var/lib/docker/volumes 目录中

5.3、判断挂载方式
# 如何确定具名挂载还是指定路径挂载
-v 容器内路径        # 匿名挂载
-v 卷名:容器内路径     # 具名挂载
-v /宿主机路径:容器内路径  # 指定路径挂载
5.4、拓展
# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly  # 只读
rw readwrite # 可读可写

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

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

6、初识 DockerFile

DockerFile 就是用来构建 docker 镜像的构建文件!本质是命令脚本!

通过脚本生成镜像,镜像是一层一层的,脚本一个一个命令,每个命令都是一层!

测试

1、准备工作

# 1、在 /home 目录下新建一个docker-test-volume 文件夹
mkdir docker-test-volume
# 在编写 DockerFile 文件中使用 VOLUME 指令来给镜像添加一个或多个数据卷
vim dockerfile1

2、编写内容

# 2、编写内容
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "-----end-----"
CMD /bin/bash

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

3、构建镜像

# 3、build后生成镜像,获得一个新镜像 mianbao/centos
# . 表示当前目录
[root@localhost docker-test-volume]$ docker build -f /home/docker-test-volume/dockerfile1 -t mianbao/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 8e82ebee8002
Removing intermediate container 8e82ebee8002
 ---> c305de8aa209
Step 3/4 : CMD echo "-----end-----"
 ---> Running in 8cd33b47383f
Removing intermediate container 8cd33b47383f
 ---> b682a519e338
Step 4/4 : CMD /bin/bash
 ---> Running in 9778993b03c3
Removing intermediate container 9778993b03c3
 ---> 17b534236794
Successfully built 17b534236794
Successfully tagged mianbao/centos:1.0
[root@localhost docker-test-volume]$ docker images
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
mianbao/centos           1.0       17b534236794   22 seconds ago   231MB

4、启动容器

[root@localhost docker-test-volume]$ docker run -it 17b534236794 /bin/bash
[root@ac30d43bfd39 /]$ ls -l
total 0
lrwxrwxrwx.   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x.   5 root root 360 Jun 29 15:47 dev
drwxr-xr-x.   1 root root  66 Jun 29 15:47 etc
drwxr-xr-x.   2 root root   6 Nov  3  2020 home
lrwxrwxrwx.   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------.   2 root root   6 Sep 15  2021 lost+found
drwxr-xr-x.   2 root root   6 Nov  3  2020 media
drwxr-xr-x.   2 root root   6 Nov  3  2020 mnt
drwxr-xr-x.   2 root root   6 Nov  3  2020 opt
dr-xr-xr-x. 105 root root   0 Jun 29 15:47 proc
dr-xr-x---.   2 root root 162 Sep 15  2021 root
drwxr-xr-x.  11 root root 163 Sep 15  2021 run
lrwxrwxrwx.   1 root root   8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3  2020 srv
dr-xr-xr-x.  13 root root   0 Jun 29 15:18 sys
drwxrwxrwt.   7 root root 171 Sep 15  2021 tmp
drwxr-xr-x.  12 root root 144 Sep 15  2021 usr
drwxr-xr-x.  20 root root 262 Sep 15  2021 var
# 这个目录就是我们生成镜像时自动挂载的,数据卷目录!(匿名挂载)
drwxr-xr-x.   2 root root   6 Jun 29 15:47 volume01
drwxr-xr-x.   2 root root   6 Jun 29 15:47 volume02

# 在容器内创建文件测试
[root@723ec0b590f5 /]$ cd volume01
[root@723ec0b590f5 volume01]$ touch container.txt
[root@723ec0b590f5 volume01]$ ls
container.txt

5、查看挂载的目录

[root@localhost ~]$ docker ps
CONTAINER ID   IMAGE    	   COMMAND        CREATED         STATUS          PORTS             NAMES
723ec0b590f5   17b534236794    "/bin/bash"    2 minutes ago   Up 2 minutes                      nice_roentgen
[root@localhost ~]$ docker inspect 723ec0b590f5

Docker 学习笔记(六)-- 容器数据卷_第6张图片

在容器外查看挂载的目录是否有该文件

[root@localhost ~]$ cd /var/lib/docker/volumes/16e62338a333ac0640c982f28dd89a975d17a73757d77c3509b479b8cb9205be/_data
[root@localhost _data]$ ls
container.txt

这种方式未来使用的较多 ,因为我们通常会构建自己的镜像!
假设构建镜像时没有挂载卷,就要手动镜像挂载 -v 卷名:容器内路径!

7、数据卷容器

多个mysql同步数据!

Docker 学习笔记(六)-- 容器数据卷_第7张图片

被挂载的容器是父容器。

测试

启动三个容器,通过我们刚才自己写的镜像启动

# 启动 docker01 容器
[root@localhost ~]$ docker run -it --name docker01 mianbao/centos:1.0 
[root@5c2f15dec8a5 /]$ ls -l
................
# 数据卷
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume01
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume02

[root@localhost ~]$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED         STATUS         PORTS     NAMES
5c2f15dec8a5   mianbao/centos:1.0   "/bin/sh -c /bin/bash"   2 minutes ago   Up 2 minutes             docker01

再启动一个容器

# 启动 docker02 容器
[root@localhost ~]$ docker run -it --name docker02 --volumes-from docker01  mianbao/centos:1.0 
[root@7ee3ba5906c9 /]$ ls -l
...............
# 数据卷
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume01
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume02

docker01 这个容器中创建文件:

# 进入 docker01 容器
[root@localhost ~]$ docker attach 5c2f15dec8a5
[root@5c2f15dec8a5 /]$ ls -l
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume01
drwxr-xr-x.   2 root root   6 Jun 30 14:45 volume02
# 查看数据卷下文件,为空
[root@5c2f15dec8a5 /]$ cd volume01/
[root@5c2f15dec8a5 volume01]$ ls -l
total 0
# 创建文件
[root@5c2f15dec8a5 volume01]$ touch docker01 

再查看 docker02volume01 文件夹下是否同步了这个文件:

# 查看数据卷下文件,已同步
[root@7ee3ba5906c9 /]$ cd volume01/
[root@7ee3ba5906c9 volume01]$ ls -l
total 0
-rw-r--r--. 1 root root 0 Jun 30 14:53 docker01

再启动一个容器 docker03

[root@localhost ~]$ docker run -it --name docker03 --volumes-from docker01  mianbao/centos:1.0 
[root@83d670962cc1 /]$ cd volume01
[root@83d670962cc1 volume01]$ ls
docker01
[root@83d670962cc1 volume01]$ touch docker03
[root@83d670962cc1 volume01]$ ls
docker01  docker03

# docker01 和 docker02 上的数据卷也同步了这个文件。

命令的理解:

  --volumes-from    docker01
# son extend father 数据卷容器

第一个容器删了,另外两个的数据卷文件也都还在!

只要通过 --volumes-from [容器名] 就能实现容器间的数据共享。

**理解:**容器共享宿主机的某个文件夹,共享文件夹里的内容是可以双向操作的,但是删除容器以后,只是解除了被删除容器的共享连接,并没有操作共享文件夹的内容,所以共享的文件还在,其他容器还能正常实现数据共享。

MySQL 实现数据共享

docker run -d -p 3305:3306 --name mysql_01 \
-v /home/mysql/conf:/etc/mysql \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=root mysql:5.7

docker run -d -p 3306:3306 --name mysql_02 \
--volumes-from mysql_01 \
-e MYSQL_ROOT_PASSWORD=root mysql:5.7

结论

  • 容器之间配置信息的传递,存储在本机的文件则会一直保留!数据卷的生命周期一直持续到没有容器使用它为止。
  • 一旦持久化到了本地,本地的数据是不会删除的!

你可能感兴趣的:(Docker,docker,数据卷)