5. Docker存储卷

Docker文件系统

Why Data Volumes?

Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层

如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,次即“写时复制(COW)” 机制。

写时复制这种方式对IO是有影响的,对那些IO要求较高的应用,比如:redis、mysql ,如果mysql运行在这样的文件系统上,容器停止时数据会被删除,在数据存取时,效率也较低,这是必然的情形。要想绕过这样的使用场景,需要借助存储卷的机制l来实现。在特权级的名称空间中,在宿主机的k空间中,找一个本地文件系统,常见是一个目录,把这个目录与容器内部的文件系统一个目录建立绑定关系。

/data/web -> /containers/data/web 建立这样的绑定关系后,宿主机和容器可以共享数据文件, 容器可直接访问宿主机的内容。如果容器内所有有效数据都是保存在存储卷从而脱离了容器自身文件系统以后,带来的好处就是,当容器关闭甚至删除时,都不用担心数据丢失,数据脱离容器生命周期的持久存储。

有状态、无状态说明

对服务器程序来说,究竟是有状态服务,还是无状态服务,其判断依旧——两个来自相同发起者的请求在服务器端是否具备上下文关系。

状态化请求,服务器端一般都要保存请求的相关信息,每个请求可以默认地使用以前的请求信息。

无状态请求,服务器端所能够处理的过程必须全部来自于请求所携带的信息,以及其他服务器端自身所保存的、并且可以被所有请求所使用的公共信息。

一、比较

有状态服务常常用于实现事务(并不是唯一办法,下文有另外的方案)。举一个常见的例子,在商城里购买一件商品。需要经过放入购物车、确认订单、付款等多个步骤。

由于HTTP协议本身是无状态的,所以为了实现有状态服务,就需要通过一些额外的方案。比如最常见的session,将用户挑选的商品(购物车),保存到session中,当付款的时候,再从购物车里取出商品信息

服务要设计为无状态的,这主要是从可伸缩性来考虑的。

如果server是无状态的,那么对于客户端来说,就可以将请求发送到任意一台server上,然后就可以通过负载均衡等手段,实现水平扩展

如果server是有状态的,那么就无法很容易地实现了,因为客户端需要始终把请求发到同一台server才行,所谓session迁移”等方案,也就是为了解决这个问题。

二、session和cookie

基于session和cookie都可以实现事务,可以认为,session是有状态的,而cookie是无状态的

三、无状态实现事务的方法

并不是一定要用有状态服务才能实现事务,本文提供另外的几种方案作为参考 ,举一个多次提交的场景作为例子:用户需要提交很多数据,分为2个页面提交 。

这里就涉及到2次http请求,第一次提交字段1、2、3,第二次提交字段4、5、6

用session很容易实现这个需求,server只需要将第一次提交的数据,保存在session里,然后返回第2个表单作为相应;然后取出第一次提交的数据,和第二次提交的数据汇聚以后,一起存入数据库即可。

不用session同样也可以实现,server接收到第一次请求以后,将数据作为隐藏元素,放在第2个表单里返回;这样用户第2次提交的时候,就隐含地再次提交了第一次的数据;server将所有数据存入数据库

四、将有状态服务转换成无状态服务

根据本文一开始的定义,除了将所有信息都放在请求里之外,还有另外一种方法可以实现无状态服务,即将信息放在一个单独可共享的地方,独立于server存在 。比如,同样还是采取session的方式,在服务端保存数据,减少每次client请求传输的数据量(节省流量),但是将session集中存放,比如放在单独的session层里。这种情况下,server同样是无状态的,可以做水平扩展

五、总结

有状态服务可以比较容易地实现事务,在不需要考虑水平扩展时,是比较好的选择。
无状态服务的优势在于可以很方便地水平伸缩,但是在实现事务时,需要做一些额外的动作
可以通过剥离session等方法,将一个有状态服务,转换成无状态服务

注:什么是事务?

事务,就是把一堆事情绑在一起做,都成功了才算完成,否则就恢复之前的样子。
举例:银行ATM取钱,扣款成功后突然大停电,吐钱的操作还没做,这时候就要恢复没取钱时候的状态,否则钱扣了还没拿到手,多冤枉

Why Data Volume?

关闭并重启容器,其数据不受影响;但删除Docker容器,则其更改将会全部丢失。

存在的问题:

  • 存储于联合文件系统中,不宜与宿主机访问;
  • 荣期间数据共享不便
  • 删除容器其数据会丢失

解决方案:“卷(volume)”

  • “卷” 是容器上的一个或多个目录,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定(关联)”

Data volumes

Volume 于容器初始化之时即会创建,有 Base image提供的卷中的数据会于此期间完成复制

Volume 的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时即不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作;

卷为docker提供了独立于容器的数据管理机制:

  • 可以把“镜像”想象成静态文件,例如:“程序”,把卷类比为动态内容,例如:“数据”;于是,镜像可以重用,而卷可以共享。
  • 卷实现了“程序(镜像)”和“数据(卷)”分离,以及“程序(镜像)”和“制作镜像的主机”分离,用户制作镜像时无需再考虑镜像运行的容器所在的主机的环境;

Volume types

Docker 有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同;

在容器中使用Volumes

为docker run 命令使用 -v 选项即可使用 Volume

Docker-managed volume

docker run -it --name bbox1 -v /data busybox
docker inspect -f {{.Mounts}} bbox1

Bind-mount Volume

docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox
docker inspect -f {{.Mounts}} bbox2

注意:多个容器可以共享1个存储卷。

共享 volumes

多个容器的卷使用同一个主机目录,例如:

docker run -it --name c1 -v /docker/volumes/v1:/data busybox
docker run -it --name c2 -v /docker/volumes/v1:/data busybox

复制使用其他容器的卷,为docker run 命令使用 --volumes-from 选项

docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox
docker run -it --name bbox2 --volumes-from bbox1 busybox

参考链接:

https://www.iteye.com/blog/kyfxbl-1831869

posted @ 2020-12-01 16:12  hukey  阅读(192)  评论(0编辑  收藏  举报