wykkx
作者wykkx2018-07-27 12:04
系统架构师, 某基金公司

企业级应用容器化部署实践

字数 6860阅读 5873评论 0赞 9

前言

各位朋友大家好,今天和大家一起探讨下“企业级应用容器化部署实践”这个话题,本文的主要思路如下,首先将从很多人到现在还不是特别清晰的“容器与虚拟机的区别”开始讨论,这个话题说清楚之后,就涉及到了“容器平台如何选型”,接下来就是“容器平台部署的建议”,容器平台部署起来之后就要考虑“什么样的应用适合容器化部署”,这是步步衔接相扣的,最后再通过“应用容器化部署实践”需要注意的问题进一步总结。

容器与虚拟机的区别

容器与虚拟机的区别,网上的资源有很多,最常见的一个图,如图一所示:
gz03gm8g9jsk

gz03gm8g9jsk

这里我主要谈下我的理解,尽可能的是大家在网上没看到过的。这里我将从开发和运维的不同体感分别去进行两者区别的分析:
对于开发而言,使用虚拟机和使用物理机没有区别,还是需要将开发好的程序做成jar包或者war包,然后在虚拟机的中间上进行部署。当切换到容器的场景,你就不能给运维说“给我一个容器我来部署自己的程序”,这样的话会让运维小伙伴一脸懵逼。在容器的场景下,开发人员需要写dockerfile文件,通过dockerfile文件将自己程序需要运行的操作系统基础环境、环境参数和代码关联起来,然后通过dockerfile形成镜像,镜像在容器平台run起来之后应用服务也就拉起来了(这里还有可能应用起来了,但是不能正常提供服务,这个我们后续会提到)。从以上过程你可以发现,在使用虚拟机和使用容器进行应用部署的时候,开发所面临的工作是完全不同的。
对于运维而言,每个虚拟机是有独立的操作系统内核的,而在一台机器上的容器是共享该机器的操作系统内核的;每一台虚拟机有一个独立的ip地址,这点和物理机没有区别,容器由于使用架构的不同,可能运维人员并不太关心容器自身的ip,例如在k8s平台上运维人员关注的是pord的ip,甚至是service ip基本没有人会去关注容器自身的ip。如果是在swarm平台上,运维人员就需要关注容器的ip地址了。另外,目前的现状,很多私有云iaas平台创建出虚拟机后ip地址还需要人工配置(并不是平台做不到,一方面是这个模块收费问题,另一个方面是运维人员习惯问题),但是容器平台上,如果容器创建出来没有ip地址,那么这个容器平台在市场上将会死的很难看。
上面简单说了在开发和运维视角对容器和虚拟机认识的不同,其实在业界,很多人是坚持走容器的轻量化路线,他们坚持容器应该是很轻量的,可以随时的销毁和创建,其ip地址不应该成为不可变的容器标示,同时容器上面也不应该有状态的保存,这一点也是和虚拟机有很大的不同,虽然现实中我们很多情况还是要求容器的ip在容器销毁并重建后不可变,这也是理想向现实妥协的一个表现。

容器平台选型建议

市面上销售的商用容器平台有很多,但是基本都是基于swarm或者k8s进行封装的。下面简单谈一谈笔者认为选型容器平台时的一些建议。这里主要分为两类目标对象,一类是具备自研能力的公司,这类公司可以直接选择使用swarm或者k8s,也可以找一家已经对swarm或者k8s进行了一轮封装,提供了更丰富功能的商用产品,考虑到采购方具备的自研能力,那么就可以要求销售方连同平台代码一起销售,这样在筛选的时候除了考虑平台能力,还要考虑交付文档是否清晰,代码质量是否过关。另一类是没有自研能力的采购方,对于这类采购方而言,主要有以下两个方面问题需要考虑(图二):一是平台自身的功能是否满足自身需求,这块在评估的时候建议找具有容器相关工作经验的同事进行需求评估,这样可以避免一些坑;二是建议选择除了提供容器平台能力之外,还提供应用容器化改造指导的公司的产品,这样能够加速应用容器化在公司内部的落地。
p1r3mpy3d2dq

p1r3mpy3d2dq

