当前位置: 首页 > news >正文

CentOS系统故障 | 一桩血案引发的容器存储驱动比较

为什么80%的码农都做不了架构师?>>>   hot3.png

写在前面:

由于红帽在Linux界的影响力,相信很多朋友在测试和生产系统用的是RedHat或者CentOS系统,这次我在CentOS系统上遇到了一个很有意思的故障,通过这次故障的原因分析及解决,特意写了这篇文章分享给大家。

 

我们在CentOS上部署了一套Docker系统,运行了一段时间后,突然发现所有容器运行异常,同时宿主机内核报磁盘I/O错误:


看到问题的第一反映是查看磁盘状态和空间使用情况,发现系统的根目录已经用完:


我们知道,Docker默认的存储目录是在/var/lib/docker/下,同时我们也知道,可以通过使用-g, --graph=”/var/lib/docker” 参数修改Docker 默认存放路径。知道了问题后,我们可以通过挂载一个大硬盘到系统,并将Docker的目录更改为新挂载到硬盘上:


我将Docker的存储目录设置到刚才新增加的/data目录下,但是原来的镜像和容器都找不到了,因为路径改了。原来的镜像是在/var/lib/docker/devicemapper/devicemapper/{data,metadata},转移文件后继续运行Docker服务,这样我们就有了一个300G的大房子给Docker们用了。

 

大家以为事情到了这里就完结了么?其实我也想,但是我顺便折腾了一下,于是又发生了接下来的事情。说我手贱也好,瞎折腾也罢,导入一堆容器镜像和运行一堆容器后,系统又光荣告诉我所有的容器根目录全部变成了只读,宿主机内核同样报磁盘I/O错误,一开始我以为data目录又被写满了,但是用df –Th命令查看后,发现目录还有很多空间:


但是残酷的现实是,只用了不到一半的空间后,所有的容器就全部出现异常了,这是我祭出了经典三板斧:重启容器,重启Docker服务,重启服务器。然并卵,容器还是运行异常。通过在网上爬了一堆资料,在http://jpetazzo.github.io/2014/01/29/docker-device-mapper-resize/上查到,CentOS默认用的是Device Mapper作为容器的存储驱动的,大家可以用dockers info命令查看,Docker服务启动时默认会在/var/lib/docker/devicemapper/devicemapper/目录创建一个100G(由于1000和1024换算的关系,系统实际显示的是107.4G,其他数字亦同)的data文件,然后启动的容器的所有变更的数据全部保存到这个data文件中;也就是说当容器内产生的相关data数据超过100G后容器就再也没有多余的空间可用,从而导致所有容器的根目录变为只读!同时它会限制每个容器最大为 10GB。太坑爹了有木有,给了大房子只能用100G!



为了找到根本原因,我们需要了解Device Mapper存储驱动的原理: Device Mapper存储驱动是以精简配置的方式运行的,它实际上是目标块设备的快照。

Docker启动时会设置一个100G的sparse文件( /var/lib/docker/devicemapper/devicemapper/data,元数据为/var/lib/docker/devicemapper/devicemapper/metadata ),并将其作为Device Mapper的存储池,而所有容器都从该存储池中分配默认10G的存储空间使用,如下图所示:



当有实际读写后,这些存储块将在存储池中被标记为已使用(或者从池中拿走)。当实际读写的块容量大于池的容量时,容器的运行空间不足,所以报I/O错误。

 

Device Mapper存储驱动非常方便,你不需要做任何安装部署便可以使用:如创建额外的分区来存储 Docker 容器,或者建立LVM。然而它也有两个缺点:

• 存储池会有一个默认 100GB 的容量,满足不了大存储的需求。

• 它将会被稀疏文件所支持(精简配置,一开始基本不占用空间,只有当实际需要写的时候才会使用磁盘的存储块)但性能较差。

 

针对这些问题,有两个解决方案:

1. 使用更大的文件/磁盘/逻辑卷创建data文件:


2. 通过Docker启动参数的--storage-opt选项来限制每个容器初始化的磁盘大小,如-storage-opt dm.basesize=80G 这样每个容器启动后,根目录的总空间就是80G。

 

但是我总觉得这样的解决方式不够优雅,需要多步操作才能满足需求,同时,容器的空间还是被限制的,只是限制的大小变化而已。那有没有更好的办法呢? 让我们继续来爬资料,在Docker的官方网站上:

(https://docs.docker.com/engine/reference/commandline/dockerd/)




Docker在存储驱动方面支持 AUFS、Device Mapper、Btrfs、ZFS、 Overlay 、Overlay2等多址方式,现由于AUFS并未并入内核,目前只有Ubuntu系统上能够使用aufs作为docker的存储引擎,而在CentOS系统上默认使用Device Mapper,但是幸运的是,在Linux内核3.18.0以上的版本,是可以原生支持Overlay驱动方式的,Overlayfs跟AUFS很像,但是性能比AUFS好,有更好的内存利用。

 

Docker通过-s参数选择存储驱动, 通过-s=overlay,我们将存储驱动器设置为Overlay方式,再重启Docker应用。




大家可以看到,现在Docker已经是使用了OverlayFS(这里大家要注意,如果系统有存储的镜像和运行的容器,更改存储驱动后将都不可用,请先行备份)。

 

通过修改为OverlayFS,Device Mapper的存储池容量限制及单个容器运行最大空间限制统统没有了,同时Overlay的读写性能也好于Device Mapper,只需通过-s=overlay一个参数即可优雅的使用更好的文件系统来运行容器。

 

至此,容器运行时I/O错误的原因已经完美解决,希望这篇文章能帮到在使用过程中遇到相同问题的朋友。


转载于:https://my.oschina.net/cloudsoar/blog/727186

相关文章:

  • 探针技术
  • DUBBO服务调用超时问题记录
  • html学习记录之表格、表单基础
  • JAVA API-----String类和StringBuffer类
  • redis 异常解决办法
  • 2016跨境电商五大物流模式盘点
  • .NET Framework 4.6.2改进了WPF和安全性
  • ubuntu 16.04 有道词典
  • AFNetworking 3.0 源码解读(四)之 AFURLResponseSerialization
  • 玩转Slot Machine
  • JavaScript之数组循环 forEach 循环输出数组元素
  • emacs初体验
  • RAW+ASM 的RAC 安装文档
  • 7 个 JavaScript “特性”
  • linux 下 ant 安装配置
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • CAP 一致性协议及应用解析
  • classpath对获取配置文件的影响
  • ES6简单总结(搭配简单的讲解和小案例)
  • es6要点
  • HTTP请求重发
  • node-glob通配符
  • Redis 懒删除(lazy free)简史
  • SpiderData 2019年2月23日 DApp数据排行榜
  • Terraform入门 - 3. 变更基础设施
  • vagrant 添加本地 box 安装 laravel homestead
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 笨办法学C 练习34:动态数组
  • 码农张的Bug人生 - 初来乍到
  • 前端_面试
  • 如何合理的规划jvm性能调优
  • 使用agvtool更改app version/build
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 因为阿里,他们成了“杭漂”
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 选择阿里云数据库HBase版十大理由
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​Linux·i2c驱动架构​
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (Oracle)SQL优化技巧(一):分页查询
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (论文阅读40-45)图像描述1
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (算法)Travel Information Center
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .NET Reactor简单使用教程
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • .NET中winform传递参数至Url并获得返回值或文件
  • .net专家(张羿专栏)
  • @AliasFor注解
  • @JsonSerialize注解的使用
  • @SpringBootApplication 包含的三个注解及其含义