DevOps实践总结

好吧,总感觉这个篇幅巨大,不知道如何着手。

老规矩,先上酸菜讲概念吧。

何为DevOps

与Agile类似,DevOps同样是一种理念。从字面意思来讲,DevOps是由Development和Operations两个单词组合而成,那么,自然而然的,它应该包括研发与运维两个大的部分,是这两个部分的一种组合方式。网上找到一个英文的定义,如下:

DevOps is a set of practices that combines software development (Dev) and IT operations (Ops).

很明显,这种组合实践的集合强调的应该是开发与运维的合作,最终的目标是实现软件或者服务的顺利交付。

DevOps的目的在于建立一种可以快速、频繁、可靠地构建、测试和发布软件的文化。它所追求的,与Agile所追求的快速稳定的交付本质上并无不同。

与Agile相比,它强调的是持续性:

  • 持续集成 CI (Integration)
  • 持续交付 CD (Delivery)
  • 连续部署 CD (Deployment)

下面这个图是比较经典的一张DevOps流程图,可以看到两个闭环的循环:

DevOps流程

DevOps也包括一系列在各个流程中使用的各种工具的组合或者服务,强调Automation Everything. 这些会在下面逐一提到。

团队构成

从敏捷的角度来讲,一个Scrum团队也是一个自组织的团队,它的构成应该包括研发测试等人员,但这些人员的职责并不是那么明确,往往要求开发人员既懂开发也懂测试。

对一个DevOps团队,首先需要的是研发和运维两方面的人才。为了达到持续继承和交付的目标,必然需要测试的支持,在传统的研发方式中来说,这属于QA团队。而基础设施的配置方面,尤其是在云计算的环境下,传统意义上的运维人员也不足以达成使命,需要云计算相关的人才参与进来做快速的支持和反馈,当然他们是应该是可以直接替代传统运维人员的。而为了能让客户满意,迅速对客户的要求做出反馈,一个用户支持方面的人才也是必不可少的。这样一来,完整的DevOps团队就由如下的人员构成:

  • 研发人员
  • 云基础设施维护,或称云运维
  • QA,测试人员
  • 客户支持,support

同样的,各个人员的职责也不是那么明确的,研发运维和测试的人员往往需要技能打通一条线,这与全栈式开发的思维不谋而合。而客户支持所需的技能比较特殊,在某些情形之下,也许只有传统的测试人员可以兼任。

DevOps实践

DevOps实践是在Agile理念和Scrum等框架的支持下完成的。按照流程大致可以分为以下几个阶段:

计划

Sprint计划会议,PO了解产品特性,与Scrum Master一起制定Sprint的计划,形成Sprint的backlog作为整个Sprint的计划。

编码

编码时应该具备这样几个要素。

DoD

首先在编码之前,一个Story的DoD(Definitino of Done)在团队内部要达成一致,简单说,做成什么样了才算了完成了。DoD中应当包括CI的通过,TDD方式开发要有Test Caset提交到代码库。

代码库

对于代码库的使用,多使用Git类的代码库,比如可以自建库的GitLab是一个选择,使用Docker启动后做一些配置就可以完成了。SVN已经不推荐了。

代码相关规范

首先是代码编写的规范,这也应在团队中达成一致。因为使用语言的不同,需要根据每个团队的情况,针对可能出现的代码情况分别定制不同的规范。

其次包括代码合入规则,分支使用规则,代码的交叉检视(Review)方式等等也要确定好。

开发方式

推荐TDD或者BDD方式,首先写测试用例,然后再写代码,在不停的试错中完成各个功能,同时建立自信,这时单元测试用例也就完成了。

测试用例的编写可以用BDD中的SBE的形式(Specification by Example)来写,简单说就是Given-When-Then三部曲。

对于不同的语言来说,一般都会有自己语言的单元测试模块或者套件可供使用,无需自己造轮子。

对于GUI界面,我们曾经使用Robot Framework/Selenium的组合来写测试用例,网上应该也有其他的方式,并且各大公司一般也都会有各自不同的测试平台或者处理方式。

测试用例同样需要放入代码库中来管理,而且需要包括单元测试,集成测试等等,能用代码库来管理的通通放入代码库。实际操作中,运维相关的一些脚本信息,Dockerfile, docker-compase的yml文件,K8s启动服务的yml文件,Ansible的play-book等等都是可以放在代码库里面管理的。

总之在Automation Everything的理念下,所有的代码,配置等等都从代码库中获取,然后运行测试等等一系列的操作。

这里插一句,现在已经开始有CaaS的理念了,代码即服务,是跟FaaS类似意思一种里面(function as a service),他们同属于servelss的范畴了。跟CaaS同样拼写的还有个Container as a service,容器即服务。这些aas们太多了一点,有空了放在杂文里面算个笑料哈哈哈~

