容器对前端开发真的有用吗?答案是确定的。html
最初当我向公司的前端同窗「安利」容器技术的时候,不少人都会说:「容器?这不是用在后端的技术吗?我不懂啊,并且前端开发用不上吧。」前端
但其实,今天咱们讨论的「前端」已经不是传统意义上的「前端」, 首先体如今终端类型的多样性,好比 iOS,Android,小程序等;另外,伴随着 Node.js 等技术的兴起,前端开发的边界也在逐渐服务端延伸。来到大前端时代,如何以工程化、服务化和自动化的方式来进行应用开发,实现业务的持续迭代、高可用、高并发是每个成功的互联网产品不断探索的事情,而渐为成熟的容器技术大大提升了这个过程的效率。git
本文将结合马蜂窝容器化平台赋能前端应用构建的实践经验,介绍整个平台背后的设计和实现原理,取得的一些效果及问题的优化方案。chrome
通常来讲前端的开发流程是这样的:建立服务/项目 → 本地开发 → 开发环境测试 → 生产环境测试 → 生产灰度 → 上线。npm
基于容器化平台进行前端开发的优点在于,前端和后端彻底分离,咱们只须要关注前端的项目构建,而不须要和后端代码一块儿打包。每一个构建版本及每一个访问规则也都是独立的,一个版本构建失败并不影响其余版本的构建及访问。小程序
那么,容器和前端的结合点在哪里?容器的优点在前端应用研发的哪一个环节发生做用?咱们能够从开发、测试、生产这三个阶段分别来看。后端
容器消除了线上线下的环境差别,保证了应用生命周期的环境一致性标准化。而对于前端开发来讲,要完成的任务每每是完成内容的呈现和响应用户的输入,处理的是 HTML、JS、CSS 等静态资源,文件直接发送到客户端,不须要一个运行环境,这里好像用不上容器。浏览器
那 Build 的时候呢?毕竟不一样的项目是用不一样的 Node 版本在作构建,不一样的容器能够进入不一样的 Node 版本,这样就不会污染本机的 Node 环境。但其实没有容器,前端还能够用 NVM 去管理 Node 版本,切换起来很随意,也就是一两行命令就能搞定的事情。并且本地开发很方便,看起来真的没有必要用容器。缓存
能够说,容器自己并无帮助前端在开发阶段变得更加便利。所以若是对容器技术不熟悉,开发阶段没有必要非要用容器。服务器
过去咱们用虚拟机进行测试的一个常见的方案是,前端研发把本身的代码上传到虚拟机的一个目录下,QA 能够直接经过域名进行测试。但问题是,公司有不少的产品线,可能会存在不少项目同时提测的状况。虚拟机对系统资源的消耗比较大,数量有限,而且难扩容,影响测试效率。
若是使用容器化平台就不会出现这方面的担心。由于容器很是轻量,消耗低、启动快,能够迅速扩容,不用担忧不够用的问题。
容器的另外一个优点是它能够实现应用程序的版本控制。好比咱们在上线以后发现版本有问题须要回滚,这种状况不可避免,传统的作法是经过 Git 或者 SVN 回滚,一旦合入的代码想回退或者拆分就很难操做,并且从新部署也很耗时。
基于容器化的平台,咱们能够直接经过流控,把流量切到旧的版本上去,几须要几秒钟的时间,回滚效率大大提高。
再如,前端性能的一个重要指标是页面加载时间,若是出现首页白屏是很是破坏用户体验的,特别是在作活动的时候,咱们把几乎全部流量都引导到活动页,出现白屏会很是让人抓狂。找到运维排查以后发现有台服务器挂了,只能经过重启来解决。可是重启机器存在不少不肯定性,有可能这台机器就起不来了,这种状况很常见。
但若是运行在容器化平台上,一个容器就是一个进程,一台机器若是宕机,集群会快速从另一个节点把服务拉起,并且是秒级的,基本不用担忧用户的访问会出现问题。
总结来看,容器与虚拟机相比主要的优点体如今能够实现快速扩容、秒级回滚和稳定保活。所以容器化对于前端开发来讲,更重要的意义是可以保证服务的快速迭代,以及线上服务的稳定性。
经过上面的介绍,相信你们已经对容器技术为前端开发带来了哪些变化有了一些感觉。那么为了更好地应用这项技术,前端同窗也应该掌握一些容器的基础知识。
首先咱们来看容器究竟是什么,它为何轻量、高性能。经过下面这张图片,咱们能够将虚拟机和容器进行一个更加直观的对比:
虚拟机经过在物理服务器上层经过运行 Hypervisor 模拟硬件系统,来提高服务器的能力和容量。每一个虚拟机中有一个内核,运行着不一样的操做系统,启动以后会作进程管理、内存管理之类的事情。但对于前端应用的构建来讲,可能只是须要一个 Nginx 作静态服务器,这种场景下使用虚拟机就过重了。
容器之因此轻量,是由于容器没有 Hypervisor 层和内核层,每一个容器都共享宿主机的内核和系统调用。所以一个容器内包含的仅仅是一个程序运行所须要的最少文件,启动容器就是启动进程,对资源的开销更小,维护起来更简单。
这是你们在聊到容器技术的时候常常会提到的三个词,下面来讲下它们各自的概念以及之间的联系是什么。
镜像:能够简单理解为一层层文件系统的集合,或者说一些目录的集合。好比对于咱们的前端代码,最下面那层目录多是 Nginx 运行所须要的二进制,而后在上面再加一层目录是咱们的代码,好比说 index.html。这个镜像分层全部的分层生成之后,都是只读的,每一层文件不可修改。
容器:其实就是在上面的目录上再加一层目录。但它实际上是一个空目录,区别就在于容器最上面一层是可读可写的,也就是说容器 = 镜像 + 读写层。
好比我若是想修改以前的 index.html ,是经过把新的版本累加在以前的镜像上。也就是说生成容器之后,全部的变动都发生在顶层的镜像可写层,下面的这些层是不容许往里面写东西的,可是能够累加,就像堆积木同样,一直加上去,而原来的镜像不会被容器修改,这也是镜像能够被多个容器共享的缘由。
Docker:容器技术其实早就存在,Docker 是用来实现容器化技术的一种工具,也是目前业界最通用的一种方式,来帮咱们制做镜像,而后把镜像运行成为容器并管理起来。
介绍完简单的概念,咱们就和你们一块儿来看马蜂窝容器化平台的总体架构,咱们是如何为前端赋能,以及赋予什么样的能力。
咱们基于 Docker 和 Kubernetes 搭建了容器云平台,将应用的构建、部署、资源调度、应用管理等能力抽象出来,以服务的方式提供给研发人员,提高线上服务的稳定性和研发效率。下图从应用的角度出发,展现了前端应用在容器化平台的生命周期:
应用是容器云平台的基本操做对象。云平台一个很是大的好处是屏蔽了项目的类型,不分前端或后端。因而在应用的外壳下,无论是前端的代码,仍是后端的代码,均可以享受一样的服务。好比传统意义上应用在后端的限流、熔断、服务治理等能力同样能够赋予前端,使前端同窗聚焦在业务开发上,而不须要关注底层的实现。
这是应用中心的一个建立页面,只须要几步,一个应用就能够建立完成,而且托管到咱们的云平台上:
建立完应用以后就要开始构建版本。经过使用容器,咱们将应用程序、配置和依赖关系等打包成一个个代码镜像,而后去告诉线上服务器怎么让它们用容器化的方式运行起来。所以版本管理包含代码镜像和运行时配置两部份内容。
1. 代码镜像
咱们使用基于 Pipeline + Docker 的 Drone 做为 CI 工具,它很是灵活,容易扩展。Drone 的灵活性体如今 Pipeline 的配置上,能够经过设置 .drone.yml 文件的方式在项目中控制构建镜像的过程。
为了更好地支持公司级别的应用,咱们向镜像注入一些内部常常用到的包来构建一个通用的基础镜像。在构建的同时会作一些 CI,好比单元测试、漏洞检测等。
2. 运行时配置
运行时配置分红 Nginx 配置和部署运行时的配置两个部分
(1)Nginx 配置
Nginx 配置主要针对 Node 前端项目来讲。将 Nginx 配置开放给应用有这么几点好处:
前端同窗能够本身去配置 history 模式,不须要再去找服务端来配合。
自定义多个 location。在面对多页应用时,能够经过配置 Nginx 把请求转发到指定的入口文件,实现指定路由。
自定义 cache 缓存策略。缓存策略选择更灵活,提高用户体验,下降服务器处理请求的压力。
(2)部署运行配置
部署运行配置是要告诉系统平台要如何运行版本包。这里其实也就为后续部署到 Kubernetes KVM 宿主机等多种平台留好了扩展。
总结来看,在版本管理的部分咱们实现了如下几点能力:
配置文件驱动,一个应用多份灵活好扩展
Nginx 配置等开放给应用,遵循 DevOps 思想,高效赋能
标准化版本产物,一处构建,到处运行
接下来咱们须要把已经构建好的版本包部署到集群上去运行。
在线上可能会有许多台机器,V一、V二、V3 指的是各类版本。这个版本能够有多个实例。若是服务出现故障,咱们主要经过两种方式来保证稳定高活:
高效调度:经过 Kubernetes 调度器将指定运行的容器调度到资源知足要求、最合适的节点上去
多副本支撑:自动部署一个容器应用的多份副本,并持续监控。若是容器挂掉自动启动副本
结合咱们以前说到的主页白页的例子具体说明,咱们会在容器化平台上持续看管容器,若是服务挂了,就在迅速在别的节点上启动起来。这里须要注意的是,「多份」不只仅是说在两台机器上启动就叫多份,若是两台机器都在一个机柜上,甚至在一个机房里,那么启动多份也没有意义。
到这里,咱们已经把服务部署到线上,而且实现稳定运行。可是完成部署,不表明用户就能访问,也不表明就能访问到正确的版本,因此接下来就到服务治理的环节。
服务治理是一个比较大的概念,能够应用的场景也不少。它的其中一个内容是让用户访问到指定的一线上版本。
技术方案
首先介绍下实现原理:
咱们采用的是一个 支持 xds 协议的网关。当新的配置经过 xds 协议推送给网关时,它就会自动进行热更新、热重启,而后去适应新的配置。好比说开始网关指向的是 V1 版本,若是咱们如今但愿指向 V2 版本,只须要把最新的配置经过 xds 协议推送给网关,它就会应用新的配置,经过这种方式就能够将指定版本部署到线上。
推送这里咱们用的是 Pilot 组件,并针对推送速度进行了优化。Pilot 组件会不断监听数据,发现有变动后就会取出。
应用场景
针对这种设计,咱们主要将其应用在三个场景中:回滚、分流和 ABTest。
1. 回滚
所谓回滚其实就是流控,好比一开始网关指向的是 V2 版本:
若是发现有问题,我只须要给网关推送一个新的配置,它就能够指向以前那个版本,很是快速:
2. 分流
分流主要应用在文章开始说到的提测场景中。过去使用虚拟机,因为不一样的虚拟机有不一样的域名,前端同窗在测试的时候要么就是为了适配虚拟机去修改代码,要么就是须要测试同窗或者产品同窗本身去修改本身本机的 host,很是不方便。
而使用容器化的方式,如说如今默认访问的是 V2 版本,但咱们如今须要测试 V1 或 V3 版本,就能够推出一个配置给网关,告诉它说若是请求里面的 cookie 含有标识 V=V1,就把请求转发至 V1 版本;一样若是 cookie 包含 V=V3,就将请求转发到 V3, 全部的转发都在网关层完成。
为了使服务更易用,咱们提供了一个插件去自动识别云平台部署的服务和版本。QA 和 产品同窗在测试的时候,只须要点选版本就能够,系统会自动完成 cookie 注入。而后向服务端发送请求时,网关就会发现这个携带了某个版本的 cookie,自动完成转发:
3. ABTest
一样的原理,咱们能够经过配置指定用户的 UID,控制用户去访问 ABTest 中的不一样版本,这里支持的方式有不少,好比注入 cookie、不一样的 head 头、不一样的请求方式等等,很是灵活。
以上是服务治理的内容。总的来讲,咱们可以自动化部署访问规则,可能只须要前端同窗作一个 git-push tag 的操做,就已经打好版本并部署到开发环境甚至是生产环境,而整个过程对于平台的使用者来讲是无感知的:
自动化部署访问规则,完整 CI/CD
灵活的分流策略,带来秒级回滚,灰度,abtest 等功能
结合 chrome 插件,体验流畅
以上介绍了基于容器化云平台咱们能够为前端赋予哪些能力。通过一些时间的探索,目前咱们的流程已经比较通畅,但不可避免仍是会遇到一些问题。
这种状况对用户体验来讲很是糟糕。通过排查后咱们发现问题出如今为了作到高可用,咱们的网关配置了多个。
由于网关的转发配置是经过推送下发的,多个网关以前就会存在时间差。有的网关先收到新的推送,有的后收到。当用户的请求打到了其中一个网关拿到了一个 html,会告诉它应该访问哪一个 hash 的 js。但若是不巧的是 hash 的 js 却访问到了另一个网关,而后转发到另一个版本,也就是另一个容器,那么 hash 值确定就不同了,找不到对应的文件,致使 404。
这个问题不只云平台会存在,只要是分布式的部署方案均可能存在时差的问题。咱们的解决方案是让全部网关都链接到同一个 Pilot。由于网关的数量是有限的,这时配置的下发就是由一个组件去负责推送全部的网关,由于 xds 协议自己是基于 GRPC 实现的,是一个长链接的操做,因此速度很是快。当由一个节点去作推送,全部网关接收到配置的时差能够控制在在毫秒间,几乎没有影响。也就是 A 网关接收到新配置的同时,基本上 B 网关也已经接收到新配置,这时候全部请求不管打到哪一个网关,他们都会指向同一个版本,这个时候线上就不会再出现 404 的请求。
以前说到,咱们的灰度方案是应用插件作 cookie,理论上来讲只要 cookie 的配置正确,就能够转发到指定的版本上去。那么既然个人 html 已经没问题了,为何 js 还会出现 404?
排查后发现,由于 js 请求的时候有一个标签叫「匿名标签」,若是咱们在用 js 的时候打了匿名的标签,浏览器在发 js 请求时就不会携带任何身份的标识,网关就会认为访问到一个默认版本,也就是线上的版本,这个时候若是请求再到 V2 版本就会 404。
目前咱们构建镜像的方式主要是用 npm install 和 npm run build 两个命令。以后咱们会尽量去释放 Pipeline,包括基础镜像、Node 版本等,让前端同窗能够实现更多自定义的需求。
目前咱们构建镜像的方案没有很好地利用 Docker 的缓存机制,所以会影响构建的时间。咱们目前也在作优化,尽量减小甚至消灭大部分 npm install 的时间和 build 的时间。
目前咱们已经完成了一部分监控告警能力的建设,主要是由平台维护团队在使用,去监控 QPS 情况、服务是否稳定,有没有重启等,团队内部也会收到不少告警。但咱们认为这种报警其实更应该发送给服务的负责人,后面咱们慢慢要将这部分能力释放出来,而且不断完善和优化告警规则。
最后简单总结:
容器化以后到底给前端赋能了什么?
提升测试效率
服务更加稳定,运维高效
马蜂窝云平台如何进一步给前端赋能?
应用中心:一步上云,无差异享受云平台带来的服务
版本管理:实践 DevOps思想,赋能 Nginx 配置;配置驱动,灵活好扩展
部署管理:智能调度,稳定高活
服务治理:秒级回滚,秒级恢复,灰度访问,ABTest等众多功能
目前咱们在如何经过容器化的方式帮助前端完成应用研发有了必定的探索,而且经过云平台的方式上作到更进一步的赋能,但愿能带给你们一些技术思惟上的启发。
本文做者:周磊,马蜂窝旅游网基础平台服务化研发工程师。
(题图来源于网络)
关注马蜂窝技术,找到更多你想要的内容