在过去的一年或者2年,我们谈了太多的容器技术,尤其是Docker,目前,Docker 和以其为代表的容器技术的热度已经改过了之前的 OpenStack。Adrian Cockroft将微服务架构与Docker容器的结合视为一种“颠覆”。原因十分明显:当与容器结合使用时,微服务架构所具备的优势将被进一步放大。本系列文章将探讨当微服务遇到Docker会碰出怎样的火花。
构建微服务之开源技术Docker
Docker 以及其所代表的容器技术的流行,即使因为软件技术的进步,更是由于其符合云计算对软件领域所带来新思想。在如今的互联网和企业应用开发领域,微服务和 DevOps 是两个思想颇为深入人心。而 Docker 技术的出现和其对整个容器技术及其生态圈发展的促进,解决了微服务和 DevOps 这两个思想实践中的很多难题,使得前面两种思想大规模地实现成为了可能。所以,我们有必要地深入了解一下 Docker 这个技术,看看它会对云计算时代的软件开发产生什么样的影响。
在 Docker 出现之前,不仅 Google 大量使用容器技术,国内的如淘宝也使用容器技术搭建了自己的应用平台。影响力最大的开源 PaaS 解决方案 CloudFoundry,也在使用自己的容器解决方案 Warden。而 Docker 发布之后,因其极有可能成为未来企业应用、互联网应用和云计算应用的开发、部署的中心角色,所以得到了几乎所有的业界大佬的追捧,Google、VMware、微软、RedHat 等等都已全力推动 Docker 技术的发展。同时,围绕 Docker,出现了一系列以 CoreOS 为代表的新技术。
Docker 的出现并非创造了一个新的容器技术,而是在 LXC (LinuX Container)注1、cgroups、namespaces 技术之上所构建的一种技术:
Docker 简化了容器的运行:它通过一个简单的命令就能够运行起一个容器docker run [params] [image] [command (optional)]
Docker 简化了容器镜像的构建和分发:Docker 提供了Dockerfile和docker commit两种方式构建镜像,并且提供了 Docker image registry 机制以保存和分发镜像
关于构建微服务的开源技术Docker,详情请点回复1,点击完整PDF文档。
实施微服务需要哪些技术框架
和单块(Monolithic)架构不同,微服务架构是由一系列职责单一的细粒度服务构成的分布式网状结构,服务之间通过轻量机制进行通信,这时候必然引入一个服务注册发现问题,也就是说服务提供方要注册通告服务地址,服务的调用方要能发现目标服务,同时服务提供方一般以集群方式提供服务,也就引入了负载均衡和健康检查问题。根据负载均衡LB所在位置的不同,目前主要的服务注册、发现和负载均衡方案有三种:
第一种是集中式LB方案,如下图1,在服务消费者和服务提供者之间有一个独立的LB,LB通常是专门的硬件设备如F5,或者基于软件如LVS,HAproxy等实现。LB上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向LB发起请求,由LB以某种策略(比如Round-Robin)做负载均衡后将请求转发到目标服务。LB一般具备健康检查能力,能自动摘除不健康的服务实例。服务消费方如何发现LB呢?通常的做法是通过DNS,运维人员为服务配置一个DNS域名,这个域名指向LB。
[图1]集中式LB方案
集中式LB方案实现简单,在LB上也容易做集中式的访问控制,这一方案目前还是业界主流。集中式LB的主要问题是单点问题,所有服务调用流量都经过LB,当服务数量和调用量大的时候,LB容易成为瓶颈,且一旦LB发生故障对整个系统的影响是灾难性的。另外,LB在服务消费方和服务提供方之间增加了一跳(hop),有一定性能开销。
关于实施微服务需要哪些技术框架的全部内容,请回复2,阅读完整PDF文档
使用容器技术来建立一个微服务架构
Linux容器技术的使用可以很大程度上缓解微服务架构所带来的问题。Linux容器技术使用了类似cnames和namespaces这样的内核接口,它允许不同容器共享相同的内核,同时容器之间还进行了完全的隔离。Docker执行环境使用了一个被称为libcontainer的模块,它标准化了这些接口。Docker同样为容器镜像提供了一个类GitHub的资源库DockerHub,让容器的共享和发布非常简单,也正是这种相同主机上的容器隔离简易了不同语言开发的微服务代码部署。使用Docker,我们可以创建一个DockerFile来描述所有用到的语言、框架和服务间库的依赖性。举个例子,下面代码中的DockerFile可以用来定义一个微服务的Docker镜像,它使用了Ruby和Sinatra框架:
代码语言:javascript复制FROM ubuntu:14.04
MAINTAINER John Doe <jdoe@example.com>
RUN apt-get update && apt-get install -y curl wget default-jre git
RUN adduser --home /home/sinatra --disabled-password --gecos ''
sinatra
RUN adduser sinatra sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER sinatra
RUN curl -sSL https://get.rvm.io | bash -s stable
RUN /bin/bash -l -c "source /home/sinatra/.rvm/scripts/rvm"
RUN /bin/bash -l -c "rvm install 2.1.2"
RUN /bin/bash -l -c "gem install sinatra"
RUN /bin/bash -l -c "gem install thin"
使用这个镜像建立的容器可以便捷地被部署到一个主机上,这个主机同时还运行了另一个使用Java和DropWizard 定义的Docker镜像所建立的容器。容器执行缓解隔离了主机上运行的不同容器,因此不存在使用不同语言、库和框架容器所造成的冲突问题。
同时值得高兴的是,近期发布的Amazon EC2 Container Service(Amazon ECS)可以帮你搞定所有这些工作。使用Amazon ECS,你可以定义一个被称为“cluster”的计算资源池,一个cluster由一个或以上的EC2实例组成。Amazon ECS负责管理集群中所有基于容器的应用程序,提供 telemetry和logging,并管理集群的容量优化,进行高效的任务调度。Amazon ECS提供了一个“任务内容(task definition)”的理念,它可以定义组成一个应用程序的一组容器。task definition中的每个容器都指定了该容器所需的资源,而Amazon ECS将基于集群中的可用资源来调度这个任务的执行。
如何使用容器技术来建立一个微服务架构,回复2,查看完整PDF文档
在Docker上运行微服务
Container是基于内核的空间。一个操作系统的内核主要管理资源,把服务器交给操作系统的内核,它把内存、CPU和硬盘等资源管理起来。Container进一步做隔离,这个隔离以进程为单位,让一个进程只能看到这个网卡收发的数据,但是看不到其他的网卡。
Container有以下几个名字空间。
- 网络的空间,它隔离了和网络相关的资源,如服务器上的网卡、IP地址、服务表等,之后这个进程在某个网络的空间内运行就看不到其他空间相关的网络资源。
- 文件系统,这个名字空间把这类资源也进行了隔离。一个进程运行时看到的根目录可能不是操作系统原生的根目录,看到的块设备也不是原来的块设备。
- PID,每运行一个进程都有一个PID,现在内核里的名字空间,PID的资源也被隔离起来。
Container对系统调用做了权限的控制。例如一个进程启动的时候限制它的权限,让很多系统调用做不了。Container的作用包括镜像管理和运行实例的管理,还有输入输出的管理。
那么,Container对服务端架构有什么影响呢?很重要的工作是模块化,去定义这个模块的边界,怎么工作、怎么测试及在生产环境如何部署。因此,从组件的角度看微服务化主要有以下三点。
- 组件划分的方式,Container以功能为单位来划分组件的边界。
- 组件物理边界,以前的边界有静态或动态的库,模块间的边界通常是函数调用。而微服务组件的物理边界是网络,这些组件都是独立的、可编译的进程(即每个单独的服务实例),这些服务实例之间通过网络来沟通。
- 组件的依赖方式,以前是在编译期考虑怎么才能把可执行程序编译出来,只要编译出来,就能肯定依赖关系肯定被解决了。当微服务化之后,依赖方式的处理被延后了,延后到运行的时候,因此错误被延后了,组件间的依赖方式变复杂了。Container中组件间的依赖可通过渲染文件和环境变量等实现。
关于Docker上运行微服务请回复4,查看完整PDF文档
再谈Docker-微服务的场景化应用
在Docker出现之前,虽然我们谈论微服务架构,但是其实是很难实现的。微服务要运行,首先需要一套执行的环境。这套环境不能对外部有依赖性。同时,执行环境的粒度又必须足够的小,这样才能称之为”微“,否则必然是对资源的巨大浪费。一个微服务可以跑在一台虚拟机上面,但是虚拟机粒度太大,即使最小的虚拟机,也至少也有1个核。正如我们上面的ghost博客的例子,服务一个用户的服务,显然用不了一个核。同时,虚拟机有没有一套方便的管理机制,能够快速的让这些服务之间能够组合和重构。Docker出现以后,我们看到了微服务的一个非常完美的运行环境。
- 独立性:一个容器就是一个完整的执行环境,不依赖外部任何的东西。
- 细粒度: 一台物理机器可以同时运行成百上千个容器。其计算粒度足够的小。
- 快速创建和销毁: 容器可以在秒级进行创建和销毁,非常适合服务的快速构建和重组。
- 完善的管理工具: 数量众多的容器编排管理工具,能够快速的实现 服务的组合和调度。
除了Docker生态系统之内的一些工具,包括Serf之类的服务自发现技术的发展,可以让微服务能够自动化的感知其关联的其他服务,实现系统的自我构建。我记得2014年早些时候,centurylinklabs里面有一篇文章,讲述了如何通过FIG,Serf,HAProxy构建一个自动负载均衡的Docker应用。其实,这篇文章所蕴含的思想,就是一种微服务架构的概念。
关于“再谈Docker-微服务的场景化应用”详情,请回复5,查看完整PDF文档。
微服务革命:容器化的应用、数据及其它一切
在DockerCon Europe 2014大会上,Adrian Cockroft将微服务架构与Docker容器的结合视为一种“颠覆”。原因十分明显:当与容器结合使用时,微服务架构所具备的优势将被进一步放大。微服务鼓励软件开发者将整个软件解耦为较小的功能片段,并且这些功能片段能够应对外界的故障,这为我们带来了敏捷性和适应性。而Docker将我们的软件从底层的硬件中进行解耦,这为我们带来了在基于虚拟机的解决方案中见所未见的可移植性与速度。
如何处理状态?
虽然对微服务与Docker容器的关注在2014年得到了爆炸式的增长,但它的发展面临着一个重大障碍,为了理解这一点,我们需要仔细分析,通常所说的无状态应用程序设计具体是指什么。
无状态的应用程序设计
微服务架构的创建者倾向于在任何可能的情况下使用无状态的服务、而不是有状态的服务。无状态应用程序设计的主要优点在于:它能够平稳地应对为服务添加或移除某些实例的场景,而无需对应用程序进行重大的变更或进行配置的改动。比方说,如果服务的负载产生了突发性的增长,可以为服务加入更多无状态的web服务器,而如果某个无状态的服务器挂机了,也可以方便地用另外一台服务器取代它。因此,无状态的服务更容易实现敏捷性和适应性。
有状态的服务
尽管无状态的应用程序设计是大势所趋,但在许多系统中,状态是不可避免的。比方说,任何需要保存数据的系统都必须对状态进行管理,而且有状态的工具在数量和种类上都在不断增长,例如MongoDB、PostgreSQL、RabbitMQ、Redis、Cassandra、Riak、MySQL和ElasticSearch等等。现代软件开发者所用到的数据服务在不断增长。随着微服务架构逐渐成为规范,开发者和架构师开始在应用程序的不同地方使用不同类型的数据服务。要解析几十亿的日志信息?用ElasticSearch。要处理工作队列?用Redis或是RabbitMQ。客户的注册信息呢?那就用MySQL或MongoDB。以上这些场景完全有可能同时出现在某个应用程序中。