掌握教育自动化构建流程业内前端构建一般分为三种:手动触发构建:这个阶段非常原始,需要我们在本地进行gitpull/npminstall/npmrunbuild等操作也容易出问题;分布式构建虚拟机Jenkins集群:通过Master,分配任务给相应的Slave机器执行构建,可以极大的平衡资源和利用性能。同时解放双手;容器集群构建:容器构建和镜像发布,进一步节省资源;但是在2019年之前,硕士教育的前端研发都是在本地搭建,然后通过运维脚本跑起来的。它也容易出现生产故障。于是我们收集反馈,结合实际情况,开发了v1.0构建模式,取得了很好的效果。但没想到自己就可以因此高枕无忧,继续优化了很多痛点,最终迭代了v2.0方案。在此过程中,前端业务不断壮大,CI建设在400多个应用、每周2000+构建、300+生产发布后持续增长。v1.0面临的挑战v1.0前端构建状态,一是通过webhook触发pipeline构建,二是通过在cd上新建buildorder来触发构建。如果施工任务较多,单用一台机器是远远不够的。这种情况就需要使用Jenkins的Master/Slave主从模式来解决服务器的资源压力。让Master服务器调度资源,指定空闲的Slave机器进行建设。当Slave机器上的构建任务满了,构建任务会继续在Master队列池中等待,待Slave机器空闲后再分配。现有挑战v1.0并不是最好的解决方案,同时暴露出首次构建速度慢、错误日志反馈不清晰等问题,还有一点就是作业维护困难。要解决这些问题,您需要重新开始并重新设计。首先,工作维护困难。v1.0的任务模式是多个应用对应一个作业,这会导致几个问题。如果job发布了,版本挂了,会影响到所有。如果作业需要复用,也很难进行定制化开发。其次,第一次构建慢的问题更多是资源调度和Workspace无法复用。按照前面的资源调度方式,当我们给机器A分配了一个任务,并且任务执行成功了,那么下一个任务也会被导入到这台机器A中。通过这个观察,你会发现大部分任务都会优先执行抢占机器A。这导致了几个问题:资源调度不平衡;npm缓存越来越大;最后,无法复用Workspace模式。在v1.0的情况下,不复用Workspace模式会带来以下好处:保证node_module没有污染问题,也避免了npmrunbuild中node_module包污染导致的各种意外错误。所以在v2.0中,我们需要处理污染问题。同时,还需要考虑复用Workspace后如何最大化利用其特性,比如从node_module缓存,跳过npminstall等。v2.0优化方案的资源调度需要优化先进行资源调度,然后需要重新设计,将一组机器分成多个分片组,每个分片组有不同的调度顺序。当应用触发构建时,分配对应的key值:1AppNodeKey=AppId%nodes然后根据划分的key,找到对应的机器组,比如[0,1,2,3,4],构建任务找到机器号0,寻找对应AppId的Workspace目录地址执行构建任务,如果任务被占用(默认2个任务,可以优化资源,不会被大量任务抢占),它会寻找下一台机器,这样Machine资源调度就会平衡。构建jobpipeline,我们对不同的项目进行了模板化,比如PC项目,H5项目,游戏项目,混合项目等,我们在模板的基础上,对它们进行了封装和打包。pipeline模板的好处是我们可以做一些针对各类项目模板进行针对性的配置优化。例如,对于我们的游戏类型项目,我们将构建并打包它们。可以依赖对应开发组件库中的这一块做一些相应的缓存、通知、上报等。流水线化也带来了一些好处:首先,我们将构建任务,gitcone,npminstall,npmbuild进行了生命周期,将所有这些阶段拆解,使整个任务过程变得细粒度,这样的好处是我们可以在每个粒子之间找到优化空间,比如是否可以不执行npminstall,比如上传产品仓库的逻辑优化等等。第二,可以指定DSL,我们可以实时监控打包和排队情况,在资源调度层面做一些优化。同时可以做一些埋点,为后续的深入分析收集数据。第三,我们甚至可以在构建和打包过程中做一些交互相关的操作。比如我们打包一个h5的项目,需要测试学生复习。测试审核通过后才能进行下一步。下一道工序可能是UAT打包、生产打包等。四、对于项目依赖拉取,一开始我们做的是全量拉取,现在可以优化成增量拉取,这样对服务器的压力会减少很多错误管理,无论是本地还是Building在cd平台上也容易出现各种意外错误。比如开发中的疏忽,管道的gitcommit未经验证提交代码,在npmrunbuild或者npminstall的两个阶段可能会报不同的错误,所以需要对日志提示集进行分类,分为两种:warning类型:无package-lock.json提示,不影响任务构建;错误类型:导致job任务退出,如依赖包未找到等;4我们进行了npminstall、npmrunbuild,观察每一个构建阶段,失败可以归纳为4种触发警告或者错误类型:语法错误:代码冲突...程序异常:内存溢出...安装失败:未找到安装包...配置错误:构建未遵循标准化输出...按照“观察日志-沉淀规则-修正反馈准确率”规则沉淀日志规则。npminstall在复用Workspace的情况下会跳过已经安装好的node_modules,所以不需要重复npminstall两次,只有在依赖发生变化的时候才需要考虑re-npmisntall。同时也容易产生问题,node_modules污染,我们采取了多种方法来防止node_modules被污染。定期检查缓存;切换node版本时,执行npmrebuild重新编译一些需要在gc++环境下构建的包,比如node-sass;CD页面增加手动清理Workspace的选项;目前的好处是,相比之前的v1.0方案,我们实现了整体构建速度20%+的提升,这对我们团队也是一个很大的正向激励,说明我们之前的努力方向是对的的。迁移过程是从v1.0到v2.0。需要考虑如何进行平滑的迁移。我们迁移基于以下几点:1:每个应用创建一个独立的v2.0Job任务,方便快速修改和排查问题;2:页面支持快速回退到v1.0;3:选择gitcommit,node版本等信息不变,没感觉;概括的架构不是设计出来的,而是演化出来的。未来的建设任务可能会越来越多,项目也会越来越复杂。我们会根据实际情况考虑容器化方案,容器构建,镜像发布,尽可能节省资源。
