吐槽:Docker真的好吗?

简介: 本文讲的是吐槽:Docker真的好吗?,【编者的话】本文是一篇对Docker“吐槽”的文章,作者从Dockerfile、缓存、分层文件系统、Docker Hub、安全、容器和虚拟机几个方面入手,阐述了Docker和容器技术目前存在的一些问题,以至于说Docker的存在并没有必要。
本文讲的是吐槽:Docker真的好吗? 【编者的话】本文是一篇对Docker“吐槽”的文章,作者从Dockerfile、缓存、分层文件系统、Docker Hub、安全、容器和虚拟机几个方面入手,阐述了Docker和容器技术目前存在的一些问题,以至于说Docker的存在并没有必要。大家可以把这篇文章的观点作为对Docker认识的一个补充,对Docker有一个更加客观的认识,另外本文中包括作者在论证自己观点时引用了很多链接,建议大家都看一下,挺不错的。

概述

距离我上次发表对Docker的 看法 已经一年了,那个时候我狠狠的批评了Docker在架构上的缺陷以及其糟糕的用户体验。虽然现在项目已经发展到1.0,但是还是得到了一些来自亚马逊的 不满 ,用户失望程度也在不断增加,面临大量的 指责 ,甚至还存在一些可能会导致主机污染的 漏洞 。然而 Docker Hub 上个人私有仓库的引入,使得用户自己不需要再运行个人的Registry,再加上webhook与GitHub整合,所有这些看起来是一个良好的开始。

于是我决定再给Docker一个“机会”,并且把其投入到生产中运行六个月,看看效果怎样。结果真的令我很失望,在使用过程中,Docker表现很令人失望,不但性能糟糕,而且由于其本身功能的不足,我们还需要在解决方案上不断地进行变通,整个过程的用户体验也不尽如人意,这使得我几乎想要把自己的脸撞碎在桌子上!事实上,在我看来Docker的性能的确很糟糕,以至于缓存被禁用之后编译过程变得更快。(看看 reddit hackernews 上面讨论)

Dockerfile

