为什么要使用Docker?
作为一种新兴的虚拟化方式,Docker跟传统的虚拟化方式相比具有众多的优势。
更高效的利用系统资源
由于容器不需要进行硬件虚拟及运行完整操作系统等额外开销,Docker对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统的虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而Docker容器应用,由于直接运行与宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级别的启动时间。大大的节约了开发、测试、部署的时间。
一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些BUG并未在开发过程中被发现。而Docker的镜像提供了除了内核外完整的运行时环境,确保了应用运行环境得一致性,从而不会再出现“这段代码在我机器上没问题”这类问题。
持续交付和部署
对开发和运维人员来说,最希望的就是一次性创建或配置,可以在任意地方正常运行。
使用Docker可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过DockerFile来进行镜像构建,并结合 持续集成系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合持续部署系统进行自动部署。
而使用DockerFile使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
更轻松的迁移
由于Docker确保了执行环境得一致性,使得应用的迁移更加容易。Docker可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用迁移到另一个平台,而不用担心运行环境得变化导致应用无法正常运行的情况。
更轻松的维护和扩展
Docker使应用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变的非常简单。此外,Docker团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。
持续集成原则
1. 所有的开发人员需要在本地机器上做本地构建,然后再提交的版本控制库中,从而确保他们的变更不会导致持续集成失败。
2. 开发人员每天至少向版本控制库中提交一次代码。
3. 开发人员每天至少需要从版本控制库中更新一次代码到本地机器。
4. 需要有专门的集成服务器来执行集成构建,每天要执行多次构建。
5. 每次构建都要100%通过。
6. 每次构建都可以生成可发布的产品。
7. 修复失败的构建是优先级最高的事情。
8. 测试是未来,未来是测试
Docker技术这些应用场景,你知道吗?
场景一:节省项目环境部署时间
1.单项目打包
每次部署项目到测试、生产等环境,都要部署一大堆依赖的软件、工具,而且部署期间出现问题几率很大,不经意就花费了很长时间。
Docker主要理念就是环境打包部署,可在任意Docker Engine运行。前期我们只需要将每个项目环境打包到镜像,push到镜像仓库,当有需要部署这个项目时,直接pull镜像启动容器,这个项目就可以访问了!一次构建多次部署,一劳永逸。
2.整套项目打包
公司有一项这样的业务:有一个产品可以整套部署到客户那里,以往都是派一名实施工程师到客户那部署。如果用了Docker,我们可以前期将这套项目封装打包起来,实现一键部署,分分钟钟搞定,就不需要再派人过去了。比如官方的Docker Compose编排工具。
3.新开源技术试用
有时,我们想调研一些开源项目,我们可以直接从公共镜像仓库pull项目官方做好镜像启动容器即可。
场景二:环境一致性
开发工程师在Windows系统上开发项目,测试、生产环境操作系统都是Linux系统,这就产生了环境不一致的情况:项目在开发电脑本地运行没问题,到了测试或生产环境就运行不起来,解决这问题最好方式就是这三处环境保持一致。软件版本、操作系统、物理机、云主机......试想下,能做到吗?
Docker将项目环境打包成镜像,可以在任何Docker Engine上浪。此时Docker就是我们这些项目的基石,Docker可移植性,保持运行状态一致性,可想而知,是否更容易解决问题呢?
场景三:持续集成
一个项目版本快速迭代的测试场景,需要一个合理的CI(持续集成)/CD(持续部署)环境支撑。CI/CD是一个周期性自动化项目测试流程,包括构建、部署、测试、发布等工作,很少需要人工干预。
项目测试流程大致如下图:
Docker结合Jenkins构建持续集成环境大致如下图:
Docker在上面这个图的作用是项目镜像构建和快速部署,打通测试环境与生产环境,高度保持多个环境之间一致性。
场景四:微服务
微服务是近几年来IT圈内谈论比较多的一个名词,意义也很简单:尽可能细粒度拆分业务程序架构,由多个独立服务组成业务系统。
Docker的容器设计原则:一个容器一个服务,容器之间相互隔离,不妨试想一下,如果容器作为这些独立服务的部署单元,是不是有点恰到好处呢?
场景五:弹性伸缩
说到弹性伸缩,通常是集群模式下存在。像AWS AutoScaling,可以自定义资源阈值,SLB自动添加EC2云主机,应对业务访问量突发情况。
当适用Docker技术以后,这种弹性伸缩的单元就是云主机之上的容器了。
容器集群化管理已经有成熟的解决方案,比如:官方的Swarm,谷歌的K8S
由于Docker容器快速启动特性,可以很快速的启动几十个、上百个容器来提供更多并发和资源利用率(如果宿主机资源不够,还需要加主机到集群中)。
小结:
根据上述应用场景总结下Docker特点:开箱即用,快速部署,可移植性强,环境隔离等。
Docker这些特性的确解决了企业IT基础架构很多问题,合理的利用这些特点将更健壮和强大您的IT基础架构。也是为什么越来越多的企业拥抱它的原因!
可能您觉得眼前这种模式并没有明显带来什么好处,但从长远看,细细品味,还是可以提高更大生产力的!
以上场景特点相互相应,只有一个共同目标:简化部署流程,提高生产力!
docker与虚拟机性能比较
https://blog.csdn.net/cbl709/article/details/43955687
Docker为何未在生产环境中取得广泛成功?
如今Docker需要的是更多的人将容器部署到生产环境,而且是大批人在部署。遗憾的是,许多公司一开始就对PaaS寄以厚望,利用当前的架构过度补偿。如果你规模很小,或者规划将Docker部署到全新的环境,这种方法才可行。想在生产环境下得到更广泛的使用,我们就需要解决本提到的一些问题,以便让Docker的优点明显压倒缺点。
Docker的发展势头一天比一天强劲,它显然在试图解决实际的问题。然而,对如今许多的生产环境用户来说,没有出现优点压倒缺点的局面。在开发、测试和持续性集成等环境下,Docker在让容器吸引广大开发人员方面确实有上佳的表现,不过它还没有颠覆生产环境。按照DockerCon 2015的“生产环境下的Docker”这一主题,我想公开讨论Docker想在生产环境使用场合下得到广泛采用还没有克服的种种挑战。这里提到的问题没有一个是新问题,它们都以某种形式出现在GitHub上。大多数问题我已经在大会演讲中或与Docker团队交流中讨论过。本文倒不是要明确指出什么不再是问题:比如说,新注册中心(registry)克服了旧注册中心的许多不足。本文并没有提到仍然问题重重的许多方面,不过我认为下面这些问题是近期内需要解决的最重的问题;只有解决了这些问题,更多的企业组织才能够迈出一大步,在生产环境中运行容器。我在电子商务公司Shopify运行Docker的经历对本文有很大的影响;一年多来,我们一直在容器上大规模运行核心平台。由于像Docker这样发展这么迅猛的技术,不可能一切都保持现状。如果你发现不正确之处,务必联系我。
映像构建
为大型应用程序构建容器映像依然是个挑战。如果我们要依赖容器映像用于测试、持续性集成和紧急部署,就需要在不到1分钟的时间内将映像准备就绪。Docker文件(Dockerfile)让这对大型应用程序来说几乎不可能。虽然Docker文件易于使用,但是位于过高的抽象层,无法支持复杂的使用场合:
- 带外缓存,面向特别错综复杂的、针对特定应用程序的依赖项;
- 在构建时访问密文(密码、密钥和相关内容),又不将它们提交给映像
- 全面控制最终映像中的层
- 并行处理构建层
大多数人并不需要这些功能,但是对大型应用程序而言,其中许多功能是快速构建映像的先决条件。Chef和Puppet等配置管理软件使用广泛,但是让人觉得用于构建映像过于笨拙。我打赌,在今后十年内,现有形式的这类系统会因容器而逐渐退出历史舞台。然而,许多应用程序依赖它们来配置、部署和编排。Docker文件无法真实地记录下现在由配置管理系统管理的复杂性,但这种复杂性需要在某个地方加以管理。在Shopify,我们最后使用docker commit API,从头开始构建了自己的系统。这个过程很麻烦,我希望这一幕不会出现在任何人身上,我很想摆脱这种局面,但是我们又不得不扫除障碍。很少有人会花这么大的力气去管理用于生产环境的容器。
这个领域会出现什么情况不得而知;目前在这个领域,开展的研究工作并不多(一个例子是dockramp,这是另一种打包器)。Docker引擎会在将来有所改进,将构建基本步骤(添加文件和设置入口点等)与客户端(Docker文件)分开来。为版本1.8所做的合并工作已经让这变得更容易,为配置管理工具厂商、业余爱好者和公司进行试验尝试创造了条件。考虑到配置系统的历史还很短,认为一种标准有望搞定这个问题(就像运行时标准那样)是不切实际的。什么时候可以实现可扩展的映像构建,相当不明朗。据我所知,没人在积极迭代,很遗憾这种现状已维持一年多了。
垃圾收集
每个部署的重大Docker系统到头来要编写垃圾收集器,以便清除主机上的旧映像。使用了各种启发式方法,比如清除超过X天的旧映像,在主机上最多执行Y个映像。Spotify最近开放了其系统的源代码。我们还在很久以前就编写自己的垃圾收集器。我能明白为此设计一种易预测的用户界面(UI)有多难,但是这又是核心中绝对需要的。当生产环境的机器嚷着要存储空间时,大多数人无意中发现要求收集垃圾。最后,你会遇到同一映像,Docker注册中心因庞大映像而溢出,不过这个问题已列在了发行版路线图上(详见https://github.com/docker/distribution/blob/master/ROADMAP.md#deletes)。
迭代速度和核心状态
Docker引擎致力于1.x版本的稳定性。在版本1.5之前,降低准入门槛以便在生产环境得到采用方面所做的工作不多。开发容器的公众心理模式对Docker的成功而言必不可少,Docker害怕破坏这种模式是有其道理的。如果用户体验(UX)方面的每个变化经历的过程时间过长,迭代速度难免受到影响。自版本1.7起,Docker开始发布试验性版本,以网络和存储插件带头。这些功能特性被明确标为“未准备用于生产环境”,可能会从核心中取出或者随时经历重大变化。对于早已看好Docker的公司来说,下面这个是好消息:它让核心开发团队可以更快速地迭代开发新功能,不用担心本着最佳设计的精神而破坏次要版本之间的向后兼容性。公司仍然很难改动Docker核心,因为它需要分支――这是导致最终失败的行为和维护负担,或者需要得到上流接受;对于值得关注的补丁来说,这常常很耗费人力。自版本1.7起,宣布插件后,解决这个问题的策略就很明确:让每一个固执己见的的组件都可以插入,最后显示了“带电池而且可以更换”这种理念的成果,这种理念最早是在2014年的DockerCon欧洲大会上提出来的(不过相当模糊)。在6月份的DockerCon大会上,很高兴听到这归入到“管道”(Plumbing)这个大主题来探讨,作为核心开发团队的重中之重。虽然未来终于大有希望,但是这在今天仍然是个痛点,就跟过去两年一样。
日志
日志是表明有望得益于之前变化的一个方面的例子。这并不是引起强烈关注的问题,却是普遍性的问题。目前没有理想的、普通的解决方案。日志到处都是:尾部日志文件、容器里面的日志、通过挂载发送到主机的日志、发送到主机syslog的日志,通过fluentd(开源数据采集器)等工具来暴露日志,从应用程序直接发送到网络的日志,或者发送到文件的日志,让另一个进程将日志发送到Kafka。在版本1.6中,支持日志驱动程序的功能已并入到核心中(https://blog.docker.com/2015/04/docker-release-1-6/);然而,驱动程序在核心中必须得到接受(这并非易事)。在版本1.7中,已并入了试验性支持进程外插件的功能,但是让我失望的是,它并不随带日志驱动程序。我认为,版本1.8会计划添加这项功能,但是在官方记录中找不到这项。到那时,厂商们就能够编写自己的日志驱动程序。社区内部的共享将轻而易举,大型应用程序再也不必求助于设计定制的解决方案。
密文
迁移到容器的人大多数依赖配置管理,在机器上安全地配置密文;然而,继续沿着配置管理这种老路子配置容器中的密文很笨拙。另一个办法就是将密文与映像一同分发,但是这带来了安全风险,而且很难在开发、持续性集成和生产环境之间安全地回收映像。最纯粹的解决办法就是通过网络访问密文,让容器的文件系统保持无状态。就在不久前,这方面还没有任何面向容器的机制;不过最近,两家颇令人关注的密文代理系统Valut(https://vaultproject.io)和Keywhiz(https://github.com/square/keywhiz)开放了源代码。在Shopify,我们一年半前开发了ejson(ejson是一种简单的库,用嵌入在JSON文件中的公钥加密该文件中的所有值,详见https://www.shopify.com/technology/26892292-secrets-at-shopify-introducing-ejson),以解决这个问题,从而管理JSON文件中非对称加密的密文文件;然而,它就所运行的环境有一些假设,因而让它与密文代理系统相比,不是很理想的一般性解决方案(如果你很好奇,可以参阅这篇文章https://www.shopify.com/technology/26892292-secrets-at-shopify-introducing-ejson)。
文件系统
Docker依赖来自文件系统的写时拷贝机制(CoW)。这是为了确保如果有100个容器是从一个映像运行的,你就不需要100倍的磁盘空间。相反,每个容器在映像上面创建一个CoW层,只有利用原始映像创建文件时,才使用磁盘空间。容器的“规范市民”对容器里面的文件系统带来的影响极小,因为这类变化意味着容器具有了状态,这是绝对禁止的。这类状态应该存储在映射到主机或的卷上或通过网络来存储。此外,层次技术节省了部署之间的存储空间,因为映像常常相似,有共同的层。在Linux上支持CoW的文件系统存在的问题是,它们都有点新。我们Shopify在几百个负载相当大的主机上遇到过几种文件系统:
AUFS。看到整个分区在我们要重新挂载的地方锁起来。速度缓慢,耗用大量内存。代码库很庞大,难以读取,这可能就是为什么它没有被接受、进入到上游,因而需要自定义内核。
BTRFS。面临学习曲线,需要学用一套新的工具,因为du和ls不管用。与AUFS一样,我们看到分区冻结,内核锁隹,尽管玩猫捉老鼠的游戏,希望内核版本保持是最新版本。临近磁盘空间极限时,BTRFS的行为捉摸不定,如果你有1000个这样的CoW层(用BTRFS的术语来说是子卷),也是如此。BTRFS耗用大量内存。
OverlayFS。这在3.18版本中已并入到Linux内核,对我们来说已相当稳定、快速。它耗用的内存要少得多,因为它设法在索引节点(inode)之间共享页面缓存。遗憾的是,它需要你运行未被大多数发行版采用的较新内核,这常常意味着构建自己的内核。
幸好对Docker来说,Overlay文件系统很快就会无所不在,不过在我们看来,运行大量节点时,AUFS这一默认文件系统对生产环境来说仍然很不安全。不过很难说在这里该如何是好,因为大多数发行版也并不随带已准备支持Overlay的内核(有人提议Overlay作为默认文件系统,但由于这个原因遭到驳斥),不过这绝对是这个领域的发展方向。看来我们除了等待别无他法。
依赖处于前沿的内核功能
正如Docker依赖最前沿的文件系统那样,它还充分利用最近为内核添加的大量功能特性,也就是命名空间以及不是太新,又不常使用的控制组(cgroup)。这些特性(尤其是命名空间)还没有在业界得到广泛采用,因而还没有经过考验。我们偶尔会遇到这些特性存在的不明显错误。我们碰到网络命名空间在生产环境下被禁用的情况,那是由于我们遇到过相当多的软死锁,事后查明这些软死锁与实施有关,却又没有资源从上流解决问题。内存控制组耗用相当多的内存,我听到过外头反映不可靠的情况。随着容器得到越来越广泛的使用,大公司可能会率先做好这项稳定工作。
我们在生产环境中碰到的需要加固的一个例子就是僵尸进程(https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)。容器在PID命名空间里面运行,这就意味着容器里面的第一个进程有pid 1。容器里面的init需要执行确认已死的子进程这一特殊任务。某个进程死后,并不立即从内核进程数据结构中消失,而是成为一个僵尸进程。这确保了父进程可以通过wait(2)检测到子进程已死。然而,如果子进程成为孤儿,其父进程就被设成init。该进程随后死后,init的任务就是通过wait(2)确认子进程已死――不然,僵尸进程就会永远存在。这样一来,内核进程数据结构会被僵尸进程耗尽,之后你就得自己想办法。对基于进程的master/worker模式来说,这种场景相当常见。如果worker进程逃出外壳,并花了很长时间,master进程就会使用SIGKILL终结等待外壳命令的worker进程(除非你使用进程组,一下子终结整个进程组)。逃出外壳的派生进程然后被init继承。等该进程终于完成后,init需要对它执行wait(2)操作。Docker引擎可以解决这个问题,通过Docker引擎使用设置PR_SET_CHILD_SUBREAPER确认容器里面的僵尸进程,https://github.com/docker/docker/issues/11529有所描述。
安全
运行时安全对容器来说仍要打个问号;想针对生产环境进行加固是经典的先有鸡还是先有蛋的安全问题。以我们Shopify为例,我们并不依赖容器提供任何额外的安全保障。然而,许多使用场合却依赖容器提供额外保障。由于这个原因,大多数厂商仍在虚拟机中运行容器,而虚拟机的安全久经考验。由于操作系统虚拟机胜出,我希望看到虚拟机在今后十年内消失,因为有人曾在Linux邮件列表上说过:“我曾经听到虚拟机管理程序是活生生的证据,证明了操作系统的无能。”容器在虚拟机(硬件层虚拟化)和PaaS之间(应用程序层)提供了完美的中间体。我知道,运行时安全方面在做更多的工作,比如说能够将系统调用列入黑名单。映像方面的安全一向是问题的根源,但是Docker正在借助libtrust和notary――它们将是新的发行层(https://github.com/docker/distribution)的一部分的,积极改进这方面。
映像层和传输
- 第一个版本的Docker为映像的构建、传输和运行时环境采取了一条巧妙的捷径。它选择了适用于所有情况的工具:文件系统层,而不是为每个问题选择一种合适的工具。这种抽象机制一直作用于在生产环境中运行容器。这是完全可以接受的最小可行产品实用主义,但是每个问题都能极其高效地得到解决。
- 映像构建可以表示为有向工作图。这样可以弄清楚缓存和并行处理,以便迅速地构建可预测的映像。
- 映像传输而不是使用映像层,它就可以执行二进制差异化(binary diffing)。这个话题已研究了几十年。分发层和运行层越来越分离开来,为这种优化创造了条件。
- 运行时环境应该就实施单单一个CoW层,而不是再次使用随意的映像层抽象。如果你在第一次读取时使用AUFS之类的统一文件系统,就遍历链接文件列表来汇编最终文件。这很缓慢,而且完全没有必要。
层模式对映像传输以及对构建来说是个问题。这意味着,你必须极其小心对待映像每个层中的东西,因为不然你很可能到头来为大型应用程序传输100MB的数据。如果你在自己的数据中心里面有大型链接,这个问题不大,但是如果你想使用Docker Hub之类的注册中心服务,这就会通过公开的互联网来传输。映像分发目前正在积极开发之中。Docker公司有足够的动机将这方面做得可靠、安全而快速。至于构建,我希望这为插件创造条件,以便一种优秀的解决方案浮出水面。
结束语
另外许多话题有意没有探讨,比如存储、网络、多租户、编排和服务发现。如今Docker需要的是更多的人将容器部署到生产环境,而且是大批人在部署。遗憾的是,许多公司一开始就对PaaS寄以厚望,利用当前的架构过度补偿。如果你规模很小,或者规划将Docker部署到全新的环境,这种方法才可行。想在生产环境下得到更广泛的使用,我们就需要解决上述一些问题,以便让Docker的优点明显压倒缺点。
Docker将自己置于令人兴奋的位置,充当PaaS的接口,无论是发现、网络还是服务发现,应用程序没必要关心底层基础设施。这是好消息,因为正如Solomon所说,Docker的最大优点就是,它让人们达成了共识。我们终于开始就映像和运行时环境之外的其他方面达成共识。
我与Docker公司的人员深入探讨过所有上述问题。在一定程度上存在所有这些问题的GitHub Issues。我在这里的目的是,仅仅是提供个人之见,阐明哪几个方面对降低Docker的准入门槛最为重要。我对未来满怀激情,但是我们仍有大量工作要做,才能让Docker应用到更多的生产环境。
原文标题:Why Docker is Not Yet Succeeding Widely in Production
生产环境用Docker?先搞定这些再说!
编者按:Docker作为近几年来最受欢迎的开源技术,操作简单是其迅速能流行起来的原因之一。写个Dockerfile,在本地build成镜像,就能很快地运行起来。但那是对于个人开发者来说,对于公司或组织来说,在生产环境中应用Docker并不容易,本文将为你细数在生产环境中应用Docker之前,需要做的关键决策。以下为译文:
关键决策1:镜像管理
在开发环境中,写一个Dockerfile或docker-compose.yml文件来构建镜像是很简单的事情,但在生产环境中,你应该创建一个可持续的流程来构建Docker镜像文件。这会减少对本地环境的依赖,同时避免开发笔记本成为唯一构建新镜像的手段。还能让你创建一个从代码提交到Docker镜像的持续部署的流程,这个流程还不需要任何人为的干预。
你可能还需要一个私有的Docker镜像仓库。虽然Docker提供了私有的镜像仓库,你可以去部署和管理,但限于国内的网络环境,用起来会很不爽。
关键决策2:云的选择
大部分自建Docker生产环境的用户,也还是要把Docker部署到IaaS上。虽然目前许多IaaS都支持Docker容器的部署,但是大部分的资源消耗都超出了容器实例本身所需的资源,在最开始做好价格的调查很重要。
还要注意在不同平台的容器部署流程也不尽相同,如果未来想更换云服务商会比较麻烦。如果你希望采用多个云避免被lock-in,还需要做一些额外的方案来保证流程的一致。这样考虑的话,选择一家CaaS服务更能直接达到目的。
关键决策3:网络访问和安全
在本地开发环境中跑容器,是不会产生安全风险的。所有的进程跑在单一的主机上,可以将常见的针对生产环境服务器的网络入侵和攻击的风险隔离在外。
为了方便在开发过程中的故障检修,开发的配置是很开放的。而在生产环境中的网络设置需要更多的考虑。比如,一些特定的容器是不能被公网访问的,只能被一个私有网络中的其它容器访问。网络流量监控,暴力破解等攻击方式应该都能被识别出来,并能得到适当的处理。
你还需要时刻关注新发布的安全包,决定你的主机和容器是否安全,或者是必须安装的。将容器投入生产环境时,需要考虑网络访问,还有你的容器和Docker主机是不是打了补丁,不要忽略了生产环境的关键步骤。
关键决策4:容器和主机间的负载均衡
一旦服务从一个单独的容器迁移到跨主机的多个容器上,就会有负载均衡的需求。使用类似Nginx或HAProxy的工具是最常用的做法,但要随着容器的创建和部署,以及新的Docker主机的添加,保持配置的更新是很难的。
注意!要支持多版本同时运行,除非你计划在升级时,离线部署应用。你的负载均衡策略要考虑到这一点,防止掉线或者网络被路由到错误的版本。
关键决策5:部署流程
许多开发者都认为:在开发环境中用起来没问题的工具,在生产环境中用起来肯定也没问题。但情况并不是这样的,比如Docker Compose在开发和生产环境配置就大相径庭,从volume绑定到端口绑定和网络配置都不一样。在多主机的环境下,复杂度会更高。另外,生产环境中还会有很多开发环境之外的容器,比如日志收集,外部数据库,和HA消息代理等。
协调环境配置的差异需要很多脚本的工作,它不像在生产环境中一行docker-compose up这么简单。从一个简单的,单容器的应用到多个容器,通过负载均衡器分担workload的环境中,要事先做好各种细节的考虑。随着应用的成熟和流量的上升,滚动升级(rolling upgrade)和蓝绿部署(Blue-green deployment)的策略都可以预防网站宕机。
关键决策6:服务发现
随着容器数量的增长,管理这些容器的成本也在增加。许多工具可以管理这个过程,大部分需要被集成到你的Docker生产环境中。不管选择什么都要保证服务注册和容器实例的同步,以及容器被部署到多个Docker主机上时的负载均衡,这样做可以保证你的应用被路由到特定的容器实例。
关键决策7:日志管理
在开发环境中使用DockerCompose会让日志变得琐碎,跨主机的多容器环境会让情况变得更复杂。分布式日志可以将多个服务器中的日志汇总起来,你的生产环境基础设施需要跨容器的日志收集器。还需要提供相应的查看和搜索这些日志的功能。
关键决策8:容器监控
在生产环境中对容器的监控相当重要,从Docker主机到容器,你需要知道每个服务和整个系统的健康状况。选择正确的工具和监控策略,可以减小宕机带来的损失,还能最大化的利用主机资源,保证良好的用户体验。
关键决策9:数据库管理
开发环境中,数据库可以跨容器托管,不用担心I/O性能。在生产环境中,这个问题就不容忽视了,尤其是当我们的应用有很高的用户体验需求时。扩展数据库来按需处理I/O的增长,以保证高可用性和可靠的备份/存储策略,是保证现代web应用和移动APP运行的关键。选择生产环境的策略会对你的用户产生积极或消极的影响。
以上缺一不可吗?
是的!以上都是产品成功不可或缺的要素,除非你在部署一个流量不大的,不重要的应用。要记住,Docker只是一个工具,并不是一个产品化的架构解决方案。Docker提供了很多令人『惊艳』的功能,但想在开发环境中使用Docker,要付出的努力并不亚于其它工具。
如果你的核心并不在这些技术,而是业务,建议选择一家CaaS供应商,而不是自己搭建整个Docker生产环境。(比如灵雀云,逃)
Dockerfile文件详解
什么是dockerfile?
Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。
docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。
例:
docker build -f /path/to/a/Dockerfile
Dockerfile的基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释。
Dockerfile文件说明
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以#字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV等指令。
在这里列出了一些常用的指令。
FROM:指定基础镜像,必须为第一个命令
格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
示例:
FROM mysql:5.6
注:
tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER: 维护者信息
格式:
MAINTAINER <name>
示例:
MAINTAINER Jasper Xu
MAINTAINER sorex@163.com
MAINTAINER Jasper Xu <sorex@163.com>
RUN:构建镜像时执行的命令
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:shell执行格式:
RUN <command>
exec执行格式:
RUN ["executable", "param1", "param2"]示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]注:
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
ADD:将本地文件添加到容器中,tar类型文件会自动解压,可以访问网络资源,类似wget
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
COPY:功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
CMD:构建容器后调用,也就是在容器启动时才进行调用。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)示例:
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
注:
CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
ENTRYPOINT:配置容器,使其可执行化。配合CMD可省去"application",只使用参数。
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)示例:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
注:
ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。
LABEL:用于为镜像添加元数据
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...示例:
LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
注:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
ENV:设置环境变量
格式:
ENV <key> <value>
ENV <key>=<value> ...示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
EXPOSE:指定于外界交互的端口
格式:
EXPOSE <port> [<port>...]示例:
EXPOSE 80 443
EXPOSE 8080
注:
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
VOLUME:用于指定持久化目录
格式:
VOLUME ["/path/to/dir"]示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用2 容器并不一定要和其它容器共享卷3 修改卷后会立即生效4 对卷的修改不会对镜像产生影响5 卷会一直存在,直到没有任何容器在使用它
WORKDIR:工作目录,类似于cd命令
格式:
WORKDIR /path/to/workdir示例:
WORKDIR /a (这时工作目录为/a)
WORKDIR b (这时工作目录为/a/b)
WORKDIR c (这时工作目录为/a/b/c)
注:
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
USER:指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
示例:
USER www
注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
ARG:用于指定传递给构建运行时的变量
格式:
ARG <name>[=<default value>]示例:
ARG site
ARG build_user=www
ONBUILD:用于设置镜像触发器
格式:
ONBUILD [INSTRUCTION]示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src注:
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
以下是一个小例子:
# This my first nginx Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos
#MAINTAINER 维护者信息
MAINTAINER tianfeiyu
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 文件放在当前目录下,拷过去会自动解压
ADD nginx-1.8.0.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx"]
最后用一张图解释常用指令的意义^-^
八个Docker的真实应用场景
【编者的话】Flux 7介绍了常用的8个Docker的真实使用场景,分别是简化配置、代码流水线管理、提高开发效率、隔离应用、整合服务器、调试能力、多租户环境、快速部署。我们一直在谈Docker,Docker怎么使用,在怎么样的场合下使用?也许本文可以帮到你。有需要交流的地方,可以通过评论与我们交流。
几周前我们参加了DockerCon ,Dockercon是首个以Docker为中心的技术大会。它面向开发者以及对在Docker开放平台上构建、交付、运行分布式应用感兴趣的从业者,不论这些开放平台是运行于自用笔记本上或者是数据中心的虚拟机上。我们参加了这次大会,Flux7是Docker基础的系统集成合作伙伴,同时也是演讲嘉宾。
我们的CEO Aater Suleman和我们的一位客户一同进行了演讲。虽然DockerCon大会十分有趣,但我觉得大会太关注Docker的具体细节,而忽略了Docker的使用场景。所以,在这篇文章中,我想介绍并分享一些Docker的实际应用案例。
在我们讨论Docker的使用场景之前,先来看看Docker这个工具有什么特别的地方吧。
Docker提供了轻量级的虚拟化,它几乎没有任何额外开销,这个特性非常酷。
首先你在享有Docker带来的虚拟化能力的时候无需担心它带来的额外开销。其次,相比于虚拟机,你可以在同一台机器上创建更多数量的容器。
Docker的另外一个优点是容器的启动与停止都能在几秒中内完成。Docker公司的创始人 Solomon Hykes曾经介绍过Docker在单纯的LXC之上做了哪些事情,你可以去看看。
下面是我总结的一些Docker的使用场景,它为你展示了如何借助Docker的优势,在低开销的情况下,打造一个一致性的环境。
1. 简化配置
这是Docker公司宣传的Docker的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。
2. 代码流水线(Code Pipeline)管理
前一个场景对于管理代码的流水线起到了很大的帮助。代码从开发者的机器到最终在生产环境上的部署,需要经过很多的中间环境。而每一个中间环境都有自己微小的差别,Docker给应用提供了一个从开发到上线均一致的环境,让代码的流水线变得简单不少。
3. 提高开发效率
这就带来了一些额外的好处:Docker能提升开发者的开发效率。如果你想看一个详细一点的例子,可以参考Aater在DevOpsDays Austin 2014 大会或者是DockerCon上的演讲。
不同的开发环境中,我们都想把两件事做好。一是我们想让开发环境尽量贴近生产环境,二是我们想快速搭建开发环境。
理想状态中,要达到第一个目标,我们需要将每一个服务都跑在独立的虚拟机中以便监控生产环境中服务的运行状态。然而,我们却不想每次都需要网络连接,每次重新编译的时候远程连接上去特别麻烦。这就是Docker做的特别好的地方,开发环境的机器通常内存比较小,之前使用虚拟的时候,我们经常需要为开发环境的机器加内存,而现在Docker可以轻易的让几十个服务在Docker中跑起来。
4. 隔离应用
有很多种原因会让你选择在一个机器上运行不同的应用,比如之前提到的提高开发效率的场景等。
我们经常需要考虑两点,一是因为要降低成本而进行服务器整合,二是将一个整体式的应用拆分成松耦合的单个服务(译者注:微服务架构)。如果你想了解为什么松耦合的应用这么重要,请参考Steve Yege的这篇论文,文中将Google和亚马逊做了比较。
5. 整合服务器
正如通过虚拟机来整合多个应用,Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本。由于没有多个操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比虚拟机提供更好的服务器整合解决方案。
6. 调试能力
Docker提供了很多的工具,这些工具不一定只是针对容器,但是却适用于容器。它们提供了很多的功能,包括可以为容器设置检查点、设置版本和查看两个容器之间的差别,这些特性可以帮助调试Bug。你可以在《Docker拯救世界》的文章中找到这一点的例证。
7. 多租户环境
另外一个Docker有意思的使用场景是在多租户的应用中,它可以避免关键应用的重写。我们一个特别的关于这个场景的例子是为IoT(译者注:物联网)的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。
使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于Docker环境的启动速度和其高效的diff命令。
你可以在这里了解关于此场景的更多信息。
8. 快速部署
在虚拟机之前,引入新的硬件资源需要消耗几天的时间。虚拟化技术(Virtualization)将这个时间缩短到了分钟级别。而Docker通过为进程仅仅创建一个容器而无需启动一个操作系统,再次将这个过程缩短到了秒级。这正是Google和Facebook都看重的特性。
你可以在数据中心创建销毁资源而无需担心重新启动带来的开销。通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。Vsa
原文链接:8 Ways to Use Docker in the Real World(翻译:钟最龙 审校:李颖杰)