深度解析:持续交付将如何拯救IT运维?

作者简介

刘劲辉(微信号:akito_hui),前阿里移动事业群高级运维工程师,现优维科技运维与平台研发专家,专注于DevOps、应用运维和平台架构设计,参与实施监控平台设计、运维规范设计、虚拟化应用、效率提升等相关工作,在若干大中型项目的建设和运维中,积累了丰富的系统运维、架构设计、项目实施经验。

一、前言

在深入探讨持续交付之前,我们先来看一个典型的场景:
A 公司最近很苦恼。
A 是一个传统行业的公司,物流运输为主营业务,IT部门作为支撑部门辅助业务发展。但是随着业务的快速发展,IT 部门开始感觉到有点力不从心了:

  1. 频繁的业务版本迭代(扩容、缩容、迁移、升级、回滚等等),全靠人工变更操作,操作单调重复,却又风险很高;
  2. 研发同学只关注代码编写,很少考虑线上部署的规范和设计,全靠运维同学自己把关,结果各个系统的维护自成一套;
  3. 新旧系统越来越多,系统调用和接口关联复杂,一个看似简单的问题都要捣弄半天,甚至还查不出原因,更别提性能优化;
  4. ……

一个好的运维/测试应该可以设计交付流水线,实践了流水线才是真正的devops专家。

长久以往,业务部门对IT部门的印象直线下降,认为IT部门是一个成本部门的同时表现还让人失望,而 IT 部门则哑巴吃黄连,有苦吐不出。

A 公司遇到的问题,相信很多传统企业都会有同样的困扰。其实,知道问题在哪里,就是最好的开始,我把帮助类似A公司解决这些问题的方案整理出来,希望对大家有所帮助。

二、无规则,不成方圆,标准化一切!

什么是标准化?

在讨论标准化是什么之前,我们先来思考这些问题:

  1. 业务维护:手工模式可以维护一套系统的开发、测试和部署,如果是十套,一百套,甚至更多呢?

  2. 业务交接:业务交接代价太高了,能不能让新来的人几分钟就能理解整套系统的维护逻辑?

  3. 服务部署:手工部署很麻烦,搭建环境很痛苦。我可以一键部署,剩下的时间去喝咖啡吗?

标准化可以帮助我们解决以上的这些问题,我对标准化的定义就是:

针对企业内部的业务系统技术栈进行梳理,规划出一套开发和部署规范,并且在各个环境(Dev/Test/Prod)严格执行。

标准化对可变部署模式最为有效,通过标准化,企业内部的每一套系统,每一个环境,都保持一致,然后把规范化后的部署方案整理好,落实到自动化平台,就可以实现自动化部署而无需过多的人工干预。

试想一下,如果是一百套不同的系统,自动化平台根本做不起来,业务维护、交接和部署的成本简直不可想象。
那么问题就来了,如何做标准化?

PS:什么是部署模式?
实际环境中,部署模式分为2种,一种是可变部署模式,一种是不可变部署模式。

可变部署模式:
是指任何的版本变更操作,都会在原来的版本上进行,例如升级、回滚、卸载、安装,这些变更操作会直接影响到原来的版本的服务,技术术语中把使用了可变部署模式的服务器称之为:Mutable Monster Server(随之时间推移逐渐变成不可控的怪物服务器)。

例如:ver1.0 发布之后,更新至ver2.0时,需要把服务器上的ver1.0的服务停止,删除版本文件,然后把 ver2.0的版本文件安装上去,再启动服务;

因此,如果版本回滚的时候,也是同样的操作,把 ver1.0 的安装回去。

不可变部署模式:
不可变部署模式,和可变部署模式相反,一旦当前的版本发布后,就不能再对该版本做任何的操作,如果要进行版本变更操作,就需要重新发布一个新的不可变版本,这些变更操作不会影响原来的版本的服务,不可变部署模式的目前代表是 Docker 镜像发布模式。

例如:ver1.0 的镜像发布后,更新至 ver2.0时,只需要把 ver2.0 的镜像发布出去,运行起来,然后把流量切换到 ver2.0 的容器实例上即可;
因此,如果版本回滚的时候,就把流量切换回去 ver1.0 的容器实例上。

如何做标准化?

我把标准化的实践思想总结为XY轴对象模型,从开发、测试、运维3个角度着手。

