当前位置: 首页 > 后端技术 > PHP

好未来学而思网校是如何在1小时内发布一个新项目的?

时间:2023-03-30 03:49:33 PHP

背景在互联网高速迭代的浪潮下,相信每一位研发人员都经历过需求研发、测试、验收,新项目的部署上线,功能迭代,甚至项目下线的全过程。其中,“需求开发”、“测试验收”、“功能迭代”、“项目下线”等环节,研发人员基本可以有效把控,也是项目整个生命周期中投入最多的环节.几个环节,所以可以提前预估一个合理的时间计划。在这些关键环节中,上线部署项目往往是最后一个环节。对于项目组成员和需求方来说,软件开发完成后,要投入生产环境是水到渠成的事情,需要马上完成。但是在网校的背景下,一个新的项目要放到生产环境中是一件很严肃的事情。其实需要经过几个环节:新域名备案(准备必要材料)服务器申请(机房选择、单机硬件配置、系统选择、网段规划、机器命名、容量预估)服务器制作(必要软件初装、参数校对)研发授权(准备dev或guest人员名单,准备批量授权机器标签)发布系统(创建发布项目,填写机器信息,项目人员分工)配置网关(集群选择、vhost配置、上游配置)域名解析(是否经过全站加速/高防等防护产品,提供解析地址生效)如果容量估计不够,youneedtoreGothrough#2~#6(多批生产机器有隐患不一致的环境配置)。如果项目下线,域名往往容易被忽略,导致一些无用的域名被备案,不好管理。整个过程最快也是以天为单位,生产次日送达;慢的话需要好几天才能完成生产环境的部署,需要跨多个部门协同完成。在2020年公益直播高峰前夕,通过“连轴”完成服务拓展的伙伴们尤为难忘。因此,为解决新项目部署周期长的问题,基建部启动了《域名收敛》和《容器平台》两个项目。《域名收敛》项目主要是缩短#1、#7、#9这三个环节消耗的时间和精力。《容器平台》项目主要是缩短#2、#3、#4、#5、#6、#8这6个环节消耗的时间和精力。而现在这两个项目已经无缝集成,在同一个平台上完成。下面将详细介绍我们是如何推动开发完成的新项目在一小时内上线,实现小时交付生产,以及目前的项目应用规模。容器平台物理机和虚拟机时代,整个新业务上线过程严重依赖机房资源、运维部署、多系统环境配置、性能压力测试。长流程资源申请流程->资源采购->机器授权->服务运行环境配置(环境、网络)->配置发布系统->配置网关/日志->性能压测当硬件资源不足时,需要排队购买从审批到资源上架的初始流程可能需要几个月的时间,漫长的处理过程大大挫伤了开发者的积极性。当资源充足时,这个过程可能需要几天时间。我们需要解决这些长期的流程问题。在互联网时代,敏捷决定了企业的生死存亡。我们如何实现便利?通过容器的环境一致性,统一调度网校云的硬件资源,使我们能够有效盘活有效的固定资产池。通过打通网关和日志系统,每位研发老师都可以自己完成所有配置。应用快速发布是由gitdevops的设计驱动的。用户只需要提供git仓库的地址和项目的域名即可。平台将调用流水线引擎构建镜像。通过配置基于git事件的触发器,自动构建镜像,然后创建deployment、service、Ingresskubernets等应用和资源。流水线操作设计,一次完成应用发布和镜像构建。应用部署完成后,我们将集群的网关入口地址提交给网关,触发网关的上游更新操作,从而实现服务发现和分发。同时与公司的发布系统对接。用户发布应用后,可以获得一个hook地址。发布系统设置钩子后,会在发布时启动k8s的滚动升级,从而实现混合部署应用的同步升级。云原生PIPELINE引擎gitlab事件触发器充分借鉴了K8S自带的CI/CD系统Prow的系统设计,实现gitlab的自动事件通知支持:Tag事件Push事件Merge事件引擎注册并监听相关事件,当事件到达,根据事件类型,将事件分发给对应的插件进行处理。实现了与网校云容器平台的无缝对接,通过简单的web配置即可构建基于指定Tag或指定Commit的镜像。引擎完全运行在容器之上,多种插件和PIPELIE灵活多变的设计使得应用的发布不局限于特定的运行和构建环境,有利于新项目、新环境的快速发布和迭代.弹性扩展是基于集群应用程序的自动弹性扩展,基于水平Pod自动扩展器。metricsserver根据CPU使用率指标,从kubelet中的cAdvisor组件获取cpu资源消耗。默认情况下,它每10秒采样一次,每30秒计算一次CPU使用率。当业务高峰到来,监控到pod的CPU使用率超过预定阈值时,会自动增加服务的副本数(在设定范围内),否则会减少副本数以释放集群资源,从而实现集群资源的高效利用。自动日志收集我们使用filebeat作为日志收集工具。filebeat以daemonset模式运行,确保每个节点都有一个filebeat容器在运行。filbeat容器可以收集宿主机和宿主机上其他容器的日志。您可以在我们的容器平台上选择需要采集日志的应用来完成日志采集。通过configMap(配置中心),对采集配置进行管理。由于我们打通了网校的日志中心,所以我们收集的所有日志都会收集到kafka中,然后落地到日志中心的ES集群中。域名收敛1.为什么要收敛域名?随着网校用户的快速发展,业务越来越多样化和复杂化,服务之间的耦合度越来越高,依赖严重,相互影响。为了减少依赖,每个项目都希望有一个独立的域名来提供服务,而业务方也开始频繁申请新的域名,这使得网校对外暴露的域名越来越多。这种做法逐渐造成了网校域名的泛滥。据不完全统计,截至2019年年中,网校已申请上千个域名,并以每周数十个的速度递增。其中,通过网关的域名数量已超过1000个,很多域名已经无人认领,没有人敢确认这些服务是否在线运行,所以不敢轻易修改或下线。此外,域名的泛滥也给网校的研发和运维带来了诸多痛点:研发人员:上线困难:域名申请、域名备案、域名解析、网关创建申请、vhost,upstream,application端机后,后端nginx+fpm配置,release代码。周期长(1周到1个月),流程冗长,效率极低。研发人员在项目启动上花费了大量精力。开发难点:无论是app、H5、web还是其他客户端,开发都需要适配不同域名的不同界面。代码臃肿,难以维护。单个应用依赖的接口覆盖了近百个域名,开发者已经应接不暇。运维人员:管理维护:上千个域名难以维护和管理。配置难:运维对接各种开发配置需求,导致网关层配置不规范,复杂冗长,修改频繁,错误率高,风险大。安全问题:暴露过多的域名会降低系统的安全性。大量的域名需要备案审核和安全扫描,也暴露出很多安全漏洞。2020年2月网校公益直播期间,由网校技术委员会发起的“竞品分析”项目对多项技术测评指标进行了分析。其中,在服务器端的域名管控方面,我们的实现远远落后于对手。网校的研发和运维人员还没有形成域名融合的意识,不仅没有制定相关规范文件,更没有相应的技术手段实现域名复用。针对以上痛点,网校服务器技术委员会、运维团队、群安全团队联合推出《网校域名收敛专项》。该项目的目的是解决在线学校域名激增的问题。一方面,需要对现有域名进行收敛和规范。另一方面,调整优化后续新上线项目流程,加快推进项目上线流??程自动化、标准化,为网校云建设铺路。2.如何实现域名融合2.1域名规划那么如何实现域名融合呢?首先我们对网校的服务进行大致的划分和分类,大致如下:根据服务类型:WEB服务和API服务,前者输出html,后者输出json数据。按服务范围分类:内部服务和外部服务,前者只提供内网或办公区服务,后者提供公网服务。这样就有四种服务:外部WEB、内部WEB、外部API、内部API。因此,我们设计了四个对应的域名:app.xueersi.com;app.xesv5.com;api.xueersi.com;api.xesv5.com;这四个域名的作用如下。app.xueersi.com:主要作为外部WEB应用的代理,面向公网用户,如网站首页。app.xesv5.com:主要作为内部WEB应用的代理,面向内部用户,如admin管理后台、各种监控平台、告警平台等内部系统。api.xueersi.com:主要代理对外的API服务,如app、ios、PC端调用的API服务,以及阿里云、微信等第三方回调API。api.xesv5.com:主要代理内部api服务,比如用户数据等中端api接口。2.2方案制定2.2.1服务标注根据网校站点架构的特点,几乎所有的服务都由统一的Nginx网关进行反向代理。一个域名对应一个vhost和upstream,通过Nginx的proxy_pass进行路由转发。为了实现域名收敛,我们决定在网关层进行技术改造,实现基于收敛域名的动态路由分发。所谓收敛域名是指上述四个专用域名app.xueersi.com、app.xesv5.com、api.xueersi.com、api.xesv5.com,除特殊情况外,尽量允许所有服务重用这四个汇聚域名(也称为网关的专用“代理域名”)。如果每个人共享同一个域名,如何识别不同的服务?很简单,根据url来识别,我们将url中第一个'/'后面的字段作为每个item的标签,网关层会根据这个“标签”来识别不同的服务,比如一个new在线学习应用,想使用study.xueersi.com,业务方可以使用“study”作为项目标签,同时复用域名app.xueersi.com,当用户访问http://app.xueersi.com/study/...,网关会通过Rewritehost、upstream、uri实现如下转发规则:Rewriteupstream:从proxy_passhttp://app.xueersi.com改写为proxy_passhttp://study.xueersi.comRewritehost:Rewritefromapp.xueersi.comtostudy.xueersi.comrewriteuri:from/study/course/getInfo?a=1to/course/getInfo?a=1这时候,对于后台服务,用户请求http://app.xueersi.com/study/...,经过网关转换后,后台收到的真实请求为:http://study.xueersi.com/cour。..西米larly,其他服务类似,复用同一个域名,独占一个Label。2.2.2简化上线流程服务打标签后,服务的暴露形式由“域名”依赖转化为“标签”依赖,因此对于研发人员来说,域名申请、域名等步骤解析和网关创建vhost被省略。以部署在kvm中的服务为例,上线过程简化如下:开发只需要做两件事:域名备案:立项到上线随时备份(安全方面几乎没有要求)部门、公网域名必须备案,不得使用私网域名)。创建上游:通过网关后台创建。对于接入网校云的服务,依托k8s容器运行环境,上线速度会更快。网关已经和k8s连接上了。你只需要在k8s上创建一个应用,选择对应的网关集群即可。一键即可启动新项目。2.3技术实现从以上技术方案不难看出,实现的重点在于网关需要根据url对每个以汇聚域名开头的请求进行切割,提取请求的“标签”,并同时重写请求的host和upstreamuri,所以在gateway层我们开发了dyroute插件来实现上述功能。插件不仅支持host、url、header、body、ip、referer、cookie等十几种过滤条件,还支持url的多段切分提取,可自定义host、upstream,和uri根据需要。三、问题及解决方案理想很丰满,现实却很骨感。在真正推动域名融合的过程中,我们遇到了很多棘手的问题,这里主要记录一下。3.1根据网关的转换规则,路径池会存在漏洞。以app.xueersi.com为例,如果有人请求app.xueersi.com/A,会间接访问A.xueersi.com,访问app.xueersi.com/B会访问B.xueersi.com,即他可以随意尝试访问我们的不合理服务。你可能会问,app.xueersi.com最初不是用来代理公网服务的吗?测试成功也没关系,本来就是给公网用户的。网校域名有个“不成文”的规定,就是.xueersi.com是外部的,.xesv5.com是内部的。但是由于历史原因,很多域名并不遵守这套规则,比如oa.xueersi.com应该是一个内部OA系统,但是它使用了.xueersi.com这个外部域名。如果用户通过app.xueersi.com/oa发送请求,他们可以无障碍地访问我们的内部系统。同理,原本对外使用.xesv5.com的服务也会出现类似的问题。为了解决这个问题,我们设计了路径池机制。每个汇聚域名都需要绑定一个路径池。我们在创建upstream的时候会在路径池中加入相应的label。只有添加到相应路径池的url才能正常工作。通过网关,其他随机的/A、/B、/C请求都会被网关拦截。3.2日志切割以app.xueersi.com为例,在网关上配置一个对应的vhost。当有请求到来时,Nginx会匹配这个vhost,即所有连接到这个域名的服务都会共享这个vhost。虚拟主机有日志文件问题。如果后面这个域名接入了上百个服务,那么这上百个服务的访问日志都会记录在app.xueersi.com_access.log这个文件中,这必然会造成单个日志文件过大的问题也会给ELK搜索带来麻烦,导致用户很难找到自己服务对应的日志。为了解决这个问题,我们采用了一种“可变”的日志方式,即“access_log/home/nginx/logs/app.xueersi.com_{host}_access.log”,当访问app.xueersi.com的请求到达时,网关层将识别标签信息并据此改写主机。到了Nginx的log阶段,会识别当前的host变量,决定将log写到哪个log文件。xueersi.com/B会写入app.xueersi.com_B_access_log。3.3CookieExplosion当多个服务共享同一个域名时,另一个棘手的问题是cookie。如果服务器都在app.xueersi.com设置了cookie,首先,不同的cookiekey可能会重复,其次,如果没有标准化,后面很可能会超过浏览器的最大cookie长度限制。为了解决这个问题,我们从两个方面着手。一方面,设计了cookie管理系统。后台服务若要在app.xueersi.com设置cookie,必须向管理系统申请。如果已经申请过cookie,则不允许重复申请。每个cookie对应的服务信息将记录在管理系统中。另一方面修改了dyroute插件。在向客户端发送响应之前,会对cookie进行校验,不属于域名的cookie会被拦截。3.4跨域跨域问题也是个头疼的问题。根据群安全群反馈,这些融合域名会存在跨域风险,需要进行跨域限制。但是有的服务希望能够在网关层统一处理跨域请求,有的服务希望后端自己处理跨域请求,有的服务希望后端自己处理跨域请求,一些人希望任何来源都可以跨域访问,而另一些人则不希望。希望只能通过'http_origin'访问,甚至可能有商家希望自定义添加allowheader。一个域名虚拟主机很难涵盖所有需求。我们跟业务方和安全组讨论了一个折中方案,就是所有访问域名汇聚的服务都在网关层进行跨域处理,网关会允许组内的域名可以互相访问,比如,'.xesv5.com、.xueersi.com、.100tal.com'之间的跨域访问没有限制,而外部域名将被阻止。另外,我们在allowheader中加入了浏览器可识别的commonheader,并设置了其他变量供业务方选择作为自定义字段。3.5双活接入域融合服务部分服务需要双活服务,但是这些域名解析到21VianetIDC,不能满足双活要求,所以我们将这些域名的公网解析移到了By默认会直接转发到21Vianet。如果有业务需要转发到阿里云,会根据预先设置的路由规则转发到阿里云。其实摆在我们面前的问题远不止这些,比如前端js动态配置问题、网关插件执行顺序问题、多环境、多业务部门域名收敛规划、多协议支持问题,访问全站加速问题,静态资源cdn缓存问题等等。而且,阻力也很大。不是每个人都愿意接受这件事,尤其是一些老服务。有阻力。推动全网校各部门前端、后端、运维、群保、项目负责人制定一套网校级域名融合规范,同时推进这套历史经验给了整个集团。经过半年的努力,我们也取得了一些小成绩。不仅在网校落地了一套域名融合规范,而且以网关和容器为核心,在网校云平台上成功落地,融合域名总数也突破了500大关。.我们相信,既然确定是对的,我们就会继续努力。解决烦恼最好的办法就是不怕烦恼,总有一天会看到结果的。作者简介陈超飞好未来资深PHP/Golang开发专家