代码开发的过程最为枯燥但却最为重要,而且也是最体现研发工程师价值的部分,因为这部分没有办法自动化实现。攻城狮们往往倒了杯茶等功能开发完了才想起来喝,这下凉茶都不用买了,真的就是这么乏味。

构建

从这个阶段开始,自动化的程度会越来越高,因为人的主观影响因素在这个阶段可以慢慢去除了。

构建之前,可以使用Sonarqube对代码进行静态的检查。这个工具是专业的进行代码静态检查的工具,有Docker方式部署的CE版本可以使用。这个工具会根据指定的规则对指定代码库中的各个类型的代码(几乎支持所有类型的常见代码)进行扫描,得出的结果包括代码的语法错误(这种错误理应在代码commit之前消除),潜在的bug,代码复杂度的情况,甚至包括了糟糕的设计。对代码bug的分析解释会详细到因此造成的安全漏洞问题的标号,会造成什么样的问题,并解释如何写才可以避免这些问题,真的是太贴心了。所以,这个工具在整个项目的最开始就应该一直运行,从而保证代码质量。如果是半途引入这个工具,扫描出的问题数量很可能会让人望而却步,修正需要花费的时间非常多,代价太大了,远没有从开始就一直修正来的方便。

Sonarqube可以无缝集成到Jenknis之中,每次构建后查看结果也非常方便。

构建通常使用Jenkins Pipeline,用Groovy编写自动化构建脚本存放在代码库,然后从代码库获取脚本,再获取要构建的代码进行编译打包等等动作。

当然也可以使用在Gitlab中配置gitlab-ci.yml文件的方式来构建,或者在Gitlab中使用actions来完成,其他方式也行。

构建同样也有赖于代码的形式,比如Python/PHP/HTML这种类似的代码,要么需要在运行时由虚拟机解释先,要么属于静态语言,这样的代码当然不存在编译的过程,直接在CI时按需打包就完了。

每次构建完成后的package或者docker镜像可以留存在Artifactory中作为历史以方便查找和取用,而这种保存可以分为测试的版本和最终发布的版本,此时就放在测试的版本里面即可。

这个工具是一种二进制软件制品库,由JFrog出品,同样有免费的社区Docker版本方便使用。这又是一个超级强大的工具,可以完成远端操作系统镜像,Docker hub镜像,npm包镜像,python包镜像,maven包镜像等等功能,感觉存放构建包只是个附送的功能,你随便用用就好。有这些功能,配以较大的网络存储,很多运维问题,尤其是国内的运维问题真的是迎刃而解。Artifactory同样可以集成到Jenkins当中,而且有cli可供脚本调用来推送或者拉取二进制包,真的已经不知道该怎么夸它了好么~

测试

测试使用的工具仍然可以用Jenkins Pipeline/Gitlab/Github等来完成,测试脚本也还是要存放在代码库中。

在构建之后,生成的package可以部署至测试环境先,开始运行自动化测试脚本,包括集成测试或者系统测试,或者冒烟测试,回归测试等。单元测试我的理解是在研发人员开发完成的时候就已经完成的,当然如果有需要也可以运行。测试结果如果有问题则通知开发人员,没有问题的版本就可以准备deliver/release了。

这里说下几个测试的区别:

  • 单元测试是对软件内部的最小运行单元进行正确性检验的工作,比如函数或一个类的若干方法。
  • 集成测试是在单元测试的基础上,将所有模块整合为一个较为完整的部分,验证完成后的各个模块间接口是否正确,这部分的功能是否达到预期的测试。
  • 系统测试是将集成好的软件系统作为一个整体,在实际使用环境下进行的一系列的功能确认。
  • 冒烟测试是微软提出的概念,针对每日的构建的结果运行主要功能的验证的一种测试,运行的测试集相对较小,且仅覆盖主要部分即可。
  • 回归测试则是针对软件问题的修复所作的测试,主要是验证所做的修改是否已经成功修复了问题。

这其中,系统测试的复杂性最高,自动化的测试覆盖程度可能达不到预期,此时往往采用人工随机测试的方式作为补充,以保证系统整体的功能符合预期目标。当然,人工的随机测试随时可以进行,只要有可测试的版本即可,随时发现问题解决问题。

发布

发布这里主要指Release。对于部署,发布,上线,交付等等,估计很多人都是满脸的问号,这里有个链接解释的很明白,非常感谢作者,摘录一部分:-->看看<--

发布(Release): 打上一个发布标签,提供出来,受众可以获得它

部署(Deploy):安装,配置,通过验证(验收)测试 # 这块略作修改

交付(Delivery): 接收方确认收到(如签收、同意) # 交给用户,但不一定部署了,也不一定上线了

上线(Go-live / Ship):在生产环境中可以看到,并可以使用。上线 = 在生产环境上的部署


几个例子:

场景1,某乙方公司为甲方公司开发了一个web应用,需部署到生产环境,再发布给甲方公司,交付给使用部门(用户),使用部门才能投产使用(上线),那么它们的先后顺序就是:

集成—>部署—>发布—>交付—>上线。

场景2,A公司开发了一个商用软件,发布到网上,B公司通过购买获得,由A或B公司的技术员将软件部署到B公司的生产环境,交给B公司的使用部门(用户),使用部门才能投产使用(即上线),那么它们的先后顺序就是:

集成—>发布—>部署—>交付—>上线。

场景3,早年,微软发布了Window XP(存储在光盘中),交付给用户,用户再部署到生产环境,然后投产使用(上线)。现在的很多单体软件,大多也是这样的流程。那么它们的先后顺序就是:

集成—>发布—>交付—>部署—>上线。

场景4,A公司开发了一个SaaS应用,部署到生产环境,交付给B公司,B公司再加入自己公司的基础数据后上线了该SaaS应用,发布给使用部门(用户)使用,那么它们的先后顺序就是:

集成—>部署—>交付—>上线—>发布。

例子这块非常就容易理解了,棒棒哒~

接着说Relase。刚刚有提到,Artifactory中保存package历史以方便查找和取用,可以分为测试的版本和发布的版本两种,不过是不同的目录或者路径而已,属于使用工具是对工具的配置或者规划,比较简单。那么这个时候,软件包或者服务包在构建完成后就是通过pipeline放在发布的版本路径下。然后就完了,放着就好。有需要部署的直接获取即可。

部署

接下来是Deploy,仍然可以采用Pipeline的形式,从Artifactory下载软件包或者镜像,然后做安装和配置。这里在使用容器编排之前可以用Ansible等,Redhat还有基于Ansible的一个Ansible Tower,也很有名气,可以以工作台GUI界面的形式实时查看部署的过程。然后在使用K8s/K3s编排之后就简单了,如果使用Helm,那么就用写好的Helm package直接部署就可以了,kubectl的调用还可以用pipeline来完成,又回到了pipeline。

K8s/K3s容器编排的搭建有时候是个问题,尤其在国内网络环境下,需要花费不少时间,而且有赖于云基础设施是否完备,或者自己的私有集群的搭建情况,对网络的依赖比较重。

部署相关的概念也有不少,我找了网上蛮多的资料,总结如下:

  • 蓝绿部署

一种通过冗余方式部署的技术,目的是减少部署过程中服务停止的时间,此时需要有与要部署的服务相同配置的一套环境,部署新版本时,直接部署这套冗余环境,完成后仅需通过修改反向代理的方法切换两套系统即可。部署完成,由蓝切换到绿,如果运行正常,则删除冗余的环境,完成部署;部署后如果运行异常,则此时需要回滚,切换回蓝。

  • A/B测试

其实这跟蓝绿部署没有任何关系,通常用来测试界面或者前端,比如用户对A/B两个系统的满意程度,此时需要分拆用户的流量,一部分到A,一部分到B,哪个用户反馈更好则最终采用那个。K8s是可以完成这个动作的,或者用nginx,也可以在功能上根据用户的特性直接对用户流量进行拆分,比如按照地域选择等。

  • 灰度发布/金丝雀发布

在原有版本可以使用的情况下,变换其中一个或者说小部分的服务器到金丝雀系统,用类似金丝雀对坑道有害气体灵敏反应的方式,测试新版本是否可用。此时也是要拆分出部分用户流量,方式可以是直接绝对性的拆分,也可以基于用户特性,比如特别筛选的测试用户。测试完成没有问题,那么全部转型新系统,否则需要回滚。

  • 滚动发布

这种方式是对在线的所有服务逐个滚动更新到新系统的方式,可以保持用户流量不间断。

运维

剩下的就是运维了。监控应该算是运维的一部分,但对日常运维来说,系统的可见性尤其重要,可见性做的合理而且易用的话,运维的工作可以减轻很多,当然7*24是免不了的了。这么说来世界运维日也没过去几天,悲惨啊。

回来说监控,这是系统可见性的重要部分,监控的结果在Kibana或者Grafana里面展示出来是最后的可见,但是依赖的便是实时对系统各个维度的监控了。

针对K8s平台可以使用Prometheus,根据metrics和label对监控指标进行分类,TSDB的使用也比较易于展示和分析。另外还可以依赖Elastic stack中的Metrics beat,结合logstash将监控数据传送到Elastic search中存储,最终在Kibana中展示。这几个平台都是可以做到邮件通知的,Grafana后期版本增加的告警管理尤其实用。

在收到告警或者在监控中发现问题的时候,运维大师们就可以出动了,赶在用户发现问题之前解决问题才是正确的运维方式。

这种方式也有不好的一点,在领导们的眼里, 往往是:

  • 平时: "怎么你们什么都没做,要你们有什么用?"
  • 出了问题时: "怎么总出问题,要你们有什么用!"

实在太惨了...


最后放一个DevOps的工具链的图吧,密集恐惧症患者请慎看...

DevOps流程

updatedupdated2020-08-052020-08-05