木犀后端开发工作流(2017年6月版)

木犀后端的技术经历了一个不断演进的过程,从最初的LNMP式的简单直接的部署方式,到Docker容器部署,到现在的Kubernetes集群部署。相比当年艰难的调试由于操作系统环境不同而导致的各种部署问题,现在的部署流程可以说是相当简单而且可靠的。这也要求我们有一套标准化的开发部署流程。 三个环境 在互联网公司,一个产品一般都部署了好几个版本,比如开发、测试、预发布等等。不同的版本对应开发周期不同时间点的产品状态。QA一般就是在部署好的这些环境中进行发布前测试的。 我们对环境的要求没有那么高,只要有本地、测试、线上三个环境就可以了。下面分别讲讲从本地开发,到部署测试版本,到新版本上线过程中一系列的标准流程。 开发分支与Pull Request 本地开发其实没有太多的限制,一般就直接在本地运行代码进行开发。需要注意的是我们的仓库中一般有主分支和开发分支,这个开发分支可以是按版本号,每次新版本时从主分支checkout出来。或者是一个持续使用的开发分支。所有人都不能直接向主分支提交代码。但可以直接向开发分支提交代码。 如果想讲开发分支中的代码合并到主分支,就要发起一个Pull Request。Pull Request在负责人code review(看情况)以及CI测试通过之后才能merge。 单元测试与CI 对于有明确输入输出的后端API来说,单元测试是必要的软件质量保障。也是协助开发的一个手段。 大家在本地提交代码之前先自己跑过测试,通过之后再提交。Pull Request时还会跑一遍CI,来确保代码功能的正确。比如这样: Github上使用的比较多的是Travis CI。Docker based的项目可以参考这个CI配置。 这里简单介绍一下CI。CI指持续集成,我们说的CI一般是指云端的CI runner。Travis CI本质上其实就是一个云服务。提供了一个虚拟环境来运行你指定的脚本。Travis支持很多语言环境,但最近Travis支持了Docker,所以环境也就不是问题了。要注意我们写测试时要写清进程exit时的状态码,非0的状态码代表非正常退出。Travis就是根据这个来判断测试或者其他错误是否发生的。这决定了这次CI运行是否成功。 测试环境的具体配置 在开发基本完成,代码merge到主分支之后,我们就可以尝试部署一个测试版本了。测试环境和线上的环境差别不大。测试环境部署在我们的测试集群(几台专有网络阿里云学生机)。 大家可以随意选一台机器然后部署。部署的时候,除了数据库之外的一般都用Docker部署。如果有多个容器需要部署,我们一般用Docker-compose来一键build&run。 数据库一般就使用某台机器上直接安装的数据库。在初次部署时大家要记得在容器中执行初始化数据库和用户角色命令(当然也可以写成脚本)。 测试环境有几个用处,首先是给前端提供联调的API。然后是给产品经理和设计师提供一个线上版本来进行初步测试。因此我们需要给测试环境配置一个域名。但如果直接在DnsPod等等线上解析,要解析的域名数量会很大,很不方便。所以我们采用修改本地hosts文件的办法。 比如: 120.77.8.149 test.share.muxixyz.com 注意域名是muxixyz.com的子域名,因为阿里云会检测DNS解析的域名是否备案。如果随便写一个域名是不行的(当然理论上你用baidu.com或者其他知名的域名也行)。 这个hosts文件的配置要写在Github文档中。Tower项目里最好也写一个操作指南文档给设计师和PM看。 上线 MAE发布后本节需要更新 上线一个版本,比如1.2版。首先在主分支打上这个tag。然后在阿里云的镜像仓库里build这个tag的镜像。 最后由负责部署的同学,SSH到集群更新Deployment配置文件中的image版本号。升级Deployment即可。 这一步在将来会由开发应用的同学自行在MAE上操作完成。目前暂时还是需要有人在服务器上部署。开发的同学只要交付镜像就可以了。 总结 相比于之前的工作流,目前的工作流不同的地方主要是,需要写单元测试,PR需要CI通过才能merge,大型的应用必须要部署测试环境并用本地DNS解析访问,进行部署时是用Docker镜像而不是在服务器build。这套工作流需要大家用微服务的观点去看待将来的开发。随着时间的推移,这套工作流也会不断的变化,大致还是朝Cloud Native的方向发展。