例如,以运维的角度来梳理:

  • 梳理Y轴(实体):

    所谓的 Y 轴,是指企业IT系统所遵循的技术栈,从企业的技术栈入手,从宏观上把需要标准化的实体梳理清楚。

    以A公司为例,A公司他们使用了JBOSS作为开发平台,我梳理的Y轴的实体如下:

基础层:

基础层一般指技术栈最为底层依赖的环境,例如:

  1. Java 项目,基础层:OS + JDK;
  2. Python 项目,基础层:OS + Python;
  3. Rails 项目,基础层:OS + Ruby;
  4. ……

A 公司使用了 JBOSS-EAP,因此底层依赖的环境是 OS + JDK:

框架层

框架层一般指技术栈所使用的项目开发框架,可以是开源方案,也可以是自研发框架,例如:

  1. Java 项目,框架层:JBOSS-EAP、Play Framework、Struts 2、Spring等;
  2. Python 项目,框架层:Django、Flask、Falcon、Tornado 等;
  3. 自研发框架;
  4. ……

A 公司使用了 JBOSS-EAP 作为开发框架:

公共组件层(不一定有)

公共组件层一般存放多个组件共享的代码、配置、驱动等,需要按照实际场景进行分析,因此不一定需要。

业务组件层

业务组件层,就是研发同学开发的业务组件,业务组件一般会有:

  1. 代码包;
  2. 配置包;
  3. 运行时数据;
  4. 运行时日志;

  • 梳理X轴(属性)
    所谓的 X 轴,是指企业IT系统每一层技术栈应该遵循的标准,对每一层的技术栈进行深度分析,构建出实体应该具有的属性,例如:部署目录、运行属主、目录/文件属主、目录/文件权限、日志、数据等等。

结合 X 轴,可以得到以下需要标准化的实体/属性表:


例如,A公司针对部署目录这个属性,定制的标准化如下:

可以看看业务组件层的设计细节:

  • 部署标准化执行准则

    结合个人经验,在构建标准化对象模型时,以下的准则是应该遵守的:

    • 启动脚本:应该构建统一的启动脚本,通过传入参数来匹配不同的业务组件;

      run-app.sh 框架提供给所有业务应用的统一启动脚本,用法如下:

      Usage: -n | --name,指定应用名称 -o | --offset,指定应用端口偏移量 -s | --steps,指定应用启动后的检测间隔,每个一个间隔sleep,默认12,即1分钟 -e | --enable_http,启用HTTP检测 -u | --uri, 当启用HTTP检测时,需要自定访问的uri
    • 实体隔离:梳理出来的实体,在部署上必须隔离;
    • 代码包:代码包无状态,一次打包,多环境流转;
    • 配置包:配置包环境相关,和代码包分离,甚至可以实现配置中心来实现统一存取;
    • 数据隔离:数据需要写到数据目录或者数据卷上;
    • 日志实践:日志写到数据或者日志卷上,规范的输出级别、内容格式、日志种类、轮替周期和定期清理。

      综上所述,通过不同的角度来梳理XY的执行规范即可,例如研发也可以根据以下的规则来梳理:

      同样,在测试方面也可以提供业务测试的定制化规范,比如功能测试用例的编写、规划的测试流程(黑盒测试、白盒测试、回归测试以及性能测试)等等,不知道大家是否理解了?^_^

标准化构建平台,持续交付跑起来!

经过标准化建设后,企业内部大部分的系统开发、测试、部署实施规范就差不多大体落地了,接下来我们需要做什么呢?

虽然我们把标准化落实了,但是开发、测试和运维部署依然是孤立和隔离的,版本迭代效率并没有得到太大的提升,例如:

  1. 版本测试、部署依赖文档,团队缺乏协助,然而在现实中,文档通常只是为执行部署者写的备忘录,是难以被他人理解的;

  2. 手工部署环境,既不可重复也不可靠,在调试部署错误的过程中浪费很多时间;

  3. 尽管手工部署枯燥且极具重复性,但风险高,仍需要有相当程度的专业知识,成本高昂的资深技术人员被困于其中,无法投入到更加有价值的工作;

  4. 配置的环境管理依然是手工模式,没有版本跟踪,需要每一个环境的部署都需要文档和口头交流反复确认;
    手工运行已有的集成测试;

  5. ……

