写点什么

在 Docker 上运行微服务

  • 2015-06-19
  • 本文字数:4917 字

    阅读完需:约 16 分钟

在过去的两年里,微服务架构已经成了非常热门的名词,它出现在很多论坛、视频、演讲中。作为一种更灵活、可靠、开放的架构,其应用实践也越来越多。近日,来自七牛云存储、DaoCloud、京东、ThoughtWorks 的架构师们分别就微服务架构实践、容器技术带来的技术价值、微服务面临的挑战和解决目标等方面的经验做了交流分享。

微服务大探险

软件架构是在考虑业务、技术能力、团队、可维护性、安全性、可靠性及可持续性等多重因素下对软件内部进行的划分。通过划分,让软件内部不同的部分之间能够相互独立,又能够相互协作,同时给用户提供最终的价值。但什么是微服务架构呢?ThoughtWorks 首席咨询师王磊通过一个互联网门户案例为大家解释了微服务架构的概念,以及它如何影响传统的软件架构设计。

一年前,该门户每签一个 10 万的合同所耗费的成本是 3.5 天。他们当时的 CRM 结构是典型的三层架构,整个应用程序由一个 40 万行的代码库组成,后端有一个主动的数据库。虽然使用三层架构的成本比较小,但随着代码和功能的增加,代码库不断膨胀,修改代码存在的风险很大,整个维护成本也变得越来越高。

每当开发人员提交代码后,所需的数据集成和构建需要 50 分钟,意味着每天 8 小时工作时间最多能有 9 次代码提交。但为了系统的稳定性,持续集成过程中要尽量避免提交代码,因此,整个团队的交付能力受到了限制。此外,从准备部署包到上线需要3天,3天后才能让用户真正用到部署包,才能实现价值。而如果增加新人,要开发新的环境,包括测试和产品环境,培养周期会很长。针对以上难题,必须制定如何在团队中对系统进行改造从而满足业务需求的策略。

  • 将现有的系统保护起来,把所有开发新功能的优先级都降下来,只对系统做最紧急的修改,其他和部门进行协商,让团队保持新的精力和时间在重要的业务上。
  • 功能剥离。通过定义新服务,在前端用一些代码的机制让用户逐渐访问新服务,可以达到从原有系统抽出小功能,让客户访问小功能。
  • 数据解耦。对于庞大的系统,因为无法很快将所有系统换掉,所以为了保证系统仍然可用,要启用数据同步机制,让服务里的数据同步到原有数据库。
  • 渐进替换。通过不断地运行以上策略,将原有系统的复杂功能抽离出来用新的方式来做。

目前,每签一个 10 万的合同所耗费的成本由 3.5 天变为 1 天,持续集成构建从 50 钟降低到 18 分钟,团队成员从 10 人降到 7 人,部署周期由 3 天降到 2 小时。

对于每个应用程序,可能有一组小的服务组成,每个服务运行在自己的进程中,服务与服务之间通过轻量级的机制进行交互。那么,如何使用微服务做系统改造呢?

  • 为每个服务建立独立的环境,包括基础设施、持续集成环境、运维、监控、日志聚合、报警。
  • 不断演进的微服务开发模板,发现问题及时修改,让模板更高效。
  • 轻量级的通信协议。
  • 消费者的契约测试,解决随着服务增多带来集成测试效率低的问题。
  • 基础设施自管理,帮助管理自己需要的资源。

Container**** 为微服务带来了什么?

七牛云 CTO 韩拓从服务端的架构和运维两个方面介绍了 Container 和微服务带来的价值。他认为 Container 是基于内核的空间。一个操作系统的内核主要管理资源,把服务器交给操作系统的内核,它把内存、CPU 和硬盘等资源管理起来。Container 进一步做隔离,这个隔离以进程为单位,让一个进程只能看到这个网卡收发的数据,但是看不到其他的网卡。

