阿里云服务器ECS    
弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新 [咨询更多]
阿里云存储OSS
简单易用、多重冗余、数据备份高可靠、多层次安全防护安全性更强、低成本 [咨询更多]
阿里云数据库RDS
稳定可靠、可弹性伸缩、更拥有容灾、备份、恢复、监控、迁移等方面的全套解决方案 [咨询更多]
阿里云安全产品
DDoS高防IP、web应用防火墙、安骑士、sll证书、态势感知众多阿里云安全产品热销中 [咨询更多]
阿里云折扣优惠    
云服务器ECS、数据库、负载均衡等产品新购、续费、升级联系客服获取更多专属折扣 [咨询更多]
Docker 存储
2020-7-1    点击量:
  容器服务之所以如此流行,一大优势即来自于运行容器时容器镜像的组织形式。容器通过复用容器镜像的技术,实现在相同节点上多个容器共享一个镜像资源(更细一点说是共享某一个镜像层),避免了每次启动容器时都拷贝、加载镜像文件,这种方式既节省了主机的存储空间,又提高了容器启动效率。
  
  1. 容器读写层
  
  为了提高节点存储的使用效率,容器不光在不同运行的容器之间共享镜像资源,而且还实现了在不同镜像之间共享数据。共享镜像数据的实现原理:镜像是分层组合而成的,即一个完整的镜像会包含多个数据层,每层数据相互叠加、覆盖组成了最终的完整镜像。
  
  为了实现多个容器间共享镜像数据,容器镜像每一层都是只读的。而通过实践我们得知,使用镜像启动一个容器的时候,其实是可以在容器里随意读写的,这是如何实现的呢?
  

  容器使用镜像时,在多个镜像分层的最上面还添加了一个读写层。每一个容器在运行时,都会基于当前镜像在其最上层挂载一个读写层,用户针对容器的所有操作都在读写层中完成。一旦容器销毁,这个读写层也随之销毁。

Docker 存储卷

  如上图所示例子,一个节点上共有 3 个容器,分别基于 2 个镜像运行。
  
  镜像存储层说明如下
  

该节点上共包含 6 个镜像层:Layer 1~6。
  
  镜像 1 由:Layer 1、3、4、5 组成;
  
  镜像 2 由:Layer 2、3、5、6 组成。
  
  所以两个镜像共享了 Layer 3、5 两个镜像层;

  容器存储说明:
  
容器 1:使用镜像 1 启动
  
  容器 2:使用镜像 1 启动
  
  容器 3:使用镜像 2 启动
  
  容器 1 和容器 2 共享镜像 1,且每个容器有自己的可写层;
  
  容器 1(2)和容器 3 共享镜像 2 个层(Layer3、5);

  通过上述例子可以看到,通过容器镜像分层实现数据共享可以大幅减少容器服务对主机存储的资源需求。
  
  上面给出了容器读写层结构,而读写的原则:
对于读:容器由这么多层的数据组合而成,当不同层次的数据重复时,读取的原则是上层数据覆盖下层数据;
  
  对于写:容器修改某个文件时,都是在最上层的读写层进行。主要实现技术有:写时复制、用时配置。
  1)写时复制
  
  写时复制(CoW:copy-on-write),表示只在需要写时才去复制,是针对已有文件的修改场景。CoW 技术可以让所有的容器共享 image 的文件系统,所有数据都从 image 中读取,只有当要对文件进行写操作时,才从 image 里把要写的文件复制到最上面的读写层进行修改。所以无论有多少个容器共享同一个 image,所做的写操作都是对从 image 中复制后在复本上进行,并不会修改 image 的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。
  
  2)用时配置
  
  用时分配:在镜像中原本没有某个文件的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会为这个容器预分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。
  
  2. 存储驱动
  
  存储驱动是指如何对容器的各层数据进行管理,已达到上述需要实现共享、可读写的效果。即:容器存储驱动实现了容器读写层数据的存储和管理。常见的存储驱动:
  
  AUFS
  
  OverlayFS
  
  Devicemapper
  
  Btrfs
  
  ZFS
  
  以 AUFS 为例,我们来讲述一下存储驱动的工作原理:

Docker 存储卷:容器服务在单节点的存储组织形式

  AUFS 是一种联合文件系统(UFS),是文件级的存储驱动。
  
 

AUFS 是一个能透明叠加一个或多个现有文件系统的层状文件系统,把多层文件系统合并成单层表示。即:支持将不同目录挂载到同一个虚拟文件系统下的文件系统。
  
  可以一层一层地叠加修改文件,其底层都是只读的,只有最上层的文件系统是可写的。
  
  当需要修改一个文件时,AUFS 创建该文件的一个副本,使用 CoW 将文件从只读层复制到可写层进行修改,结果也保存在可写层。
  
  在 Docker 中,底下的只读层就是 image,可写层就是 Container 运行时。

  其他各种存储驱动这里不再细讲,有兴趣的同学可以到网上查询资料。

  3. Docker 数据卷介绍
  
  容器中的应用读写数据都是发生在容器的读写层,镜像层+读写层映射为容器内部文件系统、负责容器内部存储的底层架构。当我们需要容器内部应用和外部存储进行交互时,需要一个类似于计算机 U 盘一样的外置存储,容器数据卷即提供了这样的功能。
  
  另一方面:容器本身的存储数据都是临时存储,在容器销毁的时候数据会一起删除。而通过数据卷将外部存储挂载到容器文件系统,应用可以引用外部数据,也可以将自己产出的数据持久化到数据卷中,所以容器数据卷是容器进行数据持久化的实现方式。

容器存储组成:只读层(容器镜像) + 读写层 + 外置存储(数据卷)

    容器数据卷从作用范围可以分为:单机数据卷 和 集群数据卷。单机数据卷即为容器服务在一个节点上的数据卷挂载能力,docker volume 是单机数据卷的代表实现;集群数据卷则关注的是集群级别的数据卷编排能力,K8s 数据卷则是集群数据卷的主要应用方式。
  
  Docker Volume 是一个可供多个容器使用的目录,它绕过 UFS,包含以下特性:
  
  数据卷可以在容器之间共享和重用;
  
  相比通过存储驱动实现的可写层,数据卷读写是直接对外置存储进行读写,效率更高;
  
  对数据卷的更新是对外置存储读写,不会影响镜像和容器读写层;

  数据卷可以一直存在,直到没有容器使用。

  1)Docker 数据卷类型
  
  Bind:将主机目录/文件直接挂载到容器内部。
  

需要使用主机的上的绝对路径,且可以自动创建主机目录;
  
  容器可以修改挂载目录下的任何文件,是应用更具有便捷性,但也带来了安全隐患。

  Volume:使用第三方数据卷的时候使用这种方式。
 
Volume命令行指令:docker volume (create/rm);
  
  是Docker提供的功能,所以在非 docker 环境下无法使用;
  
  分为命名数据卷和匿名数据卷,其实现是一致的,区别是匿名数据卷的名字为随机码;
  
  支持数据卷驱动扩展,实现更多外部存储类型的接入。

  Tmpfs:非持久化的卷类型,存储在内存中。
  
数据易丢失。
 
  2)Bind 挂载方式语法
  
  -v: src:dst:opts 只支持单机版。
  
Src:表示卷映射源,主机目录或文件,需要是绝对地址;
  
  Dst:容器内目标挂载地址;
  
  Opts:可选,挂载属性:ro, consistent, delegated, cached, z, Z;
  
  Consistent, delegated, cached:为mac系统配置共享传播属性;
  
  Z、z:配置主机目录的selinux label。

  示例:

$ docker run -d --name devtest -v /home:/data:ro,rslave nginx
$ docker run -d --name devtest --mount type=bind,source=/home,target=/data,readonly,bind-propagation=rslave nginx
$ docker run -d --name devtest -v /home:/data:z nginx





  3)Volume 挂载方式语法
  
  -v: src:dst:opts 只支持单机版。
  

Src:表示卷映射源,数据卷名、空;
  
  Dst:容器内目标目录;
  
  Opts:可选,挂载属性:ro(只读)。

  示例:

$ docker run -d --name devtest -v myvol:/app:ro nginx
$ docker run -d --name devtest --mount source=myvol2,target=/app,readonly nginx

  4. Docker 数据卷使用
  
  Docker 数据卷使用方式:
  
  1)Volume 类型
  
  匿名数据卷:docker run –d -v /data3 nginx;
  
  会主机上默认创建目录:/var/lib/docker/volumes/{volume-id}/_data进行映射;
  
  命名数据卷:docker run –d -v nas1:/data3 nginx;
  
  如果当前找不到nas1卷,会创建一个默认类型(local)的卷。
 
  2)Bind 方式
  
  docker run -d -v /test:/data nginx
  
  如果主机上没有/test目录,则默认创建此目录。
 
  3)数据卷容器
  
  数据卷容器是一个运行中的容器,其他容器可以继承此容器中的挂载数据卷,则此容器的所有挂载都会在引用容器中体现。
  
  docker run -d --volumes-from nginx1 -v /test1:/data1 nginx
  
  继承所有来自配置容器的数据卷,并包含自己定义的卷。

  4)数据卷的挂载传播
  
  Docker volume 支持挂载传播的配置:Propagation。
  
Private:挂载不传播,源目录和目标目录中的挂载都不会在另一方体现;
  
  Shared:挂载会在源和目的之间传播;
  
  Slave:源对象的挂载可以传播到目的对象,反之不行;
  
  Rprivate:递归 Private,默认方式;
  
  Rshared:递归 Shared;
  
  Rslave:递归 Slave。

  示例:

$ docker run –d -v /home:/data:shared nginx
表示:主机/home下面挂载的目录,在容器/data下面可用,反之可行;
$ docker run –d -v /home:/data:slave nginx
表示:主机/home下面挂载的目录,在容器/data下面可用,反之不行;

  5)数据卷挂载的可见性
  
  Volume 挂载可见性:
  
  本地空目录、镜像空目录:无特殊处理;
  
  本地空目录、镜像非空目录:镜像目录的内容拷贝到主机;(是拷贝,不是映射;即使容器删除内容也会保存);
  
  本地非空目录、镜像空目录:本地目录内容映射到容器;
  
  本地非空目录、镜像非空目录:本地目录内容映射到容器,容器目录的内容被隐藏。
 
  Bind 挂载可见性:以主机目录为准。
  
本地空目录、镜像空目录:无特殊处理;
  
  本地空目录、镜像非空目录:容器目录变成空;
  
  本地非空目录、镜像空目录:本地目录内容映射到容器;
  
  本地非空目录、镜像非空目录:本地目录内容映射到容器,容器目录的内容被隐藏。

  5. Docker数据卷插件
  
  Docker 数据卷实现了将容器外部存储挂载到容器文件系统的方式。为了扩展容器对外部存储类型的需求,docker 提出了通过存储插件的方式挂载不同类型的存储服务。扩展插件统称为 Volume Driver,可以为每种存储类型开发一种存储插件。
  
  单个节点上可以部署多个存储插件;
  
  一个存储插件负责一种存储类型的挂载服务。

Docker 存储卷:容器服务在单节点的存储组织形式,关注数据存储、容器运行时的相关技术

  Docker Daemon 与 Volume driver 通信方式有:
  

  Sock文件:linux 下放在/run/docker/plugins 目录下
  
  Spec文件:/etc/docker/plugins/convoy.spec 定义
  
  Json文件:/usr/lib/docker/plugins/infinit.json 定义

  实现接口:
  
Create, Remove, Mount, Path, Umount, Get, List, Capabilities; 

  使用示例:

$ docker volume create --driver nas -o diskid="" -o host="10.46.225.247" -o path=”/nas1" -o mode="" --name nas1

  Docker Volume Driver 适用在单机容器环境或者 swarm 平台进行数据卷管理,随着 K8s 的流行其使用场景已经越来越少,关于 VolumeDriver 的详细介绍这里不在细讲。

联系客服免费领取更多阿里云产品新购、续费升级折扣,叠加官网活动折上折更优惠