June 5, 2017

云端木犀-MAE初步构想

2019/6/5 今年我们有同学拿到了腾讯云和 Azure 的实习,所以未来在云计算上我们会有更多的领路人,来带领团队在这个方向进行探索。MAE 虽然还没做出来,但 k3s 的发现让我们在服务器上实现了自由,相信很快就会设计出下一代的 MAE 架构。 Muxi App Engine,简称MAE,是木犀的私有PaaS方案,也是木犀云的重要组成部分。MAE主要基于Docker和Kubernetes,为木犀所有应用的构建、部署、监控和扩容提供了一个统一的入口,让我们能专注于服务本身的开发。同时MAE也为木犀提供了一套标准化的运维流程,使得团队开发中的工程化程度进一步提高。 说的这么厉害,那如果你是一个技术小白,我应该如何来解释MAE呢? TD;LR 比如我们有一个应用,华师匣子。华师匣子是由很多的服务构成的,比如成绩服务,课表服务,图书馆服务等等。每个服务都实现了对应的接口。我们使用Docker来运行这些服务。Docker是一种容器技术。我们可以简单的理解为一种沙盒环境。这些容器的存在,已经很大程度上方便了我们的部署。因为容器可以实现系统资源的隔离,使得服务器上可以同时运行很多不同的服务,而相互不打扰。 但手动部署容器,还是太复杂了。我们要登录服务器手动部署容器。容器如果出现问题,我们也需要亲自去重启。如果我们需要横向拓展,部署多个相同的容器以应对高负载,也需要一个个去手动部署。这个时候就需要一个调度者来帮我们自动完成这个任务。 我们可以把MAE理解为容器的调度者。我们在MAE中新建一个应用和下属的服务,填写相关的信息。比如我们只要提供Docker镜像的地址,就可以一键部署。MAE会帮我们将容器部署到合适的服务器上。如果容器因为某些原因崩溃了,MAE会自动重启容器。如果我们需要横向拓展,那只要在控制台里填写一下需要拓展的数量就可以了。如果需要更新代码,我们只需要提供镜像的新版本号,MAE会自动终止旧版本的容器,新建新版本的容器。一切都是这么简单。可以自动化的事情,我们都会做到自动化。 MAE提供Web UI和CLI。Web UI主要用于日常的使用以及查看监控数据。CLI适合在shell脚本等自动化环境下使用。 MAE带来的最大变革是,今后我们的应用从一开始就应该按Cloud Native的思路去编写。要拥抱云计算,我们必须编写Cloud Native的应用,具体的说,使用微服务架构,写无状态的功能单元,容器技术,将数据库等等持久化的组件作为单独的部分等等,都是Cloud Native的体现。只有这样,我们的应用才能和目前公有云和私有云的基础设施完美结合。 下面就是纯粹的技术讨论了,请耐心阅读。 MAE的技术选型 简单的说,就是Docker和Kubernetes。Docker是容器技术的实现,Kubernetes主要提供了容器编排管理的功能。上一节中说到的大部分自动化功能,都是Kubernetes实现的。MAE中需要我们研发的主要是MAE API服务、Web UI还有CLI程序。除了这些,还有就是在MAE中实现一套最适合我们的对应用的抽象。这套抽象是非常重要的。Kubernetes的概念并不是所有人都可以理解的,也没有必要对使用者暴露最底层的概念。PaaS的用户是从是应用和服务这些逻辑上的概念去看待问题的。所以MAE就提供了针对应用和服务的抽象,并且和Kubernetes整合起来。 MAE的组成部分 MAE的组成,从上到下,大致有三层: MAE服务层 MAE服务层是暴露给用户的一些服务。MAE API Server是MAE是中枢。负责和底层的集群通信,保存应用配置等等。MAE Web UI提供了一个Web界面,用户可以通过Web UI对MAE发出指令,查看监控数据。MAE CLI是一个命令行程序,提供了从命令行和API Server通信的渠道。 逻辑应用层 这一层是抽象的应用层。也就是我们概念上的应用。因为实际的集群中是没有应用概念的(当然Kubernetes的Services+Namespace已经非常接近了),所以我们需要在这里提供对应的抽象。我们可以在MAE中新建应用,然后配置这个应用对应的服务。MAE中的服务(以后简称MAE服务,区别于Kubernetes Service),其实就对应一个微服务。一个应用由至少一个微服务构成。MAE服务是用户可以控制的部署的最小单元。我们可以对某个MAE服务单独进行拓展。比较特殊的MAE服务就是Nginx入口服务,这个服务为所有应用提供反向代理,同时也作为一个MAE下的服务,被MAE部署。 Kubernetes层 Kubernetes这层就是底层的实现层了。包括了Service,Deployment和Pods。其中Service和Deployment在上层共同支撑了MAE服务。Pods则属于最底层的调度单元。在MAE层是完全不可见的。一个Pod由至少一个容器构成。 MAE的流量分发 那么作为一个分布式系统,一个用户的请求究竟是经过怎样的路径,到达最底层的Kubernetes Pod的呢? 首先DNS把域名解析到Kubernetes的Master节点的公网IP上,然后部署在Master节点上的Nginx入口服务接管,Nginx根据MAE应用设置的域名和URL规则,将这个请求转发到对应应用的某个服务上。Kubernetes的服务都是可以通过<Master内网IP>:<Service Port>来进行访问的。然后Kubernetes proxy用iptables规则,将请求转发到某个节点上的Pod。 由于Kubernetes proxy提供了均衡负载,我们不用再操心如何分配流量到服务下属的多个Pod中的某一个这样的问题。今后可以做的优化是,实现Kubernetes Master节点的高可用,也就是同时部署多个Master节点。这样的话就需要在Master节点之上再实现一个均衡负载。 MAE的实现细节 MAE做的抽象,一个是应用,应用之下是服务。对于这两个抽象,应该各自保存一些什么样的数据,这属于MAE的实现细节。 每个应用需要的信息有,应用名,域名,Nginx转发规则,应用下属的服务列表。 每个服务需要的信息有:服务名,当前镜像版本,镜像仓库地址,Github仓库地址,Kubernetes Service和Deployment需要的全部信息,当前服务属于哪个应用,授权管理当前服务的用户列表。 因为服务是部署的最小单元,因此相对来说服务是MAE中比较核心的一个部分。MAE需要将数据库中保存的服务信息,自动转化为Kubernetes需要的.yaml文件。将数据库中保存的应用信息,自动转化为nginx的配置文件。这是实现上需要去考虑的一个问题。 另外,现在还需要仔细考虑的一点,MAE在全局/应用/服务这几个层面分别需要哪些监控数据。 MAE时代的部署工作流 部署服务之前,首先我们要构建镜像(构建之前可以引入CI,测试通过才可以构建镜像)。给镜像打上版本号,然后发布到云端的镜像仓库(可以用阿里云/蜂巢/Daocloud)。之后我们就可以在MAE中为某个服务新建一次部署了,填上新的版本号,点击部署,就启动了一次部署了。得益于Kubernetes超强的部署能力,我们可以回滚、暂停、继续每一次部署。 MAE的API Server把服务目前的配置转换为.yaml格式,向Kubernetes API Server发送请求。然后Kubernetes会进行相应的处理。和Service相关的就调整Service,和Deployment相关的就调整Deployment。最终服务更新到目标状态,部署完成。 MAE的物理节点组成 MAE的逻辑组成已经介绍了,那MAE和具体的云主机之间是什么关系呢。请看下图:...