Container 有以下几个名字空间。

  • 网络的空间,它隔离了和网络相关的资源,如服务器上的网卡、IP 地址、服务表等,之后这个进程在某个网络的空间内运行就看不到其他空间相关的网络资源。
  • 文件系统,这个名字空间把这类资源也进行了隔离。一个进程运行时看到的根目录可能不是操作系统原生的根目录,看到的块设备也不是原来的块设备。
  • PID,每运行一个进程都有一个 PID,现在内核里的名字空间,PID 的资源也被隔离起来。

Container 对系统调用做了权限的控制。例如一个进程启动的时候限制它的权限,让很多系统调用做不了。Container 的作用包括镜像管理和运行实例的管理,还有输入输出的管理。

那么,Container 对服务端架构有什么影响呢?韩拓认为不管做什么架构,很重要的工作是模块化,去定义这个模块的边界,怎么工作、怎么测试及在生产环境如何部署。因此,从组件的角度看微服务化主要有以下三点。

  • 组件划分的方式,Container 以功能为单位来划分组件的边界。
  • 组件物理边界,以前的边界有静态或动态的库,模块间的边界通常是函数调用。而微服务组件的物理边界是网络,这些组件都是独立的、可编译的进程(即每个单独的服务实例),这些服务实例之间通过网络来沟通。
  • 组件的依赖方式,以前是在编译期考虑怎么才能把可执行程序编译出来,只要编译出来,就能肯定依赖关系肯定被解决了。当微服务化之后,依赖方式的处理被延后了,延后到运行的时候,因此错误被延后了,组件间的依赖方式变复杂了。Container 中组件间的依赖可通过渲染文件和环境变量等实现。

关于 Container 对运维的影响,主要是告别 DevOps。作为 DevOps 实践者,韩拓认为,DevOps 的核心是试图寻找一个合理的开发和运维的边界。有很多方法论寻找这个边界,DevOps 是其中一种,主要将运维平台化,做监控平台、日志平台等。

在持续集成方面,以前的任何一行代码做了更变都要把整个业务重新做一遍,需要很长时间。微服务化之后,每个模块独立编译、独立打包、独立测试,其边界也很明确,代码的变更影响的是一个组件和服务,单独进行编译和测试的动作会很快。

部署和升级方面变得简单,可以独立地部署和升级。

资源规划方面,按峰值申请资源会存在资源浪费。微服务化后,可以按模块去扩容。对资源的规划更灵活和合理。尤其再结合 Container,因为 Container 以进程为单位,它对资源的使用是竞争的,不需要提前规划。

网络方面,Container 一般通过端口映射的方式做网络。

监控方面,业务的运行状态对运维来讲更透明,小的服务可以单独监控,一些问题出来之后可以做报警。但监控变多了,需要监控系统更智能。

最后在高可用方面,传统的架构会做成透明的。现在,高可用由外部的框架完成,例如在做服务间依赖时就可以做高可用,不仅屏蔽了服务在哪里,服务了多少人,而且还可以把服务是死是活的细节屏蔽掉。

Micro Service,Continuous Delivery and Docker

DaoCloud 联合创始人 & 研发副总裁郭峰认为容器技术解决了原来 PaaS 技术不能解决的问题。于是他给大家展示了微服务带来的挑战,即如果将一个应用微服务化,那么很容易导致一台机器上跑很多程序。因为服务纠缠在一起,所以微服务需要运用自包含。DaoCloud 的容器技术是把最古老的几个技术融合在一起,用了一个很方便的脚本化的工具,让大家都可以用起来。它提供了标准化的镜像,不仅方便地用容器,而且可以方便地发布容器。

容器和虚拟机是什么关系呢?虚拟机有物理环境、有操作系统,但容器下面是 server,上面跑应用程序和库,这样的架构使得容器的性能比虚拟机好很多。首先没有虚拟机的虚拟化过程,直接把跑内核的进程跑到 OS 上。别人想发一个微服务,可以利用在镜像上面加一层,即使有很多镜像,有时多个镜像会一起依赖,会省资源和容量。那么,为什么容器是轻量级的?因为它只有应用和应用的依赖所打成的包,如果应用做了一点点修改,不需要完全打一个,在原有的应用上打一个补丁,把修改记下来即可。

