Docker——容器数据卷

  1. 为什么需要容器数据卷

    角度:遇到问题,尝试以朴素的道理解决问题.问题复杂化,解决的方式也变得复杂

    问题的提出:docker将应用和环境打包成一个镜像,但是对于容器内的数据,如果不进行外部的保存,那么当容器删除后,数据也会丢失

    解决:通过docker的容器数据卷技术,实现容器数据的持久化和同步操作!同时容器间也是可以数据共享的!

    实现:目录的挂载,将我们容器内的目录,挂载到Linux上面,使两者之间相互对应

  2. 使用数据卷

    建议使用两个终端进行调试

    • docker run -v 主机目录地址:容器目录地址:将主机目录地址与对应的容器目录地址进行双向绑定

      v:类似vue的v-model双向绑定(注:v-bind和v-model的区别在于v-bind多用于单向绑定,比如字段的显示;v-model则多用于表单,比如input中输入的返回等)

      测试:

      #运行一个容器,同时制定行管的目录
      [root@iZwz908j8pbqd86doyrez5Z test]# docker run -d -it -v /test:/root/test -p 8081:8080 tomcat:9.0 /bin/bash
      a5c3db57e2b230db84a9d273e2379d55b47b47bc07f5630d16a35d1e5fc0c3b0
      [root@iZwz908j8pbqd86doyrez5Z test]# docker ps
      CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
      a5c3db57e2b2        tomcat:9.0          "/bin/bash"         14 seconds ago      Up 14 seconds       0.0.0.0:8081->8080/tcp   sad_tu
      [root@iZwz908j8pbqd86doyrez5Z test]# docker attach a5c3db57e2b2
      
      #从元数据中查看绑定情况
      "Mounts": [
      {
      "Type": "bind",
      "Source": "/root/test",  //源文件位置(主机)
      "Destination": "/root/test",  //目标文件位置(容器)
      "Mode": "",
      "RW": true,
      "Propagation": "rprivate"
      }
      ]
      
      #尝试从容器写入主机
      #容器
      [root@6eec281a5e9f test]# mkdir test1
      [root@6eec281a5e9f test]# ls
      test.java  test1
      #主机
      [root@iZwz908j8pbqd86doyrez5Z test]# ls
      test1  test.java
      
      #尝试从主机写入容器
      #主机
      [root@iZwz908j8pbqd86doyrez5Z test]# touch a.tets
      [root@iZwz908j8pbqd86doyrez5Z test]# ls
      a.tets  test1  test.java
      #容器
      [root@6eec281a5e9f test]# ls
      a.tets	test.java  test1
      

      注:

      • -it:以交互的形式打开终端,-d:在后台运行
      • 只有在运行时用-it...bash,才能在之后用attach打开一个命令行
      • 主次关系来说,其实还是主机的目录覆盖容器的目录

      优点:修改只需在本地修改即可,容器内会自动同步

  3. 安装mysql完成挂载

    mysql所有数据都在data目录下

    #下载镜像
    docker pull mysql:5.7
    
    #在使用挂载对mysql的相关目录覆盖之前,我们需要保证目录中有所需要的东西
    #新建一下目录:/usr/arno/mysql/conf,/usr/arno/mysql/data
    #打开一个不需要挂载的mysql容器,将容器内对应的数据复制到新建的目录中
    [root@iZwz908j8pbqd86doyrez5Z conf]# docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 mysql:5.7
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker cp ad7db127211a:/etc/mysql/conf.d /usr/arno/mysql/conf
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker cp ad7db127211a:/var/lib/mysql /usr/arno/mysql/data
    
    #运行镜像(同时对mysql的conf和data进行了挂载)
    docker run -d -p 3310:3306 -v /usr/arno/mysql/conf:/etc/mysql/conf.d -v /usr/arno/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
    
    #尝试通过navicat访问(需要配置阿里云安全组)
    #(1).连接成功(欧耶!)
    #(2).新建一个数据库(test)
    
    #查看主机中的data
    [root@iZwz908j8pbqd86doyrez5Z data]# ls
    auto.cnf    client-cert.pem  ibdata1      ibtmp1              private_key.pem  server-key.pem
    ca-key.pem  client-key.pem   ib_logfile0  mysql               public_key.pem   sys
    ca.pem      ib_buffer_pool   ib_logfile1  performance_schema  server-cert.pem  test
    
    #查看容器中的数据库
    root@78c6defe3428:/var/lib/mysql# ls
    auto.cnf    client-cert.pem  ib_logfile0  ibtmp1	      private_key.pem  server-key.pem
    ca-key.pem  client-key.pem   ib_logfile1  mysql		      public_key.pem   sys
    ca.pem	    ib_buffer_pool   ibdata1	  performance_schema  server-cert.pem  test
    
    #完美!
    

    注:

    • 通过hub.docker搜查mysql,以便完成mysql密码的配置$ docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
    • 注意:挂载的开始,主机的目录会覆盖容器的目录,所以你的目录必须一开始就要有对应的文件.解决方法就是运行一个不挂载的容器,然后将所有东西都用docker cp 容器id:目录 要主机目录命令拷贝到主机目录下(但更好的方法是使用下面的具名挂载)
  4. 具名挂载与匿名挂载

    #1.匿名挂载
    -v 容器内路径
    docker run -d -P --name nginx01 -v /etc/nginx nginx
    
    #查看所有挂载的卷
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker volume ls  
    DRIVER              VOLUME NAME
    local               2e364979e68adc93ea6ac8075250d0f41488c62b0345db8a917f8571df312992
    local               811aa7cb9f25b11fffb8a6e3490726f6d85b28f73147a7bceb8096288aa70163
    local               c1abdabde73dcf238913e7f51aa4bcd726f170a474d3282f704f19bc86f40be0
    local               f0e7e07b67bf298bdf8c3d420f93c5851c0cfa313669cfd1887f4a3210e73c62
    #匿名卷挂载形式(在-v时只写了容器内的路径,没有写容器外的路径)
    
    #通过原数据查看匿名挂载的卷
    "Mounts": [
    {
    "Type": "volume",
    "Name": "811aa7cb9f25b11fffb8a6e3490726f6d85b28f73147a7bceb8096288aa70163",  #对应的匿名
    "Source": "/var/lib/docker/volumes/811aa7cb9f25b11fffb8a6e3490726f6d85b28f73147a7bceb8096288aa70163/_data",
    #匿名挂载对应的主机路径
    "Destination": "-etc/nginx",  #匿名挂载对应的容器路径
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    }
    
    #2.具名挂载
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker run -d -P --name nginx02 -v volume:/etc/nginx nginx
    d4a2fed1744e7c8ed2e3febe35612842a01eb8379d159b437de752e0b6c25ca1
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker volume ls
    DRIVER              VOLUME NAME
    local               2e364979e68adc93ea6ac8075250d0f41488c62b0345db8a917f8571df312992
    local               811aa7cb9f25b11fffb8a6e3490726f6d85b28f73147a7bceb8096288aa70163
    local               c1abdabde73dcf238913e7f51aa4bcd726f170a474d3282f704f19bc86f40be0
    local               f0e7e07b67bf298bdf8c3d420f93c5851c0cfa313669cfd1887f4a3210e73c62
    local               volume
    
    #查看具名挂载的目录
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker inspect volume
    [
        {
            "CreatedAt": "2020-09-12T09:03:07+08:00",
            "Driver": "local",
            "Labels": null,
            "Mountpoint": "/var/lib/docker/volumes/volume/_data",
            "Name": "volume",
            "Options": null,
            "Scope": "local"
        }
    ]
    
    #查看元数据中的挂载
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker inspect nginx02
    "Mounts": [
    {
    "Type": "volume",
    "Name": "volume",
    "Source": "/var/lib/docker/volumes/volume/_data",  #主机目录
    "Destination": "/etc/nginx",  #容器目录
    "Driver": "local",
    "Mode": "z",
    "RW": true,
    "Propagation": ""
    }
    ]
    

    注:

    • -P(大p):随机映射端口

    • 所有的docker容器内的卷,没有指定目录的情况下都是docker 在/var/lib/docker/volume/xxxx/_data

    • 挂载形式 指定挂载路径 有名字
      匿名挂载 false false
      指定路径挂载 true false
      具名挂载 true true

    如何区分具名挂载,匿名挂载,还是具名指定路径挂载?

    -v 容器内路径 #匿名挂载

    -v 卷名:容器内路径 #具名挂载

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

    拓展:

    # 通过-v容器内路径,ro/rw改变读写权限
    docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx  #只读
    docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx  #只写
    

    注:只读的挂载卷只能通过宿主机来操作

  5. 初始Dockerfile

    Dockerfile就是用来构建docker镜像的构建文件和命令脚本.由于镜像是分层的,每个命令也对应一层

    #创建一个名为docker file1的文件,同时进入编辑
    vim dockerfile1
    
    #写命令(指令大写)
    FROM centos  #以centos为基础
    VOLUME ["volumen01","volume02"]  #在生成时挂载卷,匿名挂载,volume01/volume02是内部的文件
    CMD echo "----end----"
    CMD  /bin/bash  #以指令台的形式打开
    #保存退出:esc -> :wq
    
    #查看编写的文件脚本
    car dockerfile1
    
    #生成dockerfile
    [root@iZwz908j8pbqd86doyrez5Z test]# docker build -f dockerfile1 -t arno/centos:1.0 .
    Sending build context to Docker daemon  3.584kB
    Step 1/4 : FROM centos
     ---> 0d120b6ccaa8
    Step 2/4 : VOLUME ["volumen01","volume02"]
     ---> Running in e9fd99177a57
    Removing intermediate container e9fd99177a57
     ---> 4b51c5ece9de
    Step 3/4 : CMD echo "---end---"
     ---> Running in 17fc5ba5da77
    Removing intermediate container 17fc5ba5da77
     ---> ba8b29cc064e
    Step 4/4 : CMD /bin/bash
     ---> Running in 047d5ced7a4b
    Removing intermediate container 047d5ced7a4b
     ---> bbbedbad86c6
    Successfully built bbbedbad86c6
    Successfully tagged arno/centos:1.0
    #-f 生成的文件
    #-t 生成的文件名:tag 生成的文件位置(当时当前目录)
    
    #运行容器
    [root@iZwz908j8pbqd86doyrez5Z test]# docker run -it arno/centos:1.0 /bin/bash
    [root@652cd9f64f74 /]# ls
    bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var	   volumen01
    dev  home  lib64  media       opt  root  sbin  sys  usr  volume02#可以看到有volume01和volume02两个文件
    
    #查看挂载的数据卷
    [root@iZwz908j8pbqd86doyrez5Z ~]# docker inspect 652cd9f64f74
    "Mounts": [
    {
    "Type": "volume",
    "Name": "7fe986067800aa48085b302336faa270d7df53ba65d4eb3e0964eaee6f50796a",  #匿名
    "Source": "/var/lib/docker/volumes/7fe986067800aa48085b302336faa270d7df53ba65d4eb3e0964eaee6f50796a/_data",
    "Destination": "volume02",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    },
    {
    "Type": "volume",
    "Name": "a5e71c3f49495c1b02fa559b92fb65ecc6dee0a1ce7fd3d2fa77b2dc1341e739",  #匿名
    "Source": "/var/lib/docker/volumes/a5e71c3f49495c1b02fa559b92fb65ecc6dee0a1ce7fd3d2fa77b2dc1341e739/_data",
    "Destination": "volumen01",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    }
    ],
    
    #测试
    #在容器中生成一个/volumen01/test.txt文件
    [root@652cd9f64f74 /]# cd volumen01
    [root@652cd9f64f74 volumen01]# touch test.txt
    [root@652cd9f64f74 volumen01]# ls
    test.txt
    #在主机中查看(直接复制元数据中mounts的source路径即可)
    [root@iZwz908j8pbqd86doyrez5Z _data]# cd /var/lib/docker/volumes/a5e71c3f49495c1b02fa559b92fb65ecc6dee0a1ce7fd3d2fa77b2dc1341e739/_data
    [root@iZwz908j8pbqd86doyrez5Z _data]# ls
    test.txt
    #验证完毕!
    
  6. 数据卷容器

    多个容器间的数据共享

    注意容器数据卷和数据卷容器的区别:

    • 容器的数据卷
    • 数据卷的容器:子容器挂载父容器(数据卷的容器)的数据,实现数据的同步
    #使用
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker run -d -it --name docker01 arno/centos:1.0
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker run -it --name docker02 --volumes-from docker01  arno/centos:1.0  #docker01的数据挂载到docker02上
    
    #验证
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker attach docker01
    [root@5bd780fa7cad /]# ls
    bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var	   volumen01
    dev  home  lib64  media       opt  root  sbin  sys  usr  volume02
    [root@5bd780fa7cad /]# cd volumen01
    [root@5bd780fa7cad volumen01]# touch test.txt
    [root@5bd780fa7cad volumen01]# ls
    test.txt
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker attach docker02
    [root@56e0c6ac0d64 /]# ls
    bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var	   volumen01
    dev  home  lib64  media       opt  root  sbin  sys  usr  volume02
    [root@56e0c6ac0d64 /]# cd volumen01
    [root@56e0c6ac0d64 volumen01]# ls
    test.txt
    
    #查看元数据
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker inspect docker01
    "Mounts": [
    {
    "Type": "volume",
    "Name": "9c60002316aa06044c718bd6728a9c4e71865b3127773461f65a82354e26d70c",
    "Source": "/var/lib/docker/volumes/9c60002316aa06044c718bd6728a9c4e71865b3127773461f65a82354e26d70c/_data",
    "Destination": "volume02",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    },
    {
    "Type": "volume",
    "Name": "e0584a1a806735c297b08629bb9ab4b1d419bbdc9a61fb5f526618a6096802b0",
    "Source": "/var/lib/docker/volumes/e0584a1a806735c297b08629bb9ab4b1d419bbdc9a61fb5f526618a6096802b0/_data",
    "Destination": "volumen01",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    }
    ],
    
    [root@iZwz908j8pbqd86doyrez5Z _data]# docker inspect docker02
    "Mounts": [
    {
    "Type": "volume",
    "Name": "9c60002316aa06044c718bd6728a9c4e71865b3127773461f65a82354e26d70c",
    "Source": "/var/lib/docker/volumes/9c60002316aa06044c718bd6728a9c4e71865b3127773461f65a82354e26d70c/_data",
    "Destination": "volume02",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    },
    {
    "Type": "volume",
    "Name": "e0584a1a806735c297b08629bb9ab4b1d419bbdc9a61fb5f526618a6096802b0",
    "Source": "/var/lib/docker/volumes/e0584a1a806735c297b08629bb9ab4b1d419bbdc9a61fb5f526618a6096802b0/_data",
    "Destination": "volumen01",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
    }
    ],
    
    #可以看到匿名挂载下,挂载的是同一个路径
    

    注:

    • 虽然挂载的时候有主次的关系,但是数据是互通的
    • 删除父容器,子容器内的数据还是能访问到,因为各个容器的数据卷真实主机地址的文件位置没有删
    • 主机->父容器->子容器,主机挂载数据卷到父容器,父容器作为数据卷容器对子容器挂载
    • 挂载的时候,本地一定会有对应的卷
posted @ 2020-09-15 16:23  Arno_vc  阅读(144)  评论(0编辑  收藏  举报