Docker与微服务 云端生产环境部署 应用Docker化改造 持续交付流程实践 交付方式变革改变了全球经济格局很多人都是拿集装箱的故事开始的,我也不例外。一百年前,一个叫做集装箱的东西,改变了全球定律,现在在跨国贸易的90%的货物都是通过集装箱来运输的。 一个不起眼的单,一个交付上的改变,就可以改变整个经济。Docker在这个时代就是改变整个软件交付的变革,现在几乎在所有的运维或者架构上都在用Docker进行交付,为什么? Docker in Alibaba阿里巴巴Docker的使用无处不在,2011年,淘宝开始采用容器技术,配合阿里内部自身的一些架构,极大地提高了开发和运维的效率,使得整个开发效率变得更高。在“双11”这样的大促中,发挥了巨大的作用。 阿里百川是一个面向移动平台的电商PaaS,它利用Docker可以支持不同的编程环境,让用户可以快速应用软件在线上运行。 基于阿里的实践,我们从去年开始在公共云计算平台上推行了容器服务,大家可以不用关心Docker底层的技术,网络存储、资源管理等等不用关心,大家只用关心自己Docker的应用部署就可以了。 同时,Docker在很多领域都会发挥着巨大的作用。 比如前一段时间谷歌的AlphaGo,其实背后计算很重要的一个框架就是深度学习框架,搭建一个深度学习框架是一个非常复杂的学习,你要配置相应的深入计算框架的各个软件。 可是在阿里提供给客户的服务,大家只要用Docker镜像就可以快速地在一组HPC的机器搭建起来,你可以按需地获得深度学习所需要的计算能力,也许你也有一天可以开发一款进行PK。 其实Docker在阿里巴巴的使用无所不在,你能想象,像阿里这么庞大的一个系统,包含了虚拟化、数据库、大数据、网络,这么庞大的系统,几百个组件,我们现在对它Docker处理,加速它开发运维以及输出的速度。 我们可以把整个阿里云在几个小时之内就搭建起来。所以说,Docker已经彻底地改变了我们对软件交付和运维的一些场景。 为什么Docker这么重要?加速应用交付,缩短梦想距离我们谈互联网公司,互联网公司的核心竞争力是什么? 就是效率,就是看你能不能最快速度地推出产品,最低的成本,最快的地迭代。 而在十年前我们的软件开发是什么样的? 我们的应用是一个整体式的应用,它是由大的团队来开发,这个团队分为开发团队和运维团队,开发团队有前端团队、后端团队、数据库团队,这些团队可能因为业务需求互相扯皮,到最后使整个软件开发迭代的速度极为缓慢。 在传统企业迭代的周期在半年到一年,这个速度远远不能满足业务方的需求,同时更苦逼的是我们运维人员,直到最后一刻,软件人员讲解马上要上线,把一堆安装脚本给运维人员,让运维人员去安装和部署,去保证它的高可用。 大家能想象吗?这样的事情怎么可能发生! 所以说,大家顶着一个巨大的挑战: · 第一个就是变化缓慢,在互联网时代谁变得慢,谁就死得快; · 第二,为了保证这样大型的整体应用,它非常难伸缩,通常为了适应大的流量,我们只能增加新的CPU等方法来扩展。 大家都知道,如果要保证线性计算性能的增长,可能需要花费的代价更高。另外,整个系统持续运营能力也是不好的,越大越不稳定,其中一个组件坏掉,就会产生雪崩效应,整个系统就会宕掉。 这个过程非常痛苦,阿里经过这样的过程,现在的互联网公司包括阿里都已经演变成如下的结构。 底层是一个基于云服务或者虚拟化的计算架构,每个业务比如电商,可以有用户管理、商品管理,我们的 、导购、 。 这些都是不同的模块,每个模块是由一个小组,每个图片都可以独立部署,组件之间是通过标准化的协议互相通信。 只有这样才能保证速度,才能保证在竞争中我们能够活下来。 Docker 与虚拟化技术
Docker的出现进一步地推动这件事,Docker是一种轻量级的操作系统虚拟化方案,更加敏捷地进行交付。 Docker本身具有良好的可移植性,这一点更为重要,我们能够在开发、测试、生产中用统一的方法、统一的介质来交付软件。 想象一下,如果是在一个混合云场景,比如说“双11大促”,很多现在的计算力已经移到公有云上,因为是按需分配,很快地可以把应用扩展到整个数据中心。 结合Docker容器和虚拟化技术很多人说“Docker革了虚拟化的命”,我们认为Docker和虚拟化在很多程度上也是互补的。 Docker技术依然有本身的限制,比如Docker在系统的安全隔离方面做得并不好,像虚拟化这些Docker不能做,目前一个最成熟的方案是把虚拟化的技术和容器技术结合在一起。 在公有云上非常不建议大家采用多租户的方式,因为有大量的安全漏洞。 Cloud Native Computing随着微服务和容器技术的发展,在去年谷歌牵头成立了一个Cloud Native Computing基金会。 它定义了未来的原生应用的一些基本要素和框架,以微服务架构以容器方式交付,支持DevOps,这个平台是动态自己管理的,不是手动的。 为什么做这件事?我们要以持续发展的眼光来看,单体应用早晚会碰到天花板,它的复杂性、可伸缩性一定撞到墙。 所以,我们才采用微服务,微服务不是免费的午餐,它带来好处的时候也带来复杂性,以前我运维一个应用,现在要运维几十个服务。 以前也有同事跟我说是二十个服务,分解成微服务之后是将近四百个,他的管理数量多了一个量极。 如何让服务和服务之间监控它的健康状况?一旦一个服务挂掉,我们要对它进行隔离、熔断、降级,然后我们怎么对这个微服务进行版本更新,保证以前的产品不会受到中断? 这些都是巨大的影响。 这些事情如果让人手动来做的话,肯定不行,一定要用平台、用自动化的方式。所以,这就是为什么大家在强调需要一个平台来支撑。 云端漫步:开始 Docker 之旅
其实在云上使用服务器并不复杂,大家已经非常习惯于在自己的开发、测试、数据中心使用Docker技术,但是在云上大家为什么不呢? 大家觉得要虚拟机、配各种东西很麻烦,但是其实不是这样的。 Docker在2014年底推出了Docker Machine,利用Docker Machine就可以快速地在云上创建一个Docker的云环境。 要做的事情很简单,下载Docker Machine之后寻找云的供应商的驱动,比如现在的阿里云、亚马逊、Aure这样的一些Driver,通过Driver,通过命令行就可以在上面部署我的容器化应用,非常简单。 生产环境中使用Docker但是如果真的在云上、在生长环境选Docker,你要面临的挑战远不仅如此。 一个Docker的实力肯定不够,一定是一个集群,这个集群怎么管理,网络怎么桥接,存储怎么办,如何进行资源调度,怎么安排,这是一个非常复杂的事情。 为了这件事,很多互联网企业都提供了所谓的产品,我找几个给大家介绍一下。 · Docker Cloud,Docker在去年11月收购了tutum.co在今年2月份推出了Docker Cloud,它基本上提供了Docker自身原生的一个编排的API。 · 亚马逊在2014年11月份推出了 EC2 Container Service,它最早是基于一个自己的私有API提供了容器描述的服务,但是在去年逐渐开始支持更加广泛的Docker,来描述一个组合的容器化应用。 · 谷歌的Compose template,它也是在2014年7月开源的,它是集成了以前的很多思想,相应的一些调度的很多历史。推出来之后得到很大的欢迎,但是它提供了一套自己特有的对容器化应用抽象。 容器集群管理 - Docker Swarm为了更好地阐述我们的一些内容,我今天会介绍一下阿里容器服务。阿里容器服务为了解决用户在开发、测试环境无缝迁移,我们完全兼容了Docker原生编排方案。
Docker原生编排方案包括哪些内容? · 首先是Docker Swarm,它是一个很精巧的设计,我能不能把一组Docker engine变成一个虚拟的Docker engine,我都向这一个虚拟的Docker engine下发指令,由它的控制节点真正调动到一个实际的节点来执行。 · 它的架构非常简单,在每台节点上只需要一个Docker engine之后再安装一个Agent就好了,Agent通过上报就能够实现一个机器的自动注册,通过这个功能上面有一个节点能够发现里面的节点信息,就能够自动地构建集群。 · 它是一个非常精巧的抽象,因为它几乎99%地支持了所有Docker原生的API。 它带来两个好处: 它可以和现在三方所有和Docker连接的工具集成在一起,不做任何改变; 它有另外一个好处是提供了一个可以插拔的架构,比如说它的调度器、存储和网络都可以非常容易地进行扩展。 另外它有一个很大的缺点: Swarm和Docker一样,它本身的抽象基本单位是容器,并没有站在服务的角度去思考。 容器编排 - Docker ComposeDocker Compose源于Docker的一次收购,Docker Compose是描述如何将一组容器和这个容器相关的资源组合在一起。 比如我们拿Wordpress来举例,然后Mysql,一个简单的编排模板就可以把它描述出来,通过Wordpress镜像在一起,通过链接连接到Mysql,通过volume来创建。 通过这种方式可以非常优雅地描述一组容器是怎么关联工作在一起的,而且通过一键就可以把整个应用站启动起来。如果我们对它进行一些伸缩的话,也非常简单。 优点 · 简单好用,便于开发。它是一个非常好的开发工具,在Docker的开发社区中已经有超过70% 的人在使用Docker Compose进行镜像开发。 · 扩展了对网络、存储的支持。不但可以描述和容器,还可以描述容器和它对应的基础资源的一些关联。 不足 面向开发和部署,不支持自动化运维。比如说,怎么跟运维进行监控,是不是能够进行弹性收缩,它都没有做,因为它本身就是一个开发工具。 阿里容器服务我们理想中的一个容器开发平台是什么呢? 我们的阿里云容器服务提供的一个能力,首先底层是公共云计算平台或者企业的专有云。在此之上是容器层,除了Docker之外,Docker仓库,还有相应的存储和网络。 原生的Docker是远远不够的,它提供了相应的机制,我们也建议这种机制把云端的块存储、对象存储、网络存储都能够非常容易地集成进来。 在容器层之上就是集群管理和调度层,我们做了大量的优化和改进,比如说刚才大家谈到一个应用,我们要保证它的迁移,我们要做那么多事情,我们不能保证它不宕掉,我们能够保证什么呢? 我们能够保证资源调度,哪怕一个数据中心断电,一个地区的数据中心断电,也可以保证资源调度。 另外,在容器编排的角度,我们怎么很容易地把一个服务 出去,很容易地对容器进行日志采集和监控?我们做了大量的扩展,依然可以做到非常好的容器应用的管控。 在此之上就是我们的服务层,阿里本身的微服务架构做了很久,在开源界是非常流行的,我们把这些经验都内化到我们的支持能力中来。 其中的一个很大关键是如何做服务的发现、服务的路由,我们扩展了很多,通过BNS发现,通过负载均衡来实现服务节点之间的动态的负载均衡,通过这些东西,让您的微服务做得很好。 在服务层之上就是接入层,让Web应用可以非常容易地接入到你的自身应用上。 这是我们整个容器平台的核心,但是大家知道,一个不开放的平台是远远不够的,因为容器不能解决所有的问题,容器一定要跟现有企业的应用或者云服务打通。 我们做了很好的集成能力,能够非常容易地跟云服务集成,我们能够跟第三方工具集成,把容器这个技术融合到您自己开发的流程中,同时我们提供云管控。 管控能力,除了自身接入我们的云监控日志之外,实际上我们整个系统里所有的管控框架都是可以随便扩展的,因为我们认为一个不够开放的平台基本上就是耍流氓,容器不是你的信息孤岛,一定要跟现有的IT管控结合在一起。 我们也提供了很多范例怎么利用开源的框架,迅速地搭建一个您自己需要的云监控的能力,这些我们在后面的文档中有一些示例,大家可以去看。 什么应用可以运行在容器中讲了这么多,实际上大家一定会关心: 我的应用怎么跑在容器里? 我哪些应用可以被容器化? 大家都会问这些问题。 这是我节选的一个很著名的分类方法,它可以帮助大家去挑选什么样的应用适合在容器里跑、什么样的应用不适合。 它是根据两个维度: 一个维度是长寿还是短命的应用; 另外一个是看它是有状态还是无状态。 · 容器化的应用最擅长的使用就是左面的短命且无状态的应用,因为这样的应用最容易部署。 比如一个Web应用,我们可以很容易地快速把它干掉,我们不在乎它,可以非常快速地部署一个Web应用。 · 另外一个维度就是那些短命,像高性能计算、批处理。 对一个视频进行渲染一定是大量有状态的信息,但是这些信息可以通过Web对象存储来保存,这样的计算密集型任务也非常适合在上面去做,因为我们可以快速地识别一大组集群,通过这样的容器来跑这样的任务。 · 还有一类是长寿但是无状态的,比如说我们的开发测试环境一直在用或者我们的监控,它会一直跑在那里,但是它本身的状态依赖度是非常小的,这样的应用我们也可以考虑。 · 只有左下角这个维度一般来讲是最有挑战的,它是有状态的服务,一般有状态的服务需要一些调整,包括对存储调整、对网络调整,大家依然需要DBA做很复杂的工作,也不完全做到自动化。 对于这样的一些应用,我们的建议是在测试与开发中可以使用容器技术,但是在生产上非常不建议使用这样的技术。 Docker化应用实战: Ghost 博客
接下来就拿一个特别喜闻乐见的例子跟大家解释怎么样把一个应用容器化。 Ghost 博客是我非常喜欢的一个博客应用,非常简单,非常轻,镜像也非常好用,用很简单的方式就可以把Ghost镜像起来。 但是还有很多问题: · 不是可伸缩; · 不是高可用的。 它所有的数据是保存在本地的Database里面的,如果虚拟机节点宕掉之后,迁移到另外一个节点之上,数据状态都丢掉了。 我们怎么解决?其实大家可以去参考THE TWELVE-FACTOR规范,这个规范得到了居多厂商的支持,它是现在很重要的一个编程规则。 它有几个核心原则: · 应用要和运行的环境解耦 · 应用要和外部调用服务解耦 · 应用要和配置解耦 通过这些解耦我们才能有一些应用变成无状态的,能够快速在云上进行部署和运营。 Ghost 博客 高可用集群1我们只需要增加一个MySQL,让它支持MySQL的驱动就可以了,启动一个ghost+MySQ,通过MySQL进行连接,它们是共享状态的,我们的容器服务也做了很多的优化。 Ghost 博客 高可用集群2我们不建议在生产环境中使用数据库这样有状态的服务,我们该怎么做?
我们看到很多文章都说Docker非常不好用,说它不能运行数据库,Docker本来也不是运行数据库的。 为什么我不直连到我的数据库的实例上呢?当然,这有不同的做法,但是我觉得最好的做法是我们做一个最小的改动,能够让应用层不做任何的感知就可以把一个数据库的镜像,把一个Docker的运行使用变成一个Web,我们增加了一个拓展的能力。 我们增加拓展去引用Web的服务,我们就可以部署在生产环境,而你的应用层不做修改。 Ghost 博客 高可用集群3在这个过程中依然还有一个问题没有解决,用户上传的附件,比如说图片,依然保存在本地存储中,这肯定不行。为了要做这件事情,我们有另外一件事情。
我们可以通过Docker的 Volueme Plugin来解决,它提供了一个非常灵活的机制来支持不同的存储类型,现在已经支持了块存储、对象存储、网络文件系统。 而且更加好玩的事情是,我们所有的网络驱动和Volume的驱动其实都是运行在容器里面的,因为只有通过这样的方式,我们才能对整个系统进行统一的运维和统一的管理。 但是Docker在这方面依然有缺陷,Docker不能区分这样的一些网络驱动,会导致重启Docker Engine的时候,有可能先杀掉你的Volume Driver,你的数据没有保存就坏掉; 或者说,你的网络也是一样,它可能会没有等你的应用杀掉就把你的网络驱动杀掉,这样你的应用和网络彻底中断,这样也是不行的。 我们其实也在社区中提出了改动,我们可以对不同的守护进程进行分级,可以启动一些容器,它可以有更高的系统级别,在启动的时候被优先加载,被停止的时候会被最后停止,在社区1.11版本中会有类似的工作,社区会解决这样的工作。 通过把网络驱动和卷驱动都作为容器处理,还可以给我们带来更大的好处。 我们的整个系统非常可扩展,比如说我们在和一个第三方的网络存储公司谈合作,它现在就是拿一个容器来交付存储驱动,我们不用修改一行代码就可以把存储驱动跑在服务器上,这样可以使我们的系统有更大的可扩展性。 容器化持续集成和交付
Docker的一个重要好处就是可移植性,通过可移植性可以在开发、测试和生产的整个软件生命周期中,以同样的方式交付我们的软件产品。 比如说,我们现在的开发人员就是这样的,只要一键就可以启动本地的开发环境,代码完成以后提交,提交的时候是相应的自身代码和原件。 有了这个以后,相关的Docker基础设施,比如容器、镜像仓库,就可以把相关的代码编译成Docker镜像, 并且在整个测试、生产中一直用这个镜像,所有的步骤可以重复,而且保证一致性。 在这个过程中,所有的东西都是可以支持Docker管理的,而且可以快速更新和管理。 这件事情做完以后有什么好处呢?开发者在第一天就想着“我的代码怎么上线”,这是一个巨大的文化上和时间上的改变。 以前我们讲DevOps,光运维的人员讲没有用,必须要让开发者在开发的第一天就在思考“软件怎么交付、怎么能够在云端为高可用、可伸缩”,这是必须要改变的一个文化和思想。 如果这个改变不了,你用任何技术都改变不了。 以前我们阿里也是一样,开发人员很牛逼,运维人员很苦逼,开发人员开发出来,运维人员熬夜上线,出了故障就回滚,非常低效。 但是我们现在要求开发人员每个功能必须交付一个Docker镜像,把你的前置条件、后置条件、检查的脚本、健康检测的东西在一开始就交付出来,不交付的话,我们运维人员停止接受这样的代码。 通过这样,我们可以快速地去演进。 简化的持续交付流程
源代码管理,我们可以有一个镜像服务,它可以订阅源代码仓库的通知,我们的容器服务也可以订阅镜像变化的通知。 当您的代码变更,比如修改一个网页,把两栏变成三栏,它会通知镜像服务拉取相应的代码构建,打包成镜像之后,自动通知相应的容器服务更新现成的应用。 几分钟之后,变更上线,我们也可以和其他的服务集成在一起。 完整的持续交付流程阿里社交平台何以监控源代码仓库的变更,代码发射变更之后,它拉取代码进行镜像,单元测试通过之后打镜像,通知持续交付服务器进行下一步操作,它是流水线。 在流水线中拿着Docker镜像和Docker文件在测试环境、预发环境、生产环境上部署。 我们同样的一个Docker镜像,同样的一份Docker模板,可以在不同的环境中使用,这样我就能够保证从开发、测试、上线所有东西的一致性。 大家一定要坚持这样的一些理念,因为DevOps很多东西大家都懂,缺的就是坚持。 不可变架构(immutable infrastructure)Docker出来之后为什么得到DevOps领域人士的欢呼? 其实它符合了我们所期望的运维方式。 了解OOpenStac都知道这个很著名的寓言股市,你的应用到底是像一只宠物需要你整天呵护,还像牛群的一头牛,可以随时杀掉毫无伤心,你可以随时有另外一头牛补充上来。 让这个系统变成自维护,非常健壮,不会因为任何节点的失效而导致整个系统终止。 利用不可变性来运维基础架构: 一旦实例化后,永不改变;只会用另外的一个实例正确的取代它。 优点 · 避免环境间的不一致。这在我们日常生活中占了很大的比重,超过30%的线上错误都是因为开发环境和测试环境与线上环境不一致导致的。 如果我不可变架构就可以保证所有代码除了门都是一模一样的,永远按照你预期的方式来运行,测试和上线、生产是同样的东西。 · 简化部署复杂度。在原地打补丁升级非常难,尤其是很多系统软件,有很多副多少。 · 低成本回滚。写个回滚代码复杂很多,而且很难保证正确,因为大家从来不测回滚。 其实这个事情并不新奇,以前有个虚拟机,在家配个自动化的工具也可以,但是Docker让这件事情做得更快,变得更简单。 就等于说,每个Docker镜像实际上是不可变的,它就是一个进程,随时可以替换出来一个新的镜像。 Docker启动速度特别快,以前拿虚拟机做回滚可能需要几分钟时间,但是如果用Docker回滚时间在秒级,用户是感觉不到中断的。 Docker:不可变架构梦想成真要达到这一点也需要大家注意,因为我知道很多人依然在今天把Docker容器当成轻量级虚拟机来使用,这个没有什么不好,只是大家的场景不一样。 但是,我请大家在做这件事情的时候一定要三思,当你把当容器当作轻量级虚拟机的时候,你一定要再次思考一下,您这样做可能会丧失掉Docker很多好的特性,最重要的就是不可变性。 为了达到这一点,我们需要做一些正确的工作: · 永远不要手工修改容器中的内容,你的容器应该永远是拿代码构建出来的。 · 尽量不要使用latest作为镜像标签,生产中你要回滚,你要知道回滚哪些问题、哪一个版本,一个最简单的方法是在你的镜像中用Git Commit作为镜像tag一部分,便于追踪,保证你线上的产品清楚地知道运行什么版本。 · 不要把任何可变数据保存在镜像中,要通过Volume抽象,可以把应用变化的部分跟您容器的生命周期进行良好的结合,它带来的好处远远大于懒、省事带来的好处。 跨主机容器网络 云端实践在网上大家看到很多关于Docker网络的很多讨论,大部分讨论是基于自己的数据中心,因为在自己的数据中心很简单,你甚至可以控制交换机。 但是在公有云上这件事很难,我们要选择在云上Docker容器互联的话,一定是按照云厂商的配置最大的优化去适配。 通常在云上有两种方案可以实现跨虚拟机的容器网络之间的互联: · 通过Overlay的方法,只要三层是通的,通过Overlay实现虚拟网络。 Overlay这种方式是非常通用的方式,它可以在不同的网络环境使用,甚至跨不同的云供应商都可以使用。但是它也有弱点,它自身的性能是有限的。 我们在亚马逊、阿里云、IBM的云上都测过,通过Overlay容器互联性能和容器通过原生虚机之间通信,只有带宽的70%,也会增加20%-30%的延迟,对于网络性能敏感的人我们是非常不建议这样做的。 · 通过云供应商网络自身的网络特性,比如VPC,VPC和今天网络很大的不同,在VPC中我们可以控制一些IT分配、路由规则。 通过这种方式我们得到很多好处,因为在一个VSwitch之内整个二曾是通的,我们甚至可以不用Web技术,在相应的节点上配相应的路由表就可以实现容器之间互通。 但是在一个VSwitch要做的话要承担一个后果,当一个数据中心掉链的话应用就挂了。 一般生产上我们建议这样的做法,通过一个VRouter把你的应用部署在不同的VSwitch上,然后在 VRouter上配路由规则,这种方式很通用,无论是在亚马逊还是阿里云上,我们都采用这种方式。 它的好处,容器和容器之间通信的带宽,在阿里云和亚马逊上,大概带宽基本和原生的速度没有区别,但是时延会稍微多一点,可能会在10%左右。 所以,如果大家追求性能可能会考虑,当然它也是受限于在一个 VRouter上到底有多少条路由表的限制,最后限制到您的集群节点的最大规模。 大家都知道,世界上没有最好的方案,一定根据自己的情况挑选合适的方案 (易立原创)
|