`

镜像环境、代码分支、版本发布

阅读更多
本文介绍一下镜像环境的作用,以及版本发布的一些策略

一、镜像环境

所谓镜像环境,是指跟生产环境完全一致的一套环境,包括代码、数据库表结构(或许还包括数据)、配置文件等。镜像环境的作用是用于定位、解决生产环境的问题,或者用于生产环境升级前的验证

当项目实际运行中发现了一个BUG,开发人员就需要一个环境来重现、定位问题。但是一般来说,不可能直接在生产环境上进行定位,以免对业务造成影响。另一方面,如果开发环境的代码和生产环境不一致的话,又无法准确快速地重现、定位问题。所以,镜像环境对系统运维来说,是十分重要的

对于集中部署的WEB应用,或许一套镜像环境就足够了,当然也不一定,根据实际需要,可以搭建任意数量的镜像环境

对于不是集中部署的应用,一般来说需要多套镜像环境。比如说一个系统,假设在局点A和局点B分别部署,那么开发人员就需要有2套镜像环境,分别用来支撑局点A和局点B的运维

二、关于代码分支

代码分支(branch),指的不只是代码,也还包括数据库脚本、配置文件等。代码分支是一把双刃剑,在某些情况下会给开发带来便利,但同时也可能存在很大的维护隐患

举例而言,比如一个项目开发基本完成,处于测试阶段。这个时候在现场有一些定制的需求,那么这种情况怎么办?

如果直接在主干版本上进行定制需求的开发,风险是比较大的。因为这个时候主干版本还处于测试阶段,尚未稳定,所以这个时候在主干上合入定制需求的代码,就有可能发生代码和进度冲突的情况

比如说主干版本计划3月10日转测试,定制需求计划3月15日发布到现场。那么定制需求新合入的代码,就很有可能对主干版本转测试的计划产生冲击。有可能是新代码影响了主版本的功能,也有可能是在3月10日新代码还没有完成(甚至极端一点,还没有办法跑起来或者编译通过),总之定制需求的代码,可能会影响主版本转测试

反过来,如果在修改主版本代码时引入了新问题,也有可能对定制需求的开发产生阻塞,影响定制需求发布的计划。总之,在主版本自身尚未稳定的情况下开发定制需求,是一个高风险的行为

在这种情况下,从主干版本上拉出一个分支,不失为解决问题的一种方法。拉出分支之后,主干版本可以继续进行问题的修改,按照原定的时间表转测试。分支版本上可以进行定制需求新代码的开发,开发完成之后发布到现场

但是,分支版本存在的生命周期一般来说不宜太长。还是用上面的场景作为例子,当主干版本通过测试,已经稳定下来以后,就应该启动定制需求的收编工作,将定制需求的代码合入主干版本中,然后用主干版本替换掉现场的分支版本

因为如果长期同时存在2个版本,随着时间的推移,2套代码就会渐行渐远,到那个时候再进行收编,难度就会非常大,甚至成为不可能完成的任务。总结来说,分支版本存在的时间越长,收编时就需要花费越大的成本

这种情况可以类比代码提交,比如是2个开发人员协作开发一段代码,提交到SVN上。如果2个人都是短周期地更新代码,然后提交,那么代码冲突的可能性就会比较小,即使发生了代码冲突,由于提交的代码不多,要完成代码比对与合并也比较容易。而如果2个人各写各的,半年后再要一起提交,那基本上就是一件不可能完成的事情,至少是很困难的事情

分支版本存在时间太长,除了合并的难度会增大之外,还有一个弊端,就是会增大维护的工作量。在分支版本上发现的BUG,除了需要在分支版本上修改之外,也需要合到主干版本中(这个步骤由于分支代码和主干代码不尽相同,并不是一件很容易的事情),因为以后是需要用主干版本替换分支版本的,如果这时候不合入,那替换的时候,曾经解决的问题就又会重现

或许还有一种方式,就是分支的修改不在主干上同步修改,先用问题列表的方式记录下来,到合入主干的时候再进行修改。不过一般是不推荐这种方式的,因为这只是把修改推迟了,并不会减轻工作量。而且同步修改一般来说,会比事后再修改容易得多。另外这种方式,需要对发现的问题进行持续的记录和跟踪,这也是一个不小的维护成本

另一方面,在主干上发现的问题,一般来说是不需要在分支上也同步修改的。因为以后反正会用主干版本替代分支版本。不过这也不是绝对的,如果主干上的问题,对分支造成了重大的影响,那么一般还是需要同步修改的

总的来说,主干版本和分支版本并存,就需要同时维护2套代码,也就是一个BUG需要在两处修改,维护的工作量相当于是翻倍了

如果从一开始就不打算收编分支版本,而是计划把主版本和分支版本作为两个产品来维护,那么或许情况会好一点,两边发现的问题不需要互相同步

只要有收编分支版本的计划,那么收编版本存在的生命周期就越短越好。一个分支就是一套代码,只要有分支,就有维护成本存在

三、关于版本火车的发布策略

版本火车是我从同事那里听到的一个名词,不知道是不是标准用语,不过我觉得挺形象的。这个词指的是有计划地按批次发布版本,类似于火车的一节节车厢

比如现场提了30个需求,开发人员首先对工作量和开发能力进行评估,然后结合需求的紧急程度,制定出版本发布的计划。比如1月1日交付最紧急的6个需求,然后2月1日交付次要的工作量较小的14个需求,最后在3月1日交付剩余的10个需求

这个和第一点提到的镜像环境有关联。比如1月1日交付了第一批需求之后,研发就需要建立起现场的镜像环境,来定位解决现场发现的BUG,如果之后往现场发布了补丁,镜像环境也需要保持同步更新,总之要保证镜像环境和现场环境的高度一致,这样才方便定位问题

在这个时候,现场跑的代码是代码11,镜像环境也是代码11。开发人员继续在代码11上进行开发(因为后续还要交付代码21),但是镜像环境必须保持稳定,始终保持与现场代码的一致。否则现场发现了一个BUG提交回来,家里的代码已经不一致了,就无法准确的重现及定位问题

然后到了2月1日,将代码21交付到现场之后,家里的镜像环境也需要同步更新到代码21。然后开发人员可以继续在代码21的基础上进行代码31的开发

四、关于升级的方式

升级的方式有两种

比较简单的是全量安装。即每次都将系统的全量安装包发布到现场,现场进行全新安装。这种方式的成本是比较低的,因为不需要考虑升级包的制作,每次装新的就可以了,维护的工作量比较小。不过实际中,这种方式一般是不可行的,因为在两次版本发布之间,现场的系统已经运行了一段时间,肯定已经有大量的业务数据存在,全新安装可能会对业务数据造成破坏,这是不可接受的。当然可以用数据导入导出的方式来进行规避,不过这样就需要对数据进行额外的处理,也是需要工作量的。并且如果2个版本的数据库表结构有变化的话,要进行简单的导入导出就比较困难了

另外一种方式是提供增量补丁。即每次制作升级包,将升级包发布到现场,现场不需要重新安装应用,只需要运行升级包,对应用进行升级。这种方式就需要每次制作一个升级包,将两次版本之间的差异(包括二进制文件、配置文件、数据库脚本、初始化数据等)提取出来

如果多次发布升级包,一般还要考虑把前面的升级包内容,放到后面的升级包里,即所谓的全量升级包。比如说,1月份发布了一个升级包,2月份发布的升级包里,应该把1月份的升级包内容合进来。这样的话,如果需要再搭一套环境,就可以直接跑2月份的升级包,不需要先跑1月份的,再跑2月份的

此外,制作升级包的时候,一般需要考虑升级脚本的容错性、可回滚、可重复执行等

五、一个实际的案例

以我们目前正在开发的系统,结合上文说的4个要素,来综合说明一下

我们的系统三个月前,还处在测试阶段,决定发布到现场进行试用(现在回想起来,我觉得这是一个错误的做法),然后现场提出了一些定制的需求

鉴于当时主版本还处在测试阶段,开发人员还在修改代码,每天都有很多代码合入,在主干上进行定制需求的开发相当困难,所以就决定拉出一个分支,在分支上进行定制需求的开发,然后将分支发到现场。待主版本稳定以后,再把定制需求的代码合入主版本,最后用主版本替换现场的分支版本

对需求进行评估之后,我们决定每30天往现场发布一个版本,分3个批次发布。发布完成之后,主版本的测试阶段就结束了,届时再将定制需求合入主版本,然后用主版本替换掉分支版本(现在看来,分支版本的存在时间达到了3个月,已经是相当长了,合入主版本的时候十分困难)

目前前2个批次的需求已经发到现场,并且这2批新增的代码已经收编到主干版本中。主版本计划于本月底结束测试阶段,然后在下个月替换掉现场的分支版本

所以现在正在测试的,是已经包含前2批需求的主版本,但是现场正在跑的还是分支版本

因此现在我们就面临2个问题:

1、第3批的需求,在分支还是在主干上开发?
2、修改的BUG,应该提交到主干还是分支上?是否需要发补丁到现场?

对于第一个问题:

我们可以在分支上开发,然后用分支的升级包替换现场的分支版本。接下来将第3批需求也合并到主版本上,再用主版本替换分支版本

也可以直接在主版本上开发,届时直接用主版本替换掉分支版本

看起来当然是第2种方式简单很多,但是这样就面临着和3个月前同样的问题,主版本月底才结束测试,我们如果直接在主版本上开发,势必会影响到主版本的测试

所以权衡之后,决定采用一个折中的方案。首先在分支上开发,验证;然后主版本月底测试结束之后,把分支上的代码合入到主版本,最后直接用主版本替换现场的分支版本

对于第二个问题:

首先需要明确一个原则:鉴于很快会用主版本替代分支版本(同时这也意味着分支版本生命周期的结束),分支版本上的修改,一定要在主版本上同步修改;而主版本上的修改,如果不是确实必要,则不应该继续在分支版本上同步修改

这个原则,前者是为了避免替换后已解决的问题重现,后者是为了避免毫无意义的重复劳动

明确这个原则之后,就需要对BUG的来源进行分类:

第一类是在主版本测试中发现的问题,经过上面的分析,显然,这类问题是不需要在分支上同步修改的,只需要保证在主版本中修改通过即可,也不需要发补丁到现场

第二类是现场发现的问题(既包括现场发回的BUG,也包括在现场镜像环境里测出的BUG),对于这类问题,就要复杂一些:

首先可以明确的一点是,问题肯定是要在主干上修改的,否则到主干版本替换之后,问题依然不能解决

那么现在就有2个问题,这类问题是否需要在分支上修改,是否需要发补丁到现场?

仔细分析一下,会发现这2个问题实际上是同1个问题,关键在于:在主版本替换分支版本之前,是否发补丁到现场。

因为如果要发补丁到现场,那么分支必须修改,因为现在现场跑的是分支版本代码,主版本的补丁发不出去;如果不发补丁到现场,那么这段时间在分支上的修改就毫无意义

那么现在就只需要思考一下,在版本替换之前,是否发布补丁到现场?

如果仍然坚持发补丁到现场,那么所有现场问题(包括现场发回的BUG,和镜像环境上测出的BUG),都需要在主干和分支上各修改一遍,维护成本非常高。考虑到很快就要做版本替换,我不认可这种策略的价值

如果不发补丁到现场,那么直到版本替换结束之前,现场的问题就无法解决,这同样也是一个问题,如果阻塞了现场业务,这是不可接受的

综合考虑,我认为采用如下的策略是最优的:

1、所有上述两类问题,都在主干上进行修改
2、第一类问题,不在分支上修改,也不发补丁到现场
3、第二类问题,如果是非阻塞业务的问题,不在分支上修改,也不发补丁到现场
4、第二类问题,如果是阻塞业务的问题,则在分支上修改,并制作补丁发到现场(这部分工作,在一个月内将作废,但是这是保障这个月业务顺利进行必须付出的代价)
分享到:
评论

相关推荐

    开发包换环境

    9. **版本控制**:版本控制系统如Git不仅用于代码管理,还用于跟踪不同环境的分支,如master分支对应生产环境,dev分支对应开发环境,test分支对应测试环境。 10. **配置管理**:环境之间的配置差异需要妥善管理。...

    GitOpsKubernetes多集群环境下的高效CICD实践.pdf

    - 不同环境映射到不同的代码分支,实现环境栈基线的管理。 - 对于线上发布的版本设置特定的基线,通常是代码仓库中的release tag。 3. **权限管理与安全审批:** - 代码更改需经过审查和合并,确保质量的同时也...

    软件发布管理流程规范11范文.doc

    5. **构建与打包**:将源代码编译成可执行程序,并创建安装包或容器镜像,准备发布。 6. **预发布环境验证**:在预生产环境中部署软件,模拟实际运行环境,进行最后的功能验证和性能测试。 7. **发布审批**:由...

    openjdk-jdk8u-backup-06-sep-2018:主服务器上的OpenJDK jdk8u源镜像,在分支“ dev”上具有选择性补丁。 https

    4. **版本分支管理**: "dev"分支通常用于开发新特性和功能,而"master"分支则保持稳定,通常包含已发布的代码。 5. **源代码镜像**: 为确保代码安全和协作效率,通常会进行源代码备份,方便开发者获取和贡献代码。 6...

    node-v8:V8 lkgr上的实验Node.js镜像

    5. **日常版本与仓库**: 提到的仓库可能是指GitHub或其他代码托管平台上的存储库,用于定期发布构建的Node.js镜像。这些日常版本通常频繁更新,反映V8的最新进展,供开发者跟踪和试验。 6. **问题解决与社区参与**:...

    subversion:Apache Subversion的镜像

    构建管理工具如`build-management`可以帮助自动化构建过程,例如使用Apache Ant或CMake,这些工具可以读取Subversion仓库中的信息,自动下载依赖,构建和测试项目,甚至发布版本。 总结起来,Apache Subversion是...

    cpp-Nginx模块用于镜像Google

    "master"通常指的是项目的主分支,意味着这是最新的、未经发布的开发版本,可能包含开发人员的最新改进和修复。 关于这个模块的详细知识点可能包括以下几个方面: 1. **Nginx模块开发**:理解Nginx的模块化体系...

    Git_2.11.1_64官方版本(分享方便国内下载).zip

    这个版本发布于2017年,虽然不是最新的,但对于那些需要特定版本或者兼容性的用户来说,这是一个重要的资源。 Git的核心特性包括: 1. 分布式:与集中式的版本控制系统(如SVN)不同,Git在每个开发者的本地计算机...

    mksh:MirBSD Korn Shell源代码镜像–这是仅发布的存储库,所有拉取请求都将被忽略。 该存储库是一个镜像,可以接收强制更新(非快进)。 请改为贡献MirOS项目的CVS存储库

    首先,我们要明确的是,标题和描述中提到的“存储库”是指Git仓库,而这个mksh源代码镜像是一个只读版本,用于发布目的。开发者不接受拉取请求,而是鼓励对MirOS项目的CVS存储库进行贡献。这表明mksh的开发遵循特定...

    Scintilla:Scintilla-SourceForge发布镜像

    "Scintilla-master"这个文件名可能表示的是Scintilla项目的主分支或最新版本的源代码。在实际开发中,开发者会将这个源代码克隆到本地,然后编译并链接到他们的应用程序中,以利用Scintilla的强大功能。如果想要使用...

    git-flow 的工作流程1

    3. **热修复分支 (Hotfix branches)**:用于修复已发布版本中的紧急问题。从 `master` 分支创建,命名通常以 `hotfix/` 开头,如 `hotfix/1.1.1`。修复完成后,同样需要合并到 `master` 和 `develop`,确保修复的...

    藏经阁-GitOps之应用安全发布模型实践.pdf

    3. **权限管理与安全审批**:通过设置保护分支和Merge Request,确保生产环境的变更必须经过严格的审查和批准,增加了发布过程的安全性。 4. **自动化工作流**:集成持续集成/持续部署(CI/CD)工具,如Jenkins、...

    Firefox火狐浏览器官方52.8.0esr-mac版本dmg安装包

    52.8.0esr版本是Firefox的一个重要分支,专为企业用户和需要长期稳定支持的环境设计,被称为Extended Support Release(ESR)。这个版本在发布后的一段时间内会持续收到安全更新,而功能更新则相对较少,确保了系统...

    pip-21.3.1.tar.gz

    - `git`或`svn`:pip可以直接从Git或Subversion仓库安装包,这在开发自定义版本或跟踪特定分支时非常有用。 - `-e`或`--editable`:允许你以可编辑模式安装包,这样在源代码更改后,无需重新安装即可看到变化。 6...

    GitOps之应用安全发布模型实践.pptx

    在这种情况下,GitHub作为代码仓库,Knative Build用于构建容器镜像,ArgoCD则作为声明式应用部署工具,它可以从GitHub中拉取配置并自动同步到Kubernetes集群,确保生产环境始终与Git中的定义一致。 总结来说,...

    分支模型

    - 在准备发布新版本时,从开发分支创建发布分支,用于进行发布前的测试和调试。此分支上的修改仅限于bug修复和必要的调整,以确保稳定性和兼容性。 6. **Hotfix分支**: - 当生产环境中出现紧急bug需要立即修复时...

    gitlab-v8.8.5

    具体的改变可以通过查看该版本的发布日志来了解。提供的压缩文件“gitlab-v8.8.5.zh1-c0c194a81b7b90089e43edfe51d1ecd6809fe9ba”可能是 GitLab 的中文语言包,用于支持中文界面,方便中文用户使用。为了安装和运行...

    Firefox火狐浏览器官方52.6.0esr-mac版本dmg安装包

    此版本是Extended Support Release(ESR)的分支,意味着它提供更长期的更新和支持,主要针对企业环境和那些需要稳定、安全浏览体验的用户。以下是关于这个版本的一些关键知识点: 1. **Firefox 52.6.0esr**: 这个...

    Android 开发环境下载

    SDK组件是开发Android应用的关键,包括不同版本的Android平台、SDK工具和模拟器系统镜像等。 4. **SDK Manager** 在Android Studio中,可以通过"Tools" -> "Android" -> "SDK Manager"来管理SDK组件。在这里,你...

    mac下svn与svk整合

    1. **Apache服务器**: 首先需要安装Apache服务器,可以选择直接下载Apache官方发布的版本,或者使用XAMPP这样的集成开发环境,它包含了Apache、MySQL等组件。 2. **SVN**: 下载并安装SVN,主要目的是获取`mod_dav_...

Global site tag (gtag.js) - Google Analytics