这里我谈几点我认为在商用容器平台选型过程中需要注意的事项,这些注意事项无论是自研开源还是纯采购方案都是需要考虑的:

  1. 建议选用基于k8s的商用容器平台,因为随着这两年的发展,k8s基本成了容器平台的现实标准,swarm被docker公司收购后,一直没有起色;
  2. 要评估商用容器平台是否具有容器级别的io隔离能力,因为容器共享宿主机,并且部署密度比虚拟机大,如果某几个容器io负载较大,可能将整个物理机的io打满,从而影响其他容器;
  3. 容器平台能够支持cpu超卖比例的自定义设置,这样做的目的是为了充分利用cpu资源,一般建议生产环境设置1:2到1:3的超卖比,开发测试环境设置1:10左右的超卖比;
  4. 容器调度在哪台宿主机创建是可以进行互斥设置的,这样的功能是为了防止同样用途应用的容器都部署在同一台宿主机上,当宿主机故障时导致应用不可用;
  5. 可以设置容器独占cpu,对于一些重要的应用,我们有时希望承载这个应用的容器能够独占一个逻辑cpu,这样的好处是可以避免进程在不同的cpu上调度,从而降低线程cpu调度所需的时间;
  6. 容器支持cpu、内存和磁盘的热变配,这个看起来像是一个虚拟机的需求,但是在实际应用中,笔者发现这样的需求还是存在的,很多企业级的容器平台并没有做的很彻底,所以很多时候容器是作为一个轻量级的虚拟机存在的;
  7. 容器平台最好能够提供扁平的网络结构,即跨主机的容器间通信可以通过ip直接访问,而不是通过主机加端口映射的方式进行。主机加端口映射的方式一方面通信效率低,另一方面不符合我们管理的习惯,也不符合应用调用的习惯,开发和维护的成本都较高;
  8. 容器平台应该已经集成了ci/cd工具,可以直接与本地的svn或者git代码管理工具对接,在容器平台内部闭环的实现自动化发布部署的整个流程;
  9. 容器平台要提供对外操作的接口,这些接口一方面是供自动化运维场景使用的,来实现自动化运维的动作;另一方面是供其他平台调用,提供不同平台间的数据交互。

容器平台部署建议

容器平台部署的建议主要有以下几个方面(图三):
0z1l65jgho7vq

0z1l65jgho7vq

1.部署在物理机还是虚拟机上?目前商用容器平台在进行推广的过程中,一般都是支持部署在物理机和虚拟机上的,并且两者收费的价格也是不同的。在这个问题上,如果公司是刚开始使用容器化平台,规模不大(原先30-50台虚拟机化宿主机的规模),并且并没有计划在半年到一年内将容器化应用到生产环境,那么对于这样的情况,建议部署在虚拟机上即可。对于计划将容器用于生产环境,并且计划跑高io业务,网络延迟要求较高的场景,根据笔者经验,建议使用物理机,并且必须配置ssd盘,哪怕是sata接口的ssd盘也是可以,不然应用的延迟会很高,严重影响应用的使用;

2.容器的容灾要怎么做?虽然目前的商用容器平台都可以做到容器crash后自动创建新的容器,这个过程中应用还是会多多少少受一些影响,所以一般情况下我们还是不希望因为容器crash掉而对应用有太大影响。为了做到上述这点需要做以下几种容灾:机器级别的容灾,即同一个应用的互备容器不要部署在同一台机器上;机柜级别的容灾,同一个应用的互备容器不要部署在同一个机柜的机器上,要实现这一点其实很简单,只需要用到容器的标签和互斥能力就可以了;

3.网络隔离方案,传统行业和互联网行业有一个很大的不同在于传统行业的网络里有dmz区,而互联网基本是没有这个dmz区的,因此在部署容器平台时,就存在两种方案,一种是在dmz区和内网区部署两套容器集群,另外一种是为容器平台再开通一个网段,这个网段前面没有dmz区,使用容器部署的接入端和应用端都使用这同一个网段。这两种方式没有好坏之分,第一种方案看起来更安全,但是需要开通很多网络策略,网工需要辛苦一下了;第二种方案看起来没有那么安全,领导可能不放心,但是少了很多安全策略的开通,对于开发人员的友好性会好很多。如果实在要二选一的话,在技术方面笔者比较倾向于第二种方案,因为dmz区就真的安全吗?没有dmz区对外提供服务就一定不可以吗?这里相信很多人心里也有答案,第二种方案只要安全做的好,其带来的便捷性是第一种方案无法比拟的。

什么样的应用适合容器化部署

