共计 7262 个字符,预计需要花费 19 分钟才能阅读完成。
背景
在互联网高速迭代的浪潮下,置信每位研发人员都经验过新我的项目的需要研发、测试验收、部署上线、性能迭代、甚至我的项目下线的全过程。其中“需要研发”、“测试验收”、“性能迭代”、“我的项目下线”这类环节对于研发人员来说,基本上能够无效的把控,在整个我的项目的生命周期内,也是投入最多的几个环节,因而能够提前预估出正当的工夫打算。
这几个要害的环节中,将我的项目部署上线,往往是最初一个环节。对我的项目组成员和需求方来说,软件研发实现当前,投入生产环境,是一个瓜熟蒂落的事件,须要立马实现。
然而在网校大背景下,一个新我的项目投入到生产环境是一个十分庄重的事件,实际上须要经验的几个环节如下:
- 新域名备案(筹备必要的材料)
- 服务器申请(机房抉择、单机硬件配置、零碎选型、网段布局、机器命名、容量预估)
- 服务器生产(必要软件初装、参数校对)
- 研发受权(筹备 dev or guest 人员名单、筹备机器标签进行批量受权)
- 投入公布零碎(创立公布我的项目、填充机器信息、我的项目人员分工)
- 配置网关(集群抉择、vhost 配置、upstream 配置)
- 域名解析(是否通过全站减速 / 高防等防护产品、提供解析地址失效)
- 若是容量预估有余,还须要再经验一遍 #2~#6(多批生产的机器存在环境配置不统一的隐患)
- 如果遇到我的项目下线,往往域名又被容易疏忽掉,造成一些无用且曾经备案的域名,不易治理
整个过程最快也要以天为单位,隔天交付生产;慢的话要数天能力实现生产环境的部署,并且须要跨多个部门协同实现。2020 年公益直播顶峰前夕,“连轴转”实现服务扩容的搭档,尤其铭心刻骨。
因而,为了解决新我的项目部署周期长的问题,基础架构部启动了两个我的项目:《域名收敛》、《容器平台》。
《域名收敛》我的项目,次要为了缩短:#1、#7、#9 这 3 个环节上耗费的工夫和精力。
《容器平台》我的项目,次要为了缩短:#2、#3、#4、#5、#6、#8 这 6 个环节上耗费的工夫和精力。
并且当初两个我的项目曾经无缝联合,在同一个平台上实现。
上面将具体的介绍,咱们如何给开发实现的新我的项目,在 1 小时内公布上线提供便当,实现小时级交付生产,以及以后的我的项目利用规模。
容器平台
物理机与虚拟机时代整个新服务上线流程重大依赖机房资源、运维部署、多个零碎的环境配置、以及性能压测。
漫长的解决流程
资源申请流程 -〉 资源洽购 -〉 机器受权 -〉 服务运行环境配置(环境、网络)-〉 配置公布零碎 -〉 配置网关 / 日志 -〉 性能压测
硬件资源有余时,须要排队洽购审批,到资源上架初始化过程可能长达数月,漫长的解决流程十分打击开发人员的激情。
在资源短缺的时候,也须要数天的解决流程。咱们须要去解决这些漫长的流程的问题,在互联网时代敏捷性决定了业务的生与死。
咱们是如何做到便捷性的呢?
- 通过容器的环境一致性
- 网校云的对立调度硬件资源使咱们能无效盘活无效固定资产池
- 通过买通网关、日志体系,每位研发老师齐全自助的实现所有配置。
利用疾速公布
驱动于 git devops 的设计,用户只须要提供 git 仓库地址及我的项目域名,平台会调用 pipeline 引擎构建镜像,通过配置基于 git 事件的触发全自动构建镜像,而后依照模板创立 deployment,service, 及 ingress 的 kubernets 等利用及资源。流水线作业设计,零打碎敲实现利用公布与镜像构建。
与网关进行了自动化买通,利用部署实现后咱们将集群的网关 ingress 的地址提交给网关,触发网关的 upstream 更新操作,从而实现了服务的发现以分流。
同时与公司公布零碎进行买通,在用户公布完利用后,能够取得一个 hook 地址,公布零碎设置 hook 后,在公布的时候登程 k8s 的滚动降级,以实现混合部署利用的同步降级。
云原生的 PIPELINE 引擎
gitlab 事件触发充沛借鉴了 K8S 自带的 CI/CD 零碎 Prow 的零碎设计,实现 gitlab 的主动事件告诉反对:
- Tag 事件
- Push 事件
- Merge 事件
引擎通过向注册相干事件并监听,当事件到来时会依据事件类型散发事件给相应的插件来解决。曾经实现了和网校云容器平台的无缝连贯,通过在简略的 web 配置就能够构建出基于指定 Tag 或指定 Commit 的镜像。
引擎齐全运行在容器之上,多插件和 PIPELIE、灵便多变的设计让利用的公布不会拘泥于特定的运行与构建环境,助力新我的项目的新环境的疾速公布于迭代。
弹性扩容
以基于 horizontal pod autoscalers 实现的 集群利用的主动弹性伸缩,依据 CPU 使用量指标,metrics server 从 kubelet 中的 cAdvisor 组件中获取 cpu 的资源耗费,默认状况下,每 10s 采样一次,每 30s 计算一次 cpu 使用量。当业务顶峰降临,监控到 pod 的 CPU 占用量超过预约的阈值,会主动减少服务的正本数量(在设定范畴),反之会减小正本数量,开释集群资源,由此实现集群资源的高效利用。
自动化日志收集
咱们采纳了 filebeat 作为日志采集工具。
- filebeat 以 daemon set 模式运行,保障了每个节点都会有一个 filebeat 容器运行。
- filbeat 容器能够采集宿主机以及该宿主机上其余容器的日志。
- 能够在咱们的容器平台,抉择须要收集日志的利用,即可实现日志采集。
- 通过 configMap(配置核心)的形式,对采集配置进行治理
因为咱们曾经和网校的日志核心买通,咱们所采集的日志将均被采集到 kafka 中,而后落地到日志核心 ES 集群。
域名收敛
一、为什么要做域名收敛
随着网校用户体量飞速发展,业务越来越多样化,复杂化,各服务之间的耦合度也越来越高,依赖重大,相互影响。为了加重依赖,各我的项目都心愿有独立域名来提供服务,业务方也开始频繁申请新域名,使网校对外裸露的域名越来越多。这种做法逐步造成了网校域名泛滥景象。据不齐全统计,截止 2019 年年中,网校申请的域名有数千个,而且以每周数十的速率增长,其中通过网关的域名就曾经破千,而且很多域名曾经处于无人认领的状态,没有人敢确认这些服务是否在线上 running,因而也不敢轻易去批改或下线。除此之外,域名的泛滥成灾也给网校的研发与运维带来了很多痛点问题:
- 研发人员:
- 上线艰难: 域名申请、域名备案、域名解析、网关创立利用、vhost、upstream、申请后端机器、后端 nginx+fpm 配置、公布代码。周期长(1 周~1 月),流程简短,效率极低,研发人员将大量精力消耗在我的项目上线上。
- 开发艰难:无论是 app、H5、web 等客户端,开发须要适配不同域名的不同接口,代码臃肿,难以保护,单 app 端依赖的接口就有涵盖了近百域名,开发人员曾经不堪重负。
- 运维人员:
- 治理保护:上千的域名保护治理艰难,只增不减,很多域名没有访问量,无人保护,无人认领。
- 配置艰难:运维对接各种开发配置需要,造成网关层配置毫无标准,简单简短,频繁批改,出错率高,风险性大。
- 平安问题:裸露域名过多升高了零碎的安全性,大量域名须要备案审计、平安扫描,也暴露出了很多安全漏洞。
2020 年 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 中第一个’/’ 前面的字段作为每个我的项目的标签, 网关层会依据 ” 标签 ” 辨认不同服务 ,比方新上线一个学习利用,想应用 study.xueersi.com, 则业务方能够拿 ”study” 作为我的项目标签,同时复用 app.xueersi.com 这个域名,当用户拜访 http://app.xueersi.com/study/…,网关会通过改写 host,upstream,uri 来实现以下转发规定:
- 改写 upstream:从 proxy_pass http://app.xueersi.com 改写成 proxy_pass http://study.xueersi.com
- 改写 host:从 app.xueersi.com 改写成 study.xueersi.com
- 改写 uri : 从 /study/course/getInfo?a=1 改写成 /course/getInfo?a=1
此时对于后端服务来说,用户申请的是 http://app.xueersi.com/study/…,通过网关转化后,后端真正接管到的申请为:http://study.xueersi.com/cour…
同理,其余服务也是相似,复用同一域名,独占一个标签。
2.2.2 上线流程简化
在服务标签化之后,服务的裸露模式就从‘域名’依赖转换成了‘标签’依赖,那么对于研发人员则省去了域名申请,域名解析,网关创立 vhost 等步骤,以部署在 kvm 的服务为例,上线流程简化为:
其中开发须要做的只有两件事件:
- 域名备案:从立项到上线之间任意工夫备份即可 (安全部门硬性要求,公网域名必须备案,私网域名能够不必)。
- 创立 upstream: 通过网关后盾创立即可。
对于接入了网校云的服务,依赖于 k8s 的容器运行环境,这种服务的上线会更快,网关曾经和 k8s 进行了买通,只须要在 k8s 上进行利用创立,抉择好对应的网关集群,一键切流即可上线一个新我的项目。
2.3 技术实现
从上述的技术计划中不难看出,实现的关键点在于网关须要对每一个以收敛域名打头的申请,依照 url 进行切割,提取进去申请的 ” 标签 ”,同时改写申请的 host、upstream、uri,于是在网关层咱们开发了 dyroute 插件实现了上述性能。该插件不仅反对 host,url,header,body,ip,referer,cookie 等十几种筛选条件,也反对 URL 的多段宰割和提取,能够按需对 host、upstream、uri 进行定制。
三、问题与解决
现实很饱满,事实很骨感。真正推动域名收敛的过程,咱们遇到了很多辣手的问题,这里记录了次要的几个。
3.1 path 池
依照网关的这套转换规则会存在一个破绽,以 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 的服务,也会有相似的问题。
针对此问题,咱们设计了 path 池机制,每一个收敛域名须要和一个 path 池进行绑定,咱们会在创立 upstream 的时候把对应的标签退出到 path 池,只有退出到了对应 path 池的 url 能力失常通过网关,其余胡乱试探的 /A,/B,/ C 的申请会被网关拦挡。
3.2 日志切割
以 app.xueersi.com 为例,在网关上会配置一个对应的 vhost,当申请到来时 Nginx 会匹配中这个 vhost,也就是所有接入到这个域名的服务都会共用 vhost。一个 vhost 就有一份 log 文件的问题,如果前期这个域名接入了上百个服务,那这上百个服务的 access log 全副会记录到
app.xueersi.com_access.log 这份文件中,势必会造成单份日志文件过大的问题,同时会对 ELK 的搜寻造成困扰,用户很难找到本人服务对应的日志。
针对此问题,咱们采取了一种 ” 变量式 ” 日志记录形式,即 ”access_log /home/nginx/logs/app.xueersi.com_{host}_access.log”, 当接入 app.xueersi.com 的申请到来时,网关层会辨认标签信息并将 host 进行对应的改写,到了 Nginx 的 log 阶段,会辨认以后的 host 变量决定往哪份 log 文件里写日志。例如 app.xueeris.com/A 则会写入 app.xueersi.com_A_access_log, 而 app.xueersi.com/B 则会写入 app.xueersi.com_B_access_log。
3.3 cookie 爆炸
当多个服务共用一个域名时另一个辣手的问题是 cookie,服务端如果都往 app.xueersi.com 里 set cookie,一是不同 cookie key 可能会反复,二是如果没有标准前期很可能会超出浏览器的最大 cookie 长度限度。
针对此问题,咱们从两方面着手解决。一方面设计了一套 cookie 管理系统,后端服务如果想要在 app.xueersi.com 里设置 cookie,都必须在管理系统上进行申请,如果该 cookie 曾经有人申请过,则不容许反复申请,cookie 管理系统上会记录每个 cookie 对应的服务信息。另一方面对 dyroute 插件进行革新,在发送响应给客户端之前,会对 cookie 进行校验,不属于该域名的 cookie 会被拦挡。
3.4 跨域
跨域问题也是令人头疼的一个问题,团体平安组反馈,这些收敛域名会存在跨域危险,须要在有跨域限度。然而有的服务心愿可能在网关层对立解决跨域申请,有的服务则心愿后端本人解决跨域,有的服务心愿后端自行处理,有的心愿可能任意 origin 能够跨域拜访,有的则心愿只能‘http_origin’的拜访,甚至会有心愿自定义增加 allow header 头的业务。要想在一个域名 vhost 里 cover 所有的需要很难做到,咱们和业务方以及平安组探讨了一个折中计划,即所有接入域名收敛的服务对立在网关层进行跨域解决,网关会容许团体内的域名互相拜访,例如’.xesv5.com,.xueersi.com, .100tal.com’之间的跨域拜访没有限度,而内部域名则会被拦挡。另外咱们在 allow header 里增加了浏览器辨认的通用 header 头,同时设置有其余变量供业务方选定作为自定义字段。
3.5 双活
接入了域名收敛的服务中,有一部分服务是有双活需要的,然而这些域名是解析到了世纪互联 IDC,无奈满足双活需要,于是咱们将这些域名的公网解析前移到了切流网关上,并利用切流网关的能力实现了双活需要,默认会间接转发到世纪互联,如果有业务须要转发到阿里云会依据提前设定好的路由规定进行阿里云转发。
其实拦在咱们背后的问题远远不止于此,例如前端 js 动静配置问题,网关插件执行程序问题,多环境、多事业部域名收敛布局、多协定反对问题、接入全站减速问题、动态资源 cdn 缓存问题等等。而且面临的阻力也十分大,并不是所有人都乐意承受这个事件,特地是针对一些老的服务,没有人违心去革新,改革总会面临着走出舒服区,适应新的规定,因而很多人会有抗拒。咱们要推动全网校的前端、后端、运维、团体平安以及各部门的我的项目负责人,制订一套网校级的域名收敛标准,同时将这套历史教训推广到全团体。
通过了半年的致力,咱们也获得了一点小小的成绩,不仅在网校落地了一套域名收敛标准,以网关和容器为外围,成功实践于网校云平台,收敛的域名总数也冲破 500 大关。
咱们置信,既然认定了是对的,就始终干上来,解决麻烦的最好办法就是不怕麻烦,总有一天会看到播种。
作者简介
陈朝飞为好将来 PHP/Golang 开发高级专家