Dockerfile有很多问题,在我看来,他很丑陋,有很多局限性,有的地方甚至相互矛盾,并且有很多根本性的缺陷。让我们来说说,假如你想创建单个仓库的多个镜像,例如第二个镜像包含了调试工具, 但是对两个镜像的基本要是是一样的。Docker不支持这样操作(per  #9198 ), 当前并没有能力去对Dockerfile进行扩展(per #735 ),使用子目录的话会破坏创建的上下文以及阻止你使用ADD/COPY(per  #2224 ), 就像管道一样(per #2112 ),在容器构建的时候(build time)你也不能够使用环境变量根据不同的运行条件来改变指令(per #2637 )。

我们的 变通方案 是创建一个基础的镜像,两个指定环境的镜像,以及一些包含重命名和sed替换的Makefile自动化脚本。还有一些意想不到不到的“ 特性 ”导致$HOME环境变量消失了,还会产生一些没用的错误信息,使用起来的确很不方便。

Docker 缓存/分层

Docker可以使用COW(copy-on-write)文件系统来 缓存 Dockerfile指令, 类似于LVM的 快照 ,到现在仍然仅仅支持满是问题的AuFS(AnotherUnionFS)。为了提高稳定性以及性能,之后在0.7版本中对COW做了不同的实现, 你可以在 这里 了解到详细的情况。但是这个缓存系统并不智能,导致了一些令人惊讶的 情况 ,比如不能阻止某一个指令被缓存(per  #1996 )。并且很慢, 鉴于这一点,如果你禁用缓存或者是避免使用分层,创建的速度反而快一点, 在Docker Hub上传和下载的时候这个表现的更严重,详情会在下面部分进行描述:

这些问题都是由Docker的架构设计导致的,Docker作为一个整体,总是线性的执行指令,即便是在很不合适的情况下也这样 (per  #2439 )。作为一个改变慢速创建的变通方法,你可以使用一个第三方支持异步执行的工具,例如 Salt Slack ,  Puppet ,甚至 Bash ,这样的话就完全放弃分层的思想使其毫无用武之地。

Docker Hub

Docker鼓励通过Docker Hub来进行社交合作, 允许你发布自己的Dokerfiles,不管是公有的还是私有的,这样其他人可以基于此来通过FROM来进行扩展,而不是拷贝,粘贴。这个生态系统类似于AWS  marketplace 的AMIs,以及Vagrant的 boxes ,原则上说是非常有用的。

然而由于一些原因,Docker Hub在实现上是有缺陷的。Dockerfile不支持多FROM指令(per  #3378 #5714  and #5726 ),这就意味着你只能继承自单个的镜像。并且他也没有强制版本化, 例如dockerfile/ubuntu:14.04的作者可以替换掉这个标签的内容,这就相当于在使用了没有强制版本的包管理工具。另外在后面也会提到,Docker Hub在速度上的缺陷也很令人失望。

Docker Hub也有一个自动构建的系统,它可以监测仓库中新的提交,并且触发一个容器的创建。因为很多原因,这个功能基本上是没用处的。创建服务没有可定制化的功能,甚至连最基本的前/后脚本钩子也没有。它还强制使用一个指定的项目结构,希望在根目录中只有单一的Dockerfile,导致创建过程变得相当的慢,也破坏了我们之前提到的创建的变通方法。

我们采用的变通方法是使用 CircleCI , 一个持续集成(CI)平台,可以触发基于Makefile的Docker创建, 并推送到Docker Hub。这个并不能解决速度慢的问题, 唯一的解法就是使用我们自己的Docker Registry,这样做确实有点复杂甚至可笑。

安全

Docker原来使用LXC作为默认的执行环境,从0.9之后采用libcontainer作为默认的执行环境。当使用合适的执行驱动(exec-driver)时,引入它来 调整 命名空间的能力,权限以及使用定制的LXC 配置

Docker需要一个根守护进程一直在主机上运行,并且有 很多 安全漏洞,比如 CVE-2014-6407 CVE-2014-6408 ,非常坦率的说,这还不应该排在第一位。即便是Gartner, 根据他们可怜的评估记录,也表达了对Docker不成熟,以及安全问题的担忧。

Docker,从设计上来说,对namespace 能力 过分的信任,但实际上namespace比一般的hypervisor暴露的攻击面要大很多,Xen在Linux里面有129个CVEs(Common Vulnerabilities and Exposures),与之相比它却有1279个。当然,这在某些情况下也是可以接受的,比如在Travis CI里面以公有的方式来构建, 但是在私有情况下和多用户的环境下,就显得比较危险了。

容器不是虚拟机

namespaces和cgroups是非常 强大 的,允许一个进程及其子进程有一个共享内核资源的私有视图, 例如网络栈和进程表。这种粒度的控制和隔离,加上chroot jailing和 grsec , 可以提供一个很优秀的保护层。 有些应用, 例如 uWSGI , 直接对这些优点加以利用,而不是通过Docker。 还有些应用不直接支持namespaces的可以用 firejail 封装成沙箱。如果你觉得很冒险的话, 你也可以直接在你的 代码 里面支持namespace。

容器化项目,诸如LXC和Docker, 利用这些特性,可以高效的在一个相同的内核空间中运行多个linux的发行版。与hypervisor 相比 ,它们有时候会有一些 优点 ,比如占用更少的内存并且启动速度更快。 但是这是以损失完全性,稳定性和兼容性为代价的。这里有一个跟 Linux内核接口 有关的 边缘情况 , 在内核和用户空间运行非兼容的和没有经过测试的glibc版本组合会导致一些不可预料的行为。

回到2008年, 当LXC被设想出来的时候,硬件辅助的虚拟化才有几年的时间, 很多hypervisor有性能和稳定性的问题,这样的虚拟化并没有被广泛的使用,也只是为了降低花费和减少物理机而做了折衷。但是现在hypervisor的性能已经可以和物理机器一样快了,有趣的是,在一些 情况 下可能更快。运行自定义的虚拟机也变的更快更便宜,随着 DigitalOcean 在性能和花费方面不断的 超越 EC2, 使得以一对一的方式运行应用和虚拟机,在财政上变的成为可能。

Bryan Cantrill 在这里 指出 , 虚拟化的性能主要取决于工作负载的类型,比如IO很重的应用会导致 更低 的性能。

对于有些特定的情况,使用容器化是正确的选择, 但是除非你能很明确的解释为什么你要使用容器,否则你便可以使用hypervisor来代替。即便是你使用了传统的虚拟化,你也可以直接应用namespaces的优势,诸如 firejail 就可以帮助你的应该在缺少本地支持的情况下来实现这样的特性。

Docker是没有必要的

Docker增加了一个复杂的入侵层,这使得开发,故障排查以及调试变得非常困难, 常常制造的问题比解决的问题还多。这对部署没有一点好处,因为你仍然需要使用的快照来达到自动扩展的目的。更糟糕的是,如果你不使用快照的话,你的生产环境的扩展需要取决于Docker Hub的稳定性。

这个已经被 baseimage-docker 这个项目滥用了,这个镜像试图通过运行init.d作为入口使得检查、调试,以及兼容变得更容易,它还尝试提供给你一个可以用ssh登录的服务器,从而把一个容器看成是一个虚拟机,尽管作者使用了很无力的 论据 去反驳这一点。

结论

如果你的开发工作流非常的健全,那么就应该已经明白Docker是没有必要的。所有它宣传的特性要么是没用的要么就是实现的非常差,并且它主要的特性直接可以使用namespaces来完成。Dokcer本来应该是8年前的一个很可爱的想法,但是今天已经没什么用了。

更正/修订

表面上看,Docker有很多值得关注的地方。它鼓励开发人员围绕一个 一成不变的部署流程 , 可以快速的, 简单 的开始一个新的项目,还有些其他的人认为有用的东西。但是需要提醒大家的是,本文是聚焦在一个每日的,长期使用的Docker上面,包括本地和生产环境。

尽管大多数提到的问题都是显而易见的,本文并没有为Docker如何变得更好提出什么建议。对Docker来说有很多解决方法,毕竟不管什么项目都是有优缺点的,我会在接下来的文章中作详细的解释。

a-ko 对使用容器化有个长期的讨论, markbnj 也有一个详细的技术反驳,这两个都是很有用的。

我想对所有给他们反馈的人说声谢谢,看到大家很喜欢我的写作风格感觉非常的高兴,我也读了几个高级工程师的回应, 包括那些欣赏我的人,这非常震撼人心。

原文链接:Lets review.. Docker (again)(翻译:左伟 校对:王哲)

原文发布时间为:2015-02-10 
本文作者:左伟
本文来自云栖社区合作伙伴DockerOne,了解相关信息可以关注DockerOne。
原文标题:吐槽:Docker真的好吗?
目录
相关文章
|
搜索推荐 大数据 数据处理
如何甄选出一个优秀的软件供应商?by彭文华
如何甄选出一个优秀的软件供应商?by彭文华
|
存储 传感器 数据采集
大数据
大数据是指数据量庞大(Volume)、增长迅速(Velocity)、类型多样(Variety)、价值密度低(Value)但潜力巨大的数据集。其来源包括互联网、物联网及企业内部数据。处理技术涵盖采集、预处理、存储、分析与可视化。应用领域涉及商业智能、金融、医疗、交通及公共服务等,助力决策优化与创新。
954 8
ly~
|
存储 SQL NoSQL
数据库介绍
数据库是组织、存储和管理数据的仓库,分为关系型(RDBMS)和非关系型(NoSQL)。RDBMS 如 MySQL、Oracle 和 SQL Server 通过表间关系存储结构化数据;NoSQL 包括 MongoDB、Redis 和 Neo4j,处理非结构化数据。数据库功能组件有数据定义语言(DDL)、数据操作语言(DML)和数据库管理系统(DBMS)。应用场景涵盖企业资源规划(ERP)、电子商务和大数据分析,支持自动化管理、数据分析及决策支持。
ly~
325 3
|
存储
sign与unsigned的原理、数据存储与硬件的关系
【9月更文挑战第15天】在编程语言中,`signed`(有符号)和`unsigned`(无符号)类型具有不同的原理和数据存储方式。有符号类型使用补码表示法,包含符号位,能表示正数、负数和零;无符号类型仅表示非负整数,没有符号位。两者在内存占用上相同,但在存储方式、处理器指令集支持、寄存器处理及溢出处理等方面存在差异。选择合适类型并处理溢出等问题至关重要。
521 11
|
运维 容灾 关系型数据库
阿里云关系型数据库RDS
阿里云关系型数据库RDS概述
530 2
|
XML 存储 编译器
Protobuf 详解
Protobuf 详解
|
监控 关系型数据库 Linux
systemctl管理系统服务的详细用法
systemctl管理系统服务的详细用法
734 0
|
芯片
CMOS与TTL
CMOS与TTL
497 0
CMOS与TTL
【python】使用openpyxl库的Alignment模块设置单元格的对齐方式
【python】使用openpyxl库的Alignment模块设置单元格的对齐方式
|
测试技术
03-测试用例设计方法-边界值
03-测试用例设计方法-边界值