上面介绍了那么多容器平台方面的话题,下面开始重点介绍应用在容器部署方面的问题。那么问题来了,到底什么样的应用系统适合用于容器化部署呢?这个问题恐怕也是很多人关心的问题,下面我们来重点分析下:
一是自研的应用系统适合上容器化平台。
(1)因为自研的应用系统代码可控,自研系统的代码可以使用git或者svn进行管理,这样在写dockerfile的时候可以直接从git或者svn上获取代码,形成镜像;
(2)自研的应用项目由于代码可控那么我们可以按照运维规范指定使用的jdk或者中间件,而不需要引入过多个性化的中间件,这样在进行应用镜像分层开发和维护的时候也非常方便;
(3)目前很多企业都在使用双态模式,我们都知道在敏态模式下版本迭代速度非常快,经常是一周就2-3个版本,这样的场景就特别适合使用容器平台进行ci/cd的操作;
(4)自研系统代码可控就可以实现容器弹性扩容后自动挂载到负载均衡上,这也是实现容器云的基础;
(5)自研系统可以进行无状态改造,一旦应用都进行了无状态改造,那么容器弹性伸缩,随时创建和销毁的特性就可以得到更好的发挥。

二是重量级的中间件不适合容器化,这里的重量级中间件主要是指如weblogic、WebSphere、IBM MQ等,这些中间件功能丰富,但是安装配置复杂,资源占用率高,代码不开源,进行容器化改造困难较大(因为容器化改造最快推动的是互联网公司对开源中间件进行容器化,闭源产品需要闭源厂商对中间件进行容器化改造),这些都与容器轻量化的理念不符合。

三是oracle数据库也不适合容器化,这个原因和重量级中间件不适合的原因是一致的。

四是对数据持久化有强需求的应用,这类应用要具体问题具体分析。容器运行起来后,数据的读写都是在镜像最上层的读写层,读写层的问题是容器重启后读写层的数据就消失了,这种情况对有些应用是无法接受的。因此,面对这样的情况,要么进行应用改造,让应用程序不要强依赖本地存储,要么在前期进行容器平台选型时充分考察容器平台是否支持容器数据的持久化。

五是在传统行业里核心的应用系统不建议快速进行容器化改造。传统行业由于采用的是商用平台的方案,那么应用系统的稳定性就和这个商用平台的稳定性直接绑定。一旦出现平台级问题,采购方的运维人员和开发人员由于缺乏容器平台的运维经验,很可能不能快速定位和处理问题,从而影响核心应用。因此传统行业使用容器部署应用,建议的上容器顺序如图三所示:
oves4zqat7f4

oves4zqat7f4

稳妥起见每个阶段建议最少上2-3个应用并且运行3个月左右的时间。

应用容器化部署实践

应用容器化部署最佳实践,笔者从自己的实际经验出发,结合一线互联网公司在使用容器部署应用时一些好的做法,认为需要做到以下几个方面(图四):
7g3vuwar093t

7g3vuwar093t

1.版本管理
不要使用默认标签last。开发人员在分支开发完一个版本后,就基于此分支(或者先合并回主干,这个是由开发的代码管理方式决定的)生成一个版本的镜像,建议使用应用名称+日期+vn的格式,n是从1开始的整数,如果发布一次成功不需要fix,那么n的值就是1,如果需要fix,n的值就加1。这样每次完成一定的功能后都有一个固定的版本号,每个版本的特性也就可以很清晰的记录下来,便于版本管理和定版本发布。

2.CI/CD
CI/CD现在在传统行业使用的也很多了,其实主要还是在CI部分,CD这块还需要人工参与。很多公司不敢完全自动化CD主要是缺少四方面的能力,一是应用的健康检查能力,CD自动化需要时刻关注新上或者变更应用的服务是否正常,如果缺乏这方面的能力就如同闭眼开车;二是灰度发布能力,通过灰度的方式可以将新版本通过引流进行预热;三是与监控系统联动的熔断或者回滚机制,即如果监控发现新上或者变更的应用出现问题,应该能够快速熔断路由到这个节点的访问并选择进行回滚;四是应用间的强依赖,如果A应用依赖B应用,那么如果B应用做变更不可用,A应用是一定会受到影响的。要解决这个问题,那么B应用要进行灰度发布,同时A应用在对B应用有感知能力,当对B1进行变更时,A的请求被路由到B2,当对B2进行变更时,再将A的请求路由到B1。接下来讨论下为什么应用容器化必须要Ci/CD,其实原因很简单,在快速扩容的场景中,基础资源快速弹出以后,应用程序要部署在上面才能提供服务,快速扩容就必须自动化,人工操作是不能忍受的。在使用容器平台时,由于在开发阶段到上线阶段基本就是维护一个dockerfile(也就是有些环境变量会有不同),所以对于运维同学而言工作量小了很多,同时由于镜像屏蔽了底层差异,因此能避免出现很多基础环境不同导致的问题,结合ci/cd工具和自动挂载到负载均衡就可以实现应用在容器平台的快速扩容。