持续交付可以解决上述提到的大部分的问题,一般来说,持续交付包括以下 3 个方面的内容:持续集成和持续部署,持续反馈;接下来会跟大家逐步解析。

什么是持续集成?

持续集成,又称为Continuous Integration(CI),根据敏捷大师Martin Fowler的定义:

持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。

从这个定义,我们可以理解到持续集成的关键思想:

  1. 持续集成非常快非常廉价,让 Find Bugs 的时间大幅度降低,提高版本交付效率;
  2. 持续集成让开发者可以有更多的时间在Fix Bugs,而非 Find Bugs;
  3. 持续集成在流水线是全自动化的过程,无需太多的人工干预;
  4. 持续集成是开发团队每个成员的职责,所有版本开发的成果都需要经过集成校验,提高质量;

如何实现持续集成?

随着版本发布的流程,我们来一步一步地规划出一般持续集成具备的基本环节:

  1. 研发同学从 SCM中checkout代码进行日常的版本开发,完成后提交到代码库。

  2. CI Server实时监控代码库分支的变化,一旦检测到分支代码变更,就会自动拉取代码。

  1. CI 服务器会自动编译代码,编译成功后,会运行单元测试。

注意,从编译开始,任何一个环节失败,自动构建都会马上停止,并且把失败信息邮件等方式自动通知研发同学。
这就是CI的反馈能力,帮助研发同学找到bugs,保证版本质量。
到目前为止,我们可以总结一下持续集成的一部分的最佳实践:

  1. 有且仅有一个代码仓库;
  2. 自动化构建;
  3. 使用 TDD 开发模式,编写单元测试和集成测试;
  4. 保证 CI 速度,CI越快,反馈效率越高,找到bugs速度越快,迭代效率越高;
  5. 项目组成员都可以查阅所有的集成构建历史;
  1. 集成测试通过后,版本开始打发布包,自动部署到测试环境,并且运行部署后的测试。

集成测试一般是指CIServer自动运行旧的功能测试用例或者其他固定的测试流程等等;

每一次成功的构建,都会邮件通知项目组,然后测试同学会编写新的功能测试用例、运行性能测试以及选择性的回归测试等等,这也是持续集成流程里面唯一需要人工干预的步骤。

到目前,持续集成基本上结束了,在构建过程中任意一个步骤失败,都会马上停止,并且反馈到研发同学,同时我们也可以总结出剩下的持续集成最佳实践:自动化部署。

上面提到是持续集成的一般流程,给大家介绍持续集成的概念,但是在实际应用中业务环境可能更加复杂,例如:

  1. 公司内部有大量的业务系统,通过API或者API网关关联,研发团队的成员在本地开发某一个组件时,需要开发环境的各大系统来联调;

  2. 为了迭代更快,单元测试、集成测试都可以在开发联调环境来完成,在开发环境构建未通过前无需部署到测试环境;

  3. 自动化部署测试环境后,测试同学会对版本进行更多的手工测试;缺少配置中心对配置进行环境和版本跟踪。

因此,在这里我会推荐一个持续集成生产模型给大家参考一下:

该持续集成模型具有以下的优势:

  1. 本地开发时可以联调开发环境,更加方便的进行代码测试和单元用例的编写,对研发更加友好;

  2. 集成测试提前在开发环境完成,CI 反馈的速度更快;

  3. 开发环境和测试环境隔离,开发环境可能是唯一的,但是测试环境会有多套,主要提供给测试同学执行更多的人工测试,例如性能测试、新的功能用例测试等等;

  4. 测试同学维护开发环境和测试环境中的功能用例,还可以嵌入自动化测试管理系统来辅助管理;

  5. 配置管理的模式有2种:部署平台管理配置,或者是
    直接由单独的配置中心管理配置。

最后,要提醒一下大家,这里只是提供一种比较成熟的思路,切忌生搬硬套,要切合公司的实际情况,梳理代码开发和测试规范,并且应用到持续集成流程中。

持续集成的实践示例

在这小节,我会演示一个简单的例子,来告诉大家持续集成的实践应用。

1. 选择 CI 工具

实现持续集成的工具有很多,例如:Jenkins、Hudson、Travis CI、Build Bot、Strider等等。

其中,Jenkins 是 CI 的主流工具,它的前身是 Hudson,我这里选用 Jenkins 为大家演示案例。

