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


    docker的理念回顾:

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

    存在问题:

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

    解决方案:

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

    在这里插入图片描述

    1、什么是容器数据卷?

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

    数据卷特性

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

    2、挂载方式

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

    1)volumes(最常用的方式)

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

    在这里插入图片描述

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

    2)bind mounts比较常用的方式

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

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

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

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

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

    示意图如下:

    在这里插入图片描述

    3、使用数据卷

    Volume 的基本使用

    # 创建一个自定义容器卷
    $ docker volume create [容器卷名]
    # 查看所有容器卷
    $ docker volume ls
    # 查看指定容器卷详情信息
    $ docker volume inspect [容器卷名]  
    # 删除自定义数据卷
    $ docker volume rm [容器卷名]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    直接使用命令来挂载 -v

    # -v 代表挂载数据卷 目录以 / 开头
    docker run -it -v [主机目录|容器卷名]:[容器内目录]
    
    # 如果没有通过 -v 指定,那么Docker会默认帮我们创建匿名数据卷进行映射和挂载。
    
    • 1
    • 2
    • 3
    • 4

    测试

    [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"
                }
    ....
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    再次测试

    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    在这里插入图片描述

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

    5、具名挂载和匿名挂载

    5.1、匿名挂载

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

    例如:

    docker run -d -P --name nginx -v /etc/nginx nginx
    
    • 1

    5.2、具名挂载

    给挂载位置添加名字

    例如:

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

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

    5.3、判断挂载方式

    # 如何确定具名挂载还是指定路径挂载
    -v 容器内路径        # 匿名挂载
    -v 卷名:容器内路径     # 具名挂载
    -v /宿主机路径:容器内路径  # 指定路径挂载
    
    • 1
    • 2
    • 3
    • 4

    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 就说明这个路径只能通过宿主机来操作,容器内部是无法操作的!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6、初识 DockerFile

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

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

    测试

    1、准备工作

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

    2、编写内容

    # 2、编写内容
    FROM centos
    
    VOLUME ["volume01","volume02"]
    
    CMD echo "-----end-----"
    CMD /bin/bash
    
    # 这里每个命令就是镜像的一层
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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
    
    • 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

    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
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

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

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

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

    7、数据卷容器

    多个mysql同步数据!

    在这里插入图片描述

    被挂载的容器是父容器。

    测试

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

    # 启动 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再启动一个容器

    # 启动 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    再启动一个容器 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 上的数据卷也同步了这个文件。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    命令的理解:

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

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

    只要通过 --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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结论

    • 容器之间配置信息的传递,存储在本机的文件则会一直保留!数据卷的生命周期一直持续到没有容器使用它为止。
    • 一旦持久化到了本地,本地的数据是不会删除的!
  • 相关阅读:
    JavaEE初阶学习:JVM(八股文)
    SpringBoot整合RabbitMQ图文过程以及RabbitTemplate常用API介绍
    35.cuBLAS开发指南中文版--cuBLAS中的Level-2函数hbmv()
    软件架构简介
    基于51单片机的简易可调时钟闹钟Proteus仿真
    高校教师资格证备考
    【mindspore训练】modelzoo-resnet50模型训练后验证
    Qt多线程http下载器之三:文件下载异常的处理
    华为eNSP配置专题-浮动路由及BFD的配置
    亿某通电子文档安全管理系统任意文件上传漏洞 CNVD-2022-43886
  • 原文地址:https://blog.csdn.net/weixin_43989102/article/details/125610176