初创公司应该如何做好持续集成和部署?

    持续集成和部署是每一个互联网团队都必须要面对的问题,特别是初创公司业务和技术团队快速增长,技术积累较弱的情况下,一个高效的,可遵循持续的运维规范尤为重要,最近一段时间一直在梳理项目开发流程以及自动化测试和部署规范,作为一个总结和大家分享,希望有所帮助:
高效可持续的运维环境需要合理的规范作为支撑:

  • 应用管理规范
  • 权限管理规范
  • 配置变更规范
  • 发布策略规范
  • 日志运维规范
  • 持续集成部署实战

应用管理规范

应用版本化

    可以使用SVN,Git对代码进行版本控制,建议使用Git(GitLab)
    项目Group命名规范: 按大的原则根据产品域名区分 或者根据前后端业务模块进行分组(小写字母命名,横杠[-]作为连接字符)
    比如: MAKA官网http://www.maka.im对应的Git仓库Group为official
    按照功能模块分组如商城前端对应的Git仓库Group为store
项目名命名规范: 小写字母命名,横杠[-]作为连接字符,命名规则[产品名称]-[项目类型]-(自定义名称),如official-store
注: 在创建项目仓库时就要权衡前后端或者大的功能模块的拆分保持低耦合度

合理的分支策略

常用的Git工作流:

集中式工作流:很多公司使用SVN,Git使用并不熟悉,如果迁移至Git之后可以考虑集中式工作流进行开发,代码库只有master一个分支,所有开发者只有本地master和远端master分支,集中式工作流使用起来虽然简单,但无法充分利用git的优势
功能分支工作流: 与集中式工作流不同的地方在于除了master分支以外有功能分支(按功能需求创建的功能分支如third-party-login-feature),日常开发在功能分支,提测集成时提交Merge Requests(在Bitbucket中是Pull Request),此处开发者可以进行讨论审核代码,同意后可以合并至master分支,未同意或者让开发者修改后重新提交可以选择关闭该MR


Gitflow工作流:两个主干分支master(正式发布的历史)和develop(功能集成分支),开发者应基于develop分支创建feature功能分支用于开发,开发完成后提交merge requests请求合并进develop分支,此时若到了发布窗口,基于此时的develop分支创建发布分支release用于测试,预发布,发布以避免影响develop分支的正常集成合并功能分支;release分支不再有新的功能合并进来,一旦创建只用于bug修复并将修复cherry-pick到develop分支;发布完成后,release分支合并进master并分配版本号打tag用于存放发布历史;Gitflow工作流方式适用于大型项目
Forking工作流:开发者fork官方的repo到自己的账号空间,对于官方分支只有只读权限,开发者通过pr提交给官方审核是否合并进代码库;开发者通过同步上游官方的repo来使用其他人的代码,分支策略可参考上述三种工作流,适合开源项目
    针对创业公司参与同一个项目的开发者并不多,过于复杂的分支策略并不能带来便利;可以参考leancloud的分支模式,根据团队的使用情况进行调整
介绍下我们当前使用的分支策略:
    master:主干分支master用于日常开发的基线
    userA: 开发者A日常开发所在分支
    release-201603091106: master分支集成测试完成后,构建到预发布环境时自动创建release-201603091106用于发布
    hotfix-201603091106 基于当前发布之后的release-201603091106分支用于修复bug,在通过提交merge requests方式合并进release-201603091106,并将修复cherry-pick到master分支
    日常开发在userA分支操作,然后提交merge requests请求合并至master分支,本地通过git fetch origin master,然后在userA分支git rebase origin/master将master最新commit合并到本地userA分支从而形成闭环开发

关于代码审核

   三剑客GitLab+Jenkins+Gerrit,Gerrit作为创业公司代码审核的话略显复杂,不足够敏捷;建议使用GitLab的Merge Requests或者Github和Bitbucket中Pull Requests作为代码审核和讨论的工具,也可以选择Facebook的Phabricator(可同时作为代码托管和评审,非常敏捷,由于Phabricator提供的工具集在windows下使用起来不太友好,后来没有选用,后期会分享Phabricator的使用思路和工作流)

目录结构

   规范的目录结构不仅有利于开发者理解代码结构,更有利于代码的快速部署,以PHP为例目录结构建议将代码配置文件(数据库,Redis,OSS Key,语言开关,日志级别开关等),日志文件,其他文件缓存等独立于代码库之外存放,前端项目src为源码目录,dist为前端经过压缩合并等最终生成的代码目录(发布时可忽略src);
   每个项目详细写README.md:项目说明,各个环境对应的访问路径,目录说明,构建压缩方式,Nginx配置等,代码仓库中包含额外的test目录存放测试用例(本着谁开发谁写测试用例);

权限管理规范

   权限有两类一个是系统权限(包括服务器登陆,数据库/Redis等)另外一个是服务运行时的权限;