首先要给大家介绍一下在 Jenkins 中的专业名词:

  1. Jenkins 里面的集成构建的基本单位是任务-Task;
  2. 每一次任务的运行,称之为构建-Build,同时会产生一个唯一的BUILD_ID;
  3. 你可以把若干个任务添加到一个视图中,进行归类。

现在,让我们来看看任务里面的具体设置:

2. 设置构建任务

Jenkins 的构建任务分为8个模块,来支撑我们之前提到的持续集成的所有步骤,这里给大家介绍以下核心的模块:

  • General
    顾名思义,这里是设置任务的通用属性,这里简单介绍一下常用的参数:
  1. 丢弃旧的构建
    如果想Jenkins只保留一定数量的构建历史,那么勾选“丢弃旧的构建”进行选择:

  2. 参数化构建过程
    在构建任务中,可以使用自定义全局变量,常用的有选择变量、字符串变量等等:

  3. 串联执行控制
    多个任务之间可以互相触发,串联执行构建,称之为上下游,对上下游的任务进行构建控制:

  • 源码管理
    该模块是设定 SCM 地址和需要进行构建的代码分支,对于许多 SCM,Jenkins 都有插件支持,我在这里选用了 Git:

在这里可以观察到一个任务只能对一个代码分支进行持续集成,在版本开发和分支管理策略上面就需要做好调整:

  1. 主干开发模式比较适合目前的持续集成;
  2. 推荐使用 Git-Flow的代码管理,只需要对Develop分支和Master分支做持续集成,可以很方便地做较长版本发布周期的项目、持续集成和随时发布;

我在这里不展开更多的细节,更多的版本分支管理和发布实践可以参考 IBM 开发文库:《Git 分支管理最佳实践》。

PS:默认 Jenkins 只安装了Git插件,如果需要对其他的SCM进行持续集成,那么需要在“系统管理”-“管理插件”-“可选插件”中进行搜索和勾选安装;

如果 Jenkins 服务器没有联网,还手动下载插件的.hpi安装文件,然后在“系统管理”-“管理插件”-“高级”中上传插件进行手动的安装,安装时注意自己解决依赖。^_^

  • 构建触发器
    触发器非常关键,是实现自动化构建的入口。一般构建触发器会有以下的种类:
  1. 定时构建
    Jenkins的定时构建语法格式和Linux的crontab一样,只不过没有命令列,常见的有以下 2 种模式:

    1. Build periodically:不管源码是否发生变化,周期性地进行项目构建;
    2. Poll SCM:定时检查源码变更(根据SCM软件的版本号),如果有更新就checkout最新code下来,然后执行构建动作。
  2. 依赖构建
    Jenkins 里面可以选择在任意的其他任务构建完毕后,触发当前任务的构建,当然也可以在“构建后操作”模块中触发其他下游的任务进行构建。

  3. 触发构建
    触发构建一般有以下 3 种模式:

    1. Build when a change is pushed to GitHub:当前项目是GitHub项目时,可以勾选此构建,当产生Push操作时,可以定制GitHub上的事件,由GitHub来触发自动构建;

    2. Build when a change is pushed to GitLab:当前项目是 GitLab 项目时,可以勾选次构建,当产生 Push 操作时,可以定制 GitLab 上的事情,由 GitLab 来触发自动构建;

    3. 通 过Remote HTTP API 来触发当前任务的构建:由通过任意的方式,使用 HTTP请求JenkinsAPI接口,可以触发当前任务PROJECTNAME的构建:http://YOURHOST/jenkins/job /PROJECTNAME/build
      这是给用户自由定制触发条件和场合使用的。

  4. 手动构建
    这个就不需要解释了吧,大家手动点一下就好了。

Pre Steps

在进行构建之前你还有什么想要准备的,在这里编写 pre-build step。

Build

顾名思义,在这里执行构建动作,一般的构建动作会包括:编译、运行单元测试,如果需要上传和部署,那么还需要打包

在这里,我给大家演示一下 Maven 项目的构建(mvn package 指令会经历 compile、test 等关键周期,因此编译、单元测试均均会运行):

Post Steps

Post Steps 允许你根据构建的结果,来执行其他操作,构建的结果支持:

1. Run only if build succeeds  2. Run only if build succeeds or is unstable  3. Run regardless of build result

构建设置

在这里,你可以发送邮件通知其他项目组的成员关于本次构建的结果:

构建后操作

本次构建结束后,你还可以执行其他的操作,如下图:

例如之前提到的触发其他任务进行构建,在这里勾选 Build other projects 即可:

又例如,我们在构建成功后,自动上传和部署到开发或者测试环境,在这里设置一下构建后的操作即可:

什么是持续部署?

持续部署和持续集成非常接近,持续部署就在持续集成完成后,自动部署到生产环境。

部署生产环境的能力和部署开发联调环境、测试验证环境一样,但是我们通常做不到生产环境的自动化部署,原因有很多:

1. 商业、市场上的策略,新版本功能披露的时机需要人为控制。  2. 许多组织的测试并不充分,这无法确保一次新的发布能够在没有人工干预的情况下部署至生产环境中。即使这些测试本身是可靠的,但往往没有将这些测试在所有可能在生产环境中出现的相同条件下运行。  3. 生产环境的自动化部署对团队能力要求高,例如研发同学需要编写足够充分的单元测试,关注线上的服务部署状况、测试同学要提前做好新版本的测试准备、运维同学的角色定位在发生变化,将会从枯燥重复的部署操作中解放出来,去实践一个业务运维应该关注的工作——业务监控、业务分析、性能优化等等,这是对公司组织 结构和团队功能的变革。

在很多传统企业的场景下,就算我们做不到持续部署,对开发联调环境和测试验证环境的持续集成的实践已经是非常巨大的进步了。持续部署示例如下(多环节部署、回滚、灰度、升级、调度编排等等):

什么是持续反馈?

在实现了持续集成、持续部署后,我们的版本能够从提交代码后,自动化部署到各个环境而无需人工干预,但是好像还缺少些什么?

是的,没错,我们还缺少持续反馈。

版本上线,我们需要得到持续的反馈:

1. 研发、测试和运维团队关注版本的质量、版本的性能; 2. 运维团队关注目前关联系统的IT运营分析,例如集群容量变化等等; 3. 运营和产品关注新版本带来的产品收益、对用户的影响; 4. ……

我们一般会通过监控平台和日志分析来做持续反馈。

通过监控平台和日志平台的数据分析反馈,我们得到产品的程序性能跟踪、运营的数据分析,这些都可以反馈到提升业务价值上,最终实现了持续交付。

四、端到端监控

监控,是业务发布中非常非常重要的一环,所谓业务上线,监控先行。业务上线的质量以及后续问题跟踪,需要业务监控来保护、发现并且暴露出来。
一般情况下,监控的采集方式有 2种:

1. 动态数据采集:常见于底层数据分析,例如硬件资源使用情况、系统资源使用情况等等; 2. 日志数据采集:常见于业务层数据采集,多维数据采集、分析和监控。

业务监控能力包括以下个方面:

  • 基础监控能力:主机资源(CPU Usage、Memory Usage 等等)的监控;

  • 业务基础监控:业务的端口、进程等;

  • 业务逻辑监控:业务整体流程、单个业务功能点的监控;

  • 业务高级监控:接口API级别的链路调度监控、请求全流程染色跟踪等;

  • 日志多维监控:对日志进行采集、格式化处理和存储、多维度的分析和监控。

在很多传统企业里面,生产环境可能不止是 Linux 服务器,还可能包含大量的 windows 服务器,监控系统需要对这 2个 OS 进行无缝支持:

五、写在最后

持续交付最终的目标,其实也就是IT运营,把IT部门从成本部门的印象中解放出来,变成能够为业务部门提高产品运营和发布效率、提升价值的支撑部门,估计应该是许多 IT 人的梦想吧。

以上提到的在实现持续交付时所需的平台功能,鹿厂优维科技会在新发布的EASYOPS社区版中陆续开放,用户可以终身免费使用,助大家早日实现 IT 运营!

另外,刚听朋友问到监控日志的问题,我下次谈谈监控分析和日志分析的新思路吧。

最后,也是最重磅的,可以免费使用EasyOps一站式运维平台。扫一扫如下二维码即可直接注册享受带来的精益运维能力。

微信群:EasyOps行业交流6群:

别忘了,还有更牛X的“高效运维”等你关注

标签

发表评论