Docker互联一 Volum

1  基于Docker Volum的容器互联

1.1 Docker的文件存储

docker的文件系统是copy on write方式的, 文件是一层层往上叠加的, 最下的一层是只读的, 要修改的时候会复制这层只读的覆盖在只读的上面作为一层可写的, 这个时候原来的只读文件依然是存在的这是看不到了

docker 中镜像的存储就是使用的上述方式,分层结构如下

 

 

 

上图Docker的容器就是通过只读的镜像上面覆盖的可写层, 要想把这个可写层持久化, 就要用到之前的讲的 docker commit 了

但是镜像的层次又可以共享:

 

 

 

镜像是分层叠加的, 顶层的镜像依赖于底层的镜像, 容器是通过镜像 Copy On Write 一个可写层, 这个可写层 Commit 就完成了持久化又成了一个新的镜像. 

Docker镜像的存储位置:

docker的镜像是分层的,一个镜像往往是多个镜像分层叠加出来的, 镜像的分层信息是存储在 Docker Graph 里面

这里记录了镜像有些那些层,   每一层的父层和大小等信息

 

 

 

其中 GrapDB 存储的是分层结构 , Repository 里面存储是镜像的信息, 两者结合得到镜像的分层信息

但是这些里面存储都是镜像的信息, 并不是镜像的实际存储位置,

镜像的二进制文件存储位置是. /var/lib/docker/<storage-driver>

<storage-driver> 是  Docker Graph Driver , 不同的 Docker Graph Driver 会存储在不同的目录, 比如本机采用的是 overlay2

[root@localhost data]# cd /var/lib/docker/
[root@localhost docker]# ll
total 20
drwx------.  2 root root   24 Feb 17 15:43 builder
drwx--x--x.  3 root root   20 Feb 17 15:43 containerd
drwx------. 17 root root 4096 Feb 22 16:50 containers
drwx------.  3 root root   22 Feb 17 14:26 image
drwxr-x---.  3 root root   19 Feb 17 14:26 network
drwx------. 61 root root 8192 Feb 22 16:50 overlay2
drwx------.  4 root root   32 Feb 17 14:26 plugins
drwx------.  2 root root    6 Feb 22 16:48 runtimes
drwx------.  2 root root    6 Feb 17 14:26 swarm
drwx------.  2 root root    6 Feb 22 16:48 tmp
drwx------.  2 root root    6 Feb 17 14:26 trust
drwx------.  6 root root 4096 Feb 22 16:50 volumes
[root@localhost docker]# 

Docker Graph Driver 是Docker 使用来管理存储镜像每层内容及可读写的容器的驱动, 目前主要有 DeviceMapper、AUFS、Overlay、Overlay2、Btrfs、ZFS 等,不同的存储驱动实现方式有差异,镜像组织形式可能也稍有不同,但都采用栈式存储,并采用 Copy-on-Write策略。且存储驱动采用热插拔架构,可动态调整。

Aufs driverDocker最早支持的driver,但是aufs只是Linux内核的一个补丁集

Device mapperLinux 2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,是LVM2的核心,支持块级别的copy on write特性目前,除少数版本如UbuntuDocker基本运行在Devicemapper基础上VFS虚拟文件系统的最大缺陷是不支持copy on write特性,每层都是一个单独的目录,如果新增一个child层,则需要将父级层镜像文件一并复制到新目录

btrfs 非常快,采用btrfs的文件系统级的快照能力来实现layer分层功能,缺点是仍然在进化中,还不够成熟,特别是大量写操作的压力下 

Graph Driver 就类似于Java连接数据库的 JDBC, 只不过这个驱动是用于 docker Deamon 来对镜像个容器进行读写.

 

 

 

选择策略:

  • 若内核支持多种存储驱动,且没有显式配置,Docker 会根据它内部设置的优先级来选择。优先级为 AUFS > Btrfs/ZFS > Overlay2 > Overlay > DeviceMapper。若使用 DeviceMapper 的话,在生产环境,一定要选择 direct-lvm, loopback-lvm 性能非常差。
  • 选择会受限于 Docker 版本、操作系统、系统版本等。例如,AUFS 只能用于 Ubuntu 或 Debian 系统,Btrfs 只能用于 SLES (SUSE Linux Enterprise Server, 仅 Docker EE 支持)。
  • 有些存储驱动依赖于后端的文件系统。例如,Btrfs 只能运行于后端文件系统 Btrfs 上。
  • 不同的存储驱动在不同的应用场景下性能不同。例如,AUFS、Overlay、Overlay2 操作在文件级别,内存使用相对更高效,但大文件读写时,容器层会变得很大;DeviceMapper、Btrfs、ZFS 操作在块级别,适合工作在写负载高的场景;容器层数多,且写小文件频繁时,Overlay 效率比 Overlay2 更高;Btrfs、ZFS 更耗内存。