上图是 Docker 的流程图, Dockerfile 这个镜像可以运行在本机。在上面运行容器,等容器开发好并且测试通过了再把这个容器 push 到镜像仓库上。任何一个人都可以从镜像仓库上下载,下载后,Docker 运行一套命令让行为一致。重要的是,Docker 官方维护了 DockerHA,所以 Docker 允许以镜像的方式发布 Container,发布的 Container 像未来的 VM,这个 VM 很轻量,大家可以把它 pull 下来,不管用什么物理硬件资源,都可以让 Docker 运行起来,而且运行结果和其他没有差别。Docker 是如何做到自包含的呢? Docker 的自包含是它容器的本身包括了 OS 的版本,以及依赖的环境和客户,所有的都描述成 Dockerfile。Docker 可以帮助两类人——开发人员和运维人员,它跨越了开发和运维间的那道鸿沟。

仅仅自包含就做微服务是不够的,微服务要求把之前大系统的问题分解为很多简单的小问题,然后将每个简单的小问题用最合适的技术实现。但这导致现在有很多小应用,原来靠人工可以解决的事现在解决不了,比如做 CI(持续集成)/CD(持续交付)。微服务化以后,会导致一个企业的应用 CI 很难做。

此外,他还向大家介绍了 Docker 的三件法宝。第一个是 Docker Compose,如果应用不是单应用可以用同一方法描述应用和应用的依赖,然后上线。第二个是 Volumes,可以共享文件。最后一个是环境变量,不管是微服务和微服务之间的依赖以及微服务运行时的依赖的环境变量也好,还是端口也好,都描述清楚,定义好后给运维人员。这是可复制的迭加过程,不仅把代码和运行做自包含变成一个镜像,而且镜像用运行的方式提供出来。运维人员不需要关心应用内部的逻辑,只需要关心模块的镜像以及如何将镜像运行起来,这样可以大大地减少运维成本。

Docker**** 的应用与实践

来自京东的资深架构师季锡强分享了 Docker 的应用与实践。主要讲了 Docker 的系统整体架构及其技术实现、镜像存储部分、Container 启动流程,还介绍了制作镜像命令的原理以及 volume 挂载的原理。

他为大家介绍了 Docker 的组件,Docker 真正的实现主要是几个组件组成,第一层是镜像存储的模块,实现有很多种,比如 device mapper、aufs 以及 btrfs。第二层是 exec driver,主要是 libcontainer 及 lxc。第三层是 network driver,主要是主机以及网络命名空间,而 Namespace 支持 ipc、mnt、pid、net、uts 及 user。组件 CGroup 主要做资源控制,涉及的方面有 CPU、IO,IO 可以不依赖于 Namespace 单独使用,和操作文件一样改一下值就可以。CGroup 的限制主要是通过子系统来实现,相应的模块有 IO、CPU 等。而组件 Device Mapper 的实现有 DM - thin provision。

上图是启动容器的流程。启动的命令请求首先会把设备 mount 到指定的挂载点上访问。启动 go monitor 会带着参数启动里面的命令,接下来会用 Dockerinit 做初始化,最终命令会进行系统调用,再 exec 执行。停止容器则比较粗暴,相当于 Docker 根据 PID 直接将容器中的进程杀掉,再做一些资源的释放,这样就完成了停止容器的流程。Docker 启动的时候,如果 Docker 是意外死掉的(人为或者程序的破坏),那么之前的程序不会消失,这时候 Docker 会把所有的容器 kill 掉,会把之前容器创建的操作信息保存在 Docker 的目录下。Docker 将所有的容器都 kill 掉后,资源会被释放,这个时候就会触发一个永久性的 bug。因为当容器重启的时候,会检查 mount count,这个初始化的值是 0,而 Docker 死掉后重启则会发现 mount count 不为 0,所以会导致 mount 失败,导致出错;这个时候我们想启动容器的话,关键的动作是把设备释放并重新挂载到 mount 下。因此,告诫大家,如果 Docker 异常死掉了,要及时清理资源。