针对系统权限层面

   统一入口,受限访问IP,禁止空密码弱口令,生产环境服务器需要先拨入vpn之后通过跳板机才能连接成功(当然我们使用的是开源当中最好的跳板机Jumpserver),任何人的操作都需要审计;生产数据库及Redis禁止了外网访问,分别使用phpMyAdmin和RedisLive统一访问入口(增加了多主机访问及屏蔽了危险操作如DDL 数据的导入导出等,也需要先拨入vpn才能访问);
   开发测试环境权限控制现对宽松,DEV Leader和QA Leader同时具有开发和测试环境的服务器及数据库权限,便于测试和Debug;生产环境为了便于开发调试生产代码且不影响线上增加了低配的节点,未在线,但环境,代码及后端均和生产一致;

针对服务权限层面

   以web服务为例:Nginx和php-fpm运行用户和用户组为www-data,代码目录用户为www,这样代码目录默认情况下web服务只读,避免出现文件和目录777权限的情况;日志和缓存目录用户设置www-data,但要禁止访问php等动态文件
   禁止危险函数phpinfo exec eval system等,具体可参考http://www.sinacloud.com/doc/sae/php/runtime.html,禁止夸目录访问open_basedir,是否开启的性能对比请参考http://www.simlinux.com/archives/1531.html

配置变更规范

系统部署

   传统IDC机房可以通过定制镜像或者使用cobbler定制安装,运行的服务也可以定制在镜像中,但建议安装系统时注册puppet/salt agent,再自动化署相关服务
   公有云中可以在服务器上部署相应环境后创建系统快照制作系统镜像,弹性扩容时可选择该镜像自动化安装

日常变更

   日常变更包括服务配置的变更和代码配置的变更,这些操作我们是通过Ansible(对比puppet/salt的好处就是简单方便不用装agent,后面会详细介绍如何基于Ansible做发布回滚),变更内容使用git进行版本控制制

发布策略规范

发布时间

注意:以上请根据自己业务做相应调整,避免在业务高峰期发布(除应急bug外),我们业务高峰期基本在18:00-23:30,低峰期基本在01:00-06:00,这也是微信分享阅读的高峰和低峰时段;无论应急Bug还是日常迭代都必须由QA测试通过和产品经理审核通过后才能上线(曾经出现过开发为了修复线上很急的bug,开发修复后自主上线导致生产出现更严重的问题)

发布工具的选择

    无论是自主开发发布系统亦或是使用开源的系统都要本着解决问题的原则,否则只能是重复造轮子,然并卵呀
    开源的持续集成和发布里面个人觉得比较好的如:Jenkins,Walle,Spinnaker,go,Gitlab-ci,Bamboo(收费)等,其他参考https://github.com/geekwolf/sa-scripts/blob/master/devops.md
    下面介绍我们基于GitLab+Jenkins+Ansible(Flamingo自动化代码发布工具)实现的自动化代码部署平台,流程如下:

   Flamingo(“火烈鸟”,https://github.com/geekwolf/flamingo)是基于Ansible的自动化代码发布工具,目的是实现统一的代码发布方式,思路基于Capistrano,并对Ansisrano进行了改造可以通过传入语言环境,主机组(应用组/灰度机组等),项目代码库,分支名称,项目名称等参数来进行自动化打包发布,也可以将Flamingo工具二次打包使用
   Flamingo本者回滚即发布的原则以简化发布流程,回滚时传入要回滚的分支即可,其他参数可参看defaults/main.yml进行了解;(注:依赖Git/rsync/ansible)
    例子:

    执行后生成的目录结构如下图(目录定义请参考defaults/main.yml):

日志运维规范

    毫无疑问规范的日志对于运维和开发排查问题有非常大的帮助,例如PHP项目日志格式可以规范为时间,日志级别,日志内容(比如对于连接多个DB时出现连接不上或超时应该把实例地址一同写入日志),可以参考psr-3的标准: http://www.php-config.org/psr/psr-3
    通过ELK将业务日志,PHP自身错误日志/慢日志,Nginx慢日志等进行搜集统计并结合Zabbix实现报警,便于及早发现问题

持续集成部署实战

    后续篇章会分享针对PHP/JAVA/前端以及Android/ios持续集成和部署实战,敬请关注

总结

    以上只是粗略对持续集成和部署过程中遇到的问题进行了总结,可能并不完美,但对于初创公司应该有些帮助,欢迎一起学习讨论!

初创公司应该如何做好持续集成和部署?》上有6条评论

  1. statby

    写的非常好,求教下salt跟Ansible的优劣,目前已经用salt写了许多现成模块,有无必要转Ansible?谢谢!

    回复
    1. geekwolf 文章作者

      可以配合使用,ansible同时执行单个或多个任务比较方便,学习起来也不复杂,一般push模式,不过也可以通过pull方式但是没有salt agent的方便了

      回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注