1.2Docker Volume 

Docker Copy on Write 

 

 

 

 

和刚刚说的一样, Docker 的写操作主要分为两种, 一个是 块级别的, 一个是文件级别的,  块级别的在修改文件的时候会把修改部分所在的块 copy 到 write层用于写, 文件级别则是直接复制真个文件到 write 层,   所以块级别能够节省空间, 但是块级别 copy的操作次数多, 文件级别直接copy 文件就会是的容器变大, 但是直接copy 文件就会大大减少copy操作的次数. 

以上操作对容器中中需要频繁读写的大文件就很不利,  块级别的 COW 操作太频繁,效率低, 文件级别的又会使得容器变得很大, 比如mysql数据库的数据库存储文件.

这个时候就引入了 Volume, Volme 可以将宿主机的文件映射到容器直接操作, 不必经过 COW, 常见的高频写文件有日志系统和数据存储文件.

Vloume使用是通过docker run  的 -v 参数来实现的

[docker@VM_121_116_centos ~]$ docker run -it  -p 6379:6379 -v ~/redis/date:/data  redis /bin/bash
root@b385ca73cad3:/data# ls
appendonly.aof    root  tomcat
root@b385ca73cad3:/data# mkdir testdir
root@b385ca73cad3:/data# exit
exit
[docker@VM_121_116_centos ~]$ ll
total 580364
drwxrwxr-x 2 docker docker      4096 Mar  6 22:00 dockerFile
-rw-rw-r-- 1 docker docker 594276824 Mar  6 17:31 ideaIU-191.6014.8.exe
drwxr-xr-x 3 root   root        4096 Mar 19 21:26 redis
[docker@VM_121_116_centos ~]$ cd redis/date/
[docker@VM_121_116_centos date]$ ll
total 16
-rw-r--r-- 1 polkitd ssh_keys  443 Mar 19 21:27 appendonly.aof
-rw-r--r-- 1 polkitd ssh_keys  249 Mar 19 21:27 root
drwxr-xr-x 2 root    root     4096 Mar 19 21:32 testdir
-rw-r--r-- 1 polkitd ssh_keys  259 Mar 19 21:27 tomcat
[docker@VM_121_116_centos date]$ 

如命令所示 使用 -v 把宿主机的  ~/redis/date 挂载到 容器的 /data , 之后在容器的 /data  建立一个  testdir 文件夹. 之后在宿主机的 ~/redis/data 里面看见了刚刚建的文件夹. 如不指定宿主机目录, 那么docker就会在docker得volume目录中创建一个目录挂载到容器内, 当容器删除的时候, 这个目录也就随之删除了. 

这样容器的 /data 目录就能避免大量的 COW 操作了, 直接进行读写.

 

 

 

在次看看容器信息 使用 docker inspect

[docker@VM_121_116_centos date]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
b385ca73cad3        redis               "docker-entrypoint..."   8 minutes ago       Exited (0) 7 minutes ago                       sad_murdock
e8abf8c09a26        mysql:5.6           "docker-entrypoint..."   3 weeks ago         Exited (0) 2 weeks ago                         mysql5.6
[docker@VM_121_116_centos date]$ docker inspect b385ca73cad3
[
    {
        "Id": "b385ca73cad3607f78fc87214dadf23435eebeaf5ee5551a17f160a432b08264",
        "Created": "2019-03-19T13:31:55.437267785Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "/bin/bash"
        ],
        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 0,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2019-03-19T13:31:55.783433554Z",
            "FinishedAt": "2019-03-19T13:32:42.591792526Z"
        },
====================省略==================================
        
        "GraphDriver": {
            "Name": "overlay2",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9-init/diff:/var/lib/docker/overlay2/61d911e09963bc0e77b7020b7bdbf798a5c35dbd90514c810f3aebb6875610f7/diff:/var/lib/docker/overlay2/fdddcb2b85492183f28660470d17c554e5bdb3a01cc8089e9c2112da7eefb4d5/diff:/var/lib/docker/overlay2/9476ee9fd3b0ccad81bdfa469c4188bda49230dff3598e9018cb763a0ba683c1/diff:/var/lib/docker/overlay2/65cfb70d00faeb7477439d635dc0a6f78f4f3d7bb6c5d28b29c6428744a58ee3/diff:/var/lib/docker/overlay2/55e18ec0a5caafed7907512ee5f2dd3e4db5cd701a1adfe5f4fe3bec2911e922/diff:/var/lib/docker/overlay2/ed7f62d6e611f876fb9eb55b06653b23198a915971fd1efdffbb61c33626f759/diff",
                "MergedDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/merged",
                "UpperDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/diff",
                "WorkDir": "/var/lib/docker/overlay2/f2806e52d83beca84bd0bb5a137a4a70974fcecdede03e5bc1b3f5c3711619c9/work"
            }
        },
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/home/docker/redis/date",
                "Destination": "/data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