3.监控问题
监控是个老生常谈的问题,从传统的集中式系统就开始讲监控,一直讲到容器和微服务的监控。从目前的主流视角看,应用包括物理资源监控、操作系统监控、数据库监控、中间件监控、应用监控、业务监控。随着IT技术的发展,一是各个监控层次里的组件的监控项增多(例如数据库指标增加、中间件的种类增加),二是从原先的注重每个模块的监控开始转变为从用户视角注重整个业务体验(响应时间/吞吐量/成功率等)的监控,三是在容器和微服务架构下,还需要监控每个方法的耗时以及对每次请求的全链路跟踪。监控在实际使用中,需要关注误报的问题,报警参数调整问题,不同业务报警特征的问题,层级依赖造成的报警收敛问题(底层的交换机故障,依赖这个底层交换机的物理机、虚拟机、应用程序都会引发报警),报警的处理响应机制(这里比较建议使用on call的机制,相比于每个负责几个应用系统的方式,on call的方式一方面对大家的应急能力有更好的锻炼,另一方面也能使大家对所有的应用都熟悉)。
在应用容器化的场景下,监控就显得更加重要了,相比于传统的烟囱式架构,完成一项业务流程需要涉及多个容器(容器和微服务改造一般都是同时发生的),而且这些容器又可能是新增或者有发生扩容的。那么当一笔业务发生问题的时候,需要快速定位是哪个节点出了问题,这就需要分布式链路跟踪上场了。在容器大量使用的场景下,监控就是眼睛,在应用进行上线、变更和弹性扩容的时候需要实时感知应用的健康状态,主要包括可用率(正常情况这个指标需要是100%)、响应时间等,以便采取相应的措施来保证不影响用户体验。在云平台上,应用变更(包括版本更新和扩容)的正确姿势应该是一边做变更,一边看监控大盘,看每个动作对当前应用可用率的影响,看着监控做变更是一种好习惯。

4.状态管理
笔者在前面也稍微提到了一些状态管理的内容,笔者认为在容器平台上状态管理的好坏对能否充分使用好容器平台的很多特性也是非常重要的。在互联网领域有一句话叫做,“以无状态为荣,以有状态为耻”,但是目前在传统企业应用还是以有状态应用为主。应用的状态是阻止应用弹性伸缩以及用户端高可用体验的拦路虎,这里所说的状态信息,更多的是指原先记录在会话session中的信息和定时任务执行的状态信息。目前常见的情况是用户的session信息存储在java中间件所在主机的内存里,需要依赖前端负载均衡设备通过设置基于源地址哈希来保证同一个用户请求能够发送到同一台后端服务器上从而在保证状态。有状态应用存在的问题有:一是基于源地址哈希容易导致的问题就是由于每个请求的在线时间不同负载很容易不均衡;二是在进行版本迭代升级的时候,这个节点上如果有状态信息就会被清除,给用户的感受就是被踢出登录了或者访问的信息消失了。
如果要做无状态的改造,有两种思路,一种是通过在业务逻辑上的优化,真正的去掉原来记录在session的中的信息,这种方式改造的很完全,但是难度大,并且适用范围比较小;另外一种方式就是将原来由各个业务节点保存的session信息,集中地保存在session服务上,这样就变相的去掉了业务的状态信息,请求到达的时候,就可以从session服务中获取session信息,实现了业务逻辑与session保存的解耦,从而可以使业务模块能够快速的弹性扩容和缩容。同时session服务一般都是分布式部署,自身提供了良好的高可用机制以及分布式部署特性,在多机房或者多云环境下可以部署在多机房或者多云,从而保证session数据的安全可靠。同时认证模块如果使用token的方式,那么可以将用户的session id放在token里面,从而解决认证和session id安全两方面的问题。做了应用程序的状态管理工作后,在进行应用弹性缩容和扩容的时候,由于状态信息是统一管理的,不落在具体的java容器中才能够提供更良好的用户体验。

总结

本文从容器与虚拟机的区别,聊到容器平台选型和部署,最后到应用容器化部署的实践,谈到的内容都是笔者自己在容器领域工作过程中积累的经验和坑的总结,里面一定还有很多不完善或者考虑欠妥当的地方,欢迎各位读者批评指正,共同交流进步。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

9

添加新评论0 条评论

Ctrl+Enter 发表

本文隶属于专栏

最佳实践
不同的领域,都有先行者,实践者,用他们的最佳实践来加速更多企业的建设项目落地。

作者其他文章

相关文章

相关问题

相关资料

X社区推广