May 27, 2017

从0到1:我和木犀的故事

缘起:华大桂声技术部 2013年10月我加入华大桂声技术部。其实一开始我加的是华大青年,但因为那里没有专门的技术部,面试的时候也没有做技术的人面我,所以我在得知桂声招新的情况下,放弃了华青那边的录取。 于是就开始了在桂声技术部的日子。那个时候其实i华大已经建立了,但桂声还是比较强势一些。那段时间主要就是在一个2011级学姐的带领下做桂声的专题和网站。我记得我来的那年之前做了110周年校庆专题和迎新网,都很不错。桂声的专题是很有特色的,现在我们也试图去捡起这个传统。 我接到的第一个任务是做一个恽代英专题,在炳权学长的指导下,顺利的做出来了。关于这个我记得比较清楚的细节,一个是熄灯了之后搬个凳子去走廊里做,还有一个是上线了之后很兴奋,发给很多人看。 接下来就是下半学期开始的桂声改版,我写了一部分的主页。那个时候,我其实压根就不会写真正的代码,如果要用到JS,比如轮播图,我就去网站下一个功能差不多的插件,然后修改一下。这个过程其实是很痛苦的,因为你心里并没有底。所以每次把插件改好都像是一场战役。 一个人的i华大技术中心 2014年开始,虽然我们还是习惯说自己是技术部的,但名义上已经是i华大技术中心了。底下分技术研发部和视觉设计部。 说一个人,我指的是技术方面,设计那边还是很强大的。除了做主任的学姐和炳权学长,其他人并不会技术,然后之前的主任学姐三四月份就跑路了,炳权学长也很早就在名义上退出了。因此这个技术部就只有我一个人了。 然后就是2014年四月份,技术中心春招。我依稀记得那个时候来了有大概三四十号人。然后我在306做培训,其实就是教他们切页面。 那个时候也没想着要做一个技术团队,就想要把技术中心做好吧。当时我自己其实也是小白,也教不了他们什么。这三四十号人也并不是完全合适,因此最后待的比较久的,就只有龚红霞一个人。 2014年的上半年还发生了一件事情,就是桂声10周年庆,请了很多高校的团队来交流,有武大和理工人的来了。当时我们的技术实力几乎为0,然而却在PPT上写了我们用Node,现在想起来还是觉得脸红。我听他们讲JSON,API这些,完全不懂。想来这应该就是我想打造一个技术团队的最初来源吧。 木犀! 木犀这个名字,想来应该就是14年下半年提出的。之所以叫木犀,是因为华师的桂花很出名,但直接叫桂花又太俗。我偶然得知木犀是桂花的学名,于是就选用了这个名字。 这里有个插曲,炳权曾经提议说我们可以叫handle,现在想起来还是觉得很搞笑。 2014年的秋招,来了很多人,胡薇、韩伟、老王、王露晨、梁晓怡,这都是之后设计组的核心,想来之后那段时间也是设计组的黄金时代。小桂漫画,壁纸,表情,都是那段时间做的。 还有一个人,那就是朱承浩。 对我建设团队帮助最大的还是炳权,因为炳权那个时候已经在冰岩了(虽然我到15年上半年才知道),他会给我们很多建议,我也拓宽了很多视野。 2014年下半年我们开始学Python,决定用Python做后端的语言。但那个时候还没有能力去完成一个网站的后台。那段时间我主要是用Drupal这个CMS来做学而的第一版。 学而第一版其实反响还是很不错的,现在数据库里都还有那个时候的评论。这对我来说是一个鼓励,说明产品是有需求的。然后Drupal这个东西,开发难度很大,这坚定了我们自己学后台的决心。 2015年的到来,是一切奇迹的开始。放弃Drupal和各种前端插件,真正的踏入Web开发的大门,就是从哪个时候开始的。所以说木犀的成长史,也是技术的成长史。 首先我们在15年2月全面使用了Tower(这个时间点之前设计组好像就已经在用了)。大家看我和承浩的进度都是从15年2月开始的。至于Tower,对,没错,是炳权告诉我的,因为冰岩在用。 之后就是承浩的时间了。他学了Flask,我们用Flask搭的第一个网站是什么,我已经忘了。我只记得那个时候,光部署网站,就要花好几天,因为书上讲的是AWS这种云服务的部署。手动的部署还是有一些门槛的。那个时候,因为了解的层次比较低,会觉得很多东西是玄学。 3月我们去了联创交流,具体可以参见我的这个博客。 5月份和6月份其实还有一次转折。5月份的时候,理工的token团队办了十五周年庆,我们去参加了技术交流会。这次是我们第一次以木犀团队的名义出去交流。也是从2015年上半年开始,我们慢慢习惯以木犀团队的身份出现在所有人的眼中。这次交流会上,我们依然没有太多的干货,相比于其他团队,我们感受到了我们还太年轻。 6月联创Hackday。我们主要是去感受了一下气氛。3月和6月两次去启明,对于我和承浩两个做技术的人来说,这个冲击不亚于工业文明对封建社会的冲击。首先是感受到了华科那边浓厚的技术气氛,其次是感到了一些压力,因为我们团队是如此的弱小,而华师的技术氛围又不想。当然是压力也是动力,不管如何,从2015上半年之后,我们团队在技术上便开始了不断的进步。 联创Hackday (图片找不到了) 暑假承浩买了Mac,从此就一发不可收拾。那个暑假我在极验实习。其他人进行了我们第一次的夏令营(夏令营这个想法也是炳权提供的)。那个夏令营还是很愉快的,我们做出了第一版的内网,对于Flask的掌握已经好很多了。 夏令营照片: 夏令营最后去落雁岛玩的照片: 2015年9月,团队已经初具规模了。后面的事情,15级的同学应该都清楚了。 接下来的事情就是2015年下半年开发的学而的第二版,完全用Flask写,有同步的路由和REST API组成,前端移动版是一个SPA,用了Webpack和React。这就是我们第一个工程化的产品。 技术团队的成长,其实就是我的成长,承浩的成长,已经后面14级其他同学和15级同学的成长,每次有一个人成长为核心成员,团队就变的更加的强大。 番外:304-306-502 一开始,i华大技术中心的办公地点是在304。那时候我们还是非常自由的,304可以随意的改造。经历过那段时刻的同学应该知道,那段时间是很有归属感的一段时间: 直到今年5月份,304和306装修。我仓皇中去合租了一间房子,在教工宿舍,作为我们的临时工作室: (图片找不到了) 那段时光是难忘的,也是别扭的,痛苦的。那只狗,上门的邻居,狭小的空间,和我自己当时的各种压力混合在一起。 现在我们主要在306活动,也在304。虽然归属感没有以前这么强了,但因为大家更熟悉了,核心成员也更多了,所以团队的气氛要更好一些。 我还是希望我们能有一间独立的工作室。我们要时刻保持危机感,来应对未来的无限的可能。 前端之路 我个人的前端之路,其实也是木犀从0到1的一个很好的注脚。 我其实在15年的上半年才开始正式学计算机。那个学期在武大开始辅修,然后在团队开始学Flask和Python。5月的时候,我的前端水平是只会写简单的Banner,相比之前Banner都要用插件的水平来说,算是好一些。那个时候是标准的过程式的编程。 5月的时候看了一本单页应用开发的书,里面讲到了IIFE,闭包等等。我如获至宝,写个什么组件(其实我当时并没有组件的意识)就用IIFE,其实这算是最初的模块化,工程化意识吧。只不过我那个时候并不清楚模块化和工程化,也不知道正常的编程语言都是自带模块的。 7月和8月我主要在极验实习,切了不少的页面,里面有一些用jQuery做的组件。这个时候我写展示型的页面以及比较熟练了,CSS也掌握的不错(毕竟在写桂声那些主要就是CSS)。但对于前端的那些Grunt什么的工具,其实我并不是很清楚为什么要用。 所以对于模块的理解,对我来说是一道坎。真正理解模块和工程,还有闭包,大概是今年的事情了。 9月回学校之后我看了React,后来就开始用Backbone写学而。那个时候我对MVC了解的还是比较多的,因为之前后端用的就是MVC。写React的时候比较初步的理解了组件化。之后对于Webpack之类的工具也用的很顺手了。 这个学期对面向对象也略有了解。但对于View和Model的分层,以及组件的抽象,还没有到能手写的地步。那个时候我看Backbone源码,并没有太多感觉。而现在我回头看,就觉得抽象非常的清晰了。 那个时候我对很多事情的理解都比较的浅薄。对于React Native很崇拜,觉得Web的目标就是取代原生应用。觉得Web就是要做单页应用。也没有很深入的理解前端工具为什么存在,以及组件化的发展史。 现在来看,其实Web有Web的特点,需要动态化、快速上线、展示型的东西都可以用Web来做,这只是一个简单的技术选型的问题。 总得来说,这是一个技术视野的问题。如果你用过很多别的语言,那你就应该很容易的理解模块的存在。如果你开发过原生应用,那你就应该很好的理解为什么Web开发的UI应该是组件化的。 今年开始,我把兴趣移到了函数式,编程语言,还有计算机基础上面。对于前端,我主要在开发工具解决我们自己的工作流中的问题,还有就是研究框架和工具的源码,进一步深入。 现在回过头来看,我就能发现前端学习的一个最佳的路径,DOM可以不用花很多心思,但组件一定要自己去手动实现。模块可以直接用标准的模块。前端无非是普通的客户端软件开发,从这个视角去看的话,事情就清楚多了。 计算机基础加上足量的工程经验,应该就可以成就一个好的工程师了。我的前端之路还算顺利,大家的学习道路,在我们这些先行者的踩坑之后,肯定会更加顺利。但有一点是肯定的,要把一样事情学好,需要你的热情,时间,和精力。 还有一点,就是你的视野是随着你的经验而增长的,视野对你理解一些技术是非常有帮助的。平时我们在安排学习路线时也会特意的去安排背景阅读材料,或者是讲一些思想和Lab结合起来,努力让大家能够尽快的熟悉那些方法论层面的东西。同时,你自己的思考也是离不开的。我经常会思考,踱步。好的书常看常新,经典的思想,也是需要反复的思忖才能领悟的。 我们在路上,前方不会太远 2016年,团队最大的新闻当然就是华师匣子的上线。这个是我们的第一款移动应用,也是将来一切产品的推广基础。 在我看来,团队最大的成长,一个是技术团队在工程化上慢慢摸索,有了自己的方向。我们的方向就是通过造轮子来深入原理,积极的实践最新的技术,写完善的文档,在社区中争取拥有一定的影响力。 在团队的管理上,确立了早读制度,试行了导师制度,管理工作组共同管理团队,成功的进行了秋游,招新算是顺利,团队管理层平滑更换。这些都是一个团队平稳运行的基石。如果说这个大框架搭好了,我们就可以把精力投入到具体的产品和新人培养中去了。 在接下里的日子里,我们要把产品的汇报制度完善,项目组的气氛要更好,全员大会要常态化,组内技术积累要抓紧,新人双轨培养的计算机基础方向需要花很大的力气建设,UED部门要重新上路。 对于团队的期望,我不想说太多,我只能说,作为一个木犀人,你就算毕业了,也依然要参与到团队的建设中去,只是不在第一线了而已。只有这样才能慢慢的把事情做好。我们追求的是理想中的团队,可能我们永远都无法到达那个理想中的境界,但一直在成长,一直在进步的话,大家开开心心的,就挺好。 我们在路上,前方不会太远。

December 19, 2016

联创交流行

今天托房子学姐的福,我们一行8个人去了联创交流。收获如下: 1.招新之道。 联创的招新可谓是九九八十一难。几轮面试笔试压力测试加上实习期的四轮新手任务。这也是没办法的事情,报名的人多,而且据他们说也都不怎么有基础,那就需要不断的测试来筛选有潜力的。 新手任务我认为是可取的一个点。在不断的自我学习中获得成长,也得到了初步的知识与技能,不失为一个启动的好办法。 2.待客之道。 联创的人给人的印象是热情坦诚,愿意分享,但不失专业。 ...

March 27, 2015