关于制作镜像的原理,你可以建立一个镜像生成一个容器,这个镜像可以分到某一个文件目录下,可以做一些直接的操作。首先 mount 上去,镜像原来的版本也会 mount 上去,遍历所有的文件看两者之间的状态是否有变化,然后打包,产生 diff。这时要创建新的容器,因为已经获得了 diff,接下来要创建一个新的镜像。创建新的镜像之前要拿到 Container 的基本镜像,这时要把这个镜像 mount,就可以看到所有的文件。最后的操作是解压一个文件到一个新的 snapshot,就相当于有一个新的镜像了。

最后,他对 Docker 做了一些总结,Docker 主要用到 CGroup 的一部分子系统;Docker 启动和停止之间有一个大 Bug 需要及时关注;commit 要打包、解压文件,机器磁盘很高的时候 commit 会相当耗时。

注:「开发者最佳实践日」是由七牛云存储发起并联合各方小伙伴为开发者举办的系列技术沙龙,关注开发者在实际应用中可能遇到的技术问题。


感谢魏星对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-06-19 06:5513151

评论

发布
暂无评论
发现更多内容

京东云智臻链开源两周年,JD Chain领跑国内自研区块链技术

京东科技开发者

区块链

【LeetCode】删除有序数组中的重复项 IIJava题解

Albert

算法 LeetCode 4月日更

Ubuntu 鼠标手势软件 -- EasyStroke

TroyLiu

Linux ubuntu 效率 快捷键 鼠标手势

尤雨溪:Vue 3 将不会支持 IE11 了

清秋

翻译 Vue 4月日更 IE

IDEA实用快捷建

华血

MVVP:一种基于状态的架构模式的设计与实现

行者

「免费开源」基于Vue和Quasar的crudapi前端SPA项目实战—环境搭建 (一)

crudapi

Vue nodejs crudapi quasar SPA

“智慧旅游”:区块链能否驾驭文旅行业?

电微13828808271

智慧公安

SARIF在应用过程中对深层次需求的实现

华为云开发者联盟

DevSecOps 元数据 SARIF 软件安全 规则

字节跳动上亿级别秒杀系统优化,用这个方案可行吗?

Java架构师迁哥

私有依赖的打包与上传

blueju

JavaScript 大前端 npm

MySQL-技术专题-Lock入门到精通

码界西柚

MySQL lock

低代码平台选型的道与术

人称T客

Elasticsearch入门,看完又要会!慎点

比伯

Java 架构 面试 程序人生 架构师

「架构实战营」作业#1

高亮

Baas是什么?区块链Baas平台开发解决方案带你知晓

源中瑞-龙先生

区块链 开发 解决方案 Baas

图尔兹与达梦数据库达成全面战略合作,共筑国产数据库新生态

BinTools图尔兹

数据库 数据安全 操作数据库

【架构实战营】第1模块作业

swordman

架构实战营

“区块链+电子证照”,推动数字化经济建设

电微13828808271

区块链+ #区块链#

站在巨人的肩膀上!淘宝网Java千亿级并发系统架构设计笔记

Java架构追梦

Java 架构 亿级并发 淘宝网

Thrift 学习笔记

U2647

Thrift 4月日更

Pod 的状态

耳东@Erdong

容器 4月日更

在微前端中,antd icon createFormIconfontCN 的本地化问题

blueju

大前端 antd umijs

WordPress中常用的8个函数

Sakura

4月日更

我,第一次做项目经理,干赔了

四猿外

你的Parquet该升级了:IOException: totalValueCount==0问题定位之旅

华为云开发者联盟

sql spark ETL任务 Parquet totalValueCount

生活中的这些难题,数据库开发者可为你解决!

华为云开发者联盟

数据库 开发者 华为云 GaussDB(for Redis) Redis Stream

浅谈一个优秀的 Android SDK 需要具备哪些要点

神策技术社区

android 数据采集 sdk 神策数据

架构实战训练营

Nick~毓

物联网设备天线设计与选型指南

不脱发的程序猿

物联网 4月日更 物联网设备天线 天线设计与选型指南 射频

辽宁重点人员管控系统搭建,指挥调度系统搭建

在Docker上运行微服务_ThoughtWorks_杨爽_InfoQ精选文章