=============================省略================================
       
            }
        }
    }
]
[docker@VM_121_116_centos date]$

可以看到 将  /home/docker/redis/date 挂载到 /data

讲了这么多怎么基于 Volume 互联呢?  我们刚刚把宿主机一个指定的目录挂载到了容器内部, 那么要是我们把这个目录挂载到多个容器有什么效果呢?

我们再次创建一个容器还是挂在这个目录

[docker@VM_121_116_centos date]$ docker run -it  -p 26379:6379 -v ~/redis/date:/data --name redistwo  redis /bin/bash 
root@cf0ca7e833bb:/data# ls
appendonly.aof    root  testdir  tomcat
root@cf0ca7e833bb:/data# mkdir testdirtwo
root@cf0ca7e833bb:/data# exit
exit

为了区别刚刚那个, 我们加了 --name 参数, 进入容器发现有刚刚的建的  testdir, 我们再次建一个 testdirtwo, 再次回到上个容器看看

[docker@VM_121_116_centos date]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
cf0ca7e833bb        redis               "docker-entrypoint..."   3 minutes ago       Exited (0) 2 minutes ago                        redistwo
b385ca73cad3        redis               "docker-entrypoint..."   26 minutes ago      Exited (0) 25 minutes ago                       sad_murdock
e8abf8c09a26        mysql:5.6           "docker-entrypoint..."   3 weeks ago         Exited (0) 2 weeks ago                          mysql5.6 
[docker@VM_121_116_centos date]$ docker start b385ca73cad3
b385ca73cad3
[docker@VM_121_116_centos date]$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
b385ca73cad3        redis               "docker-entrypoint..."   28 minutes ago      Up 7 seconds        0.0.0.0:6379->6379/tcp   sad_murdock
[docker@VM_121_116_centos date]$ docker exec -it b385ca73cad3 /bin/bash
root@b385ca73cad3:/data# ls
appendonly.aof    root  testdir  testdirtwo  tomcat
root@b385ca73cad3:/data# 

有第二个容器创建的文件夹, 这样就容器之间的互联

对于跨越宿主机的容器互联, 可是在linux采取共享目录等技术, 或者分布式文件系统

有 iscsi nfs ceph 等

1.3 数据容器共享解决方案(volumes-form)

将本地目录挂载到容器, 在 DockerFile 中是不推荐使用的, 因为这样的容器就不可移植了. 

就要不指定宿主机的目录, 使用容器存储位置的目录. 

如下:

[docker@VM_121_116_centos date]$ docker run -it  -p 6379:6379 -v /data --name oneredis  redis /bin/bash
root@6636fb7d293c:/data# mkdir redis
root@6636fb7d293c:/data# ls
redis
root@6636fb7d293c:/data# exit
exit
[docker@VM_121_116_centos date]$ docker inspect oneredis

查看挂载信息结果: 将 /var/lib/docker/volumes/b4fca8f9587e906919b5c2110b5e33643315dcc73d24ca177c8122072b44ef0a/_data 挂载到了 /data

 

 我们没有实现约定好共享目录,就不能体检知道挂载的目录,  其他容器怎么从这里读取呢?

这个时候要用 --volumes-from

示例:

[docker@VM_121_116_centos date]$ docker run -it  -p 26379:6379 --volumes-from=oneredis --name tworedis  redis /bin/bash
root@bb1d9cd3a282:/data# ls
redis
root@bb1d9cd3a282:/data# exit
exit

 

 能看到第一个容器创建的目录

再看看容器挂载

 

 和第一个一模一样

这样就解决的移植性的问题

 

 一般的解决方案就是 建议一个 数据共享的管理容器, 其他业务容器 volumes-from 数据管理容器, 这样实现业务容器互联

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

[docker@VM_121_116_centos date]$ docker run -it  -p 6379:6379 -v /data --name oneredis  redis /bin/bashroot@6636fb7d293c:/data# mkdir redisroot@6636fb7d293c:/data# lsredisroot@6636fb7d293c:/data# exitexit[docker@VM_121_116_centos date]$ docker inspect oneredis
————————————————版权声明:本文为CSDN博主「水淹萌龙」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_21047625/article/details/88321317

posted @ 2020-02-22 18:08  一笔凌空  阅读(553)  评论(0编辑  收藏  举报