在上一篇文章中【DevOps】GitOps多环境管理(上) - 别用多分支!,我们介绍了在探索GitOps实践过程中会遇到的一些痛点,其中之一就是难以做到跨环境的版本发布,或者说怎么处理多个集群的部署。
在上一篇文章中,我们已经提到了一些可能的解决方法,但是这些方法都不是十全十美的,其中一个比较流行的做法是通过使用Git的分支来区分不同的环境。在这篇文章中,主要的目的便是劝退抱有这般想法的道友。
上图是一个非常简单的例子,由于需要手动处理合并,就可能会造成各个分支间合并的时间有差异,上图中,dev
环境向staging
环境提交了两次PR
, 然而,在此期间staging
环境没有及时的向production
环境提交PR
, 这就造成了在dev
和staging
上存在过的发布版本从来没有在production
环境上存在过。
在此我想再次重申并强调,一定不要采取使用branch
来区分环境的模式来实践GitOps了,甚至应该把这当成一种反面教材。下面我们将详细的说明这样做的坏处。
不得不说,长久以来,分支模型都被广泛的应用在各种场景中,并且深入人心,以至于大家在遇到问题时,首先考虑使用它来作为解决方案。但是时代在变化,技术在迭代,在GitOps的场景下,它已不再适用。
首先我们要明确, 分支模型关注的问题是什么:
当今流行的Git开发方式是主干开发, 如果需要在生产环境进行feature toggle
, 也推荐大家使用feature flag
的方式来实现。
在GitOps的场景中,应用源代码和部署配置代码应该存放在不同的Git仓库中。 因此,应用源代码仓库采用什么样的分支策略,事实上并不影响我们的配置仓库采用什么样的分支策略。GitOps监测的只是配置仓库的变更并与其同步,因此,我们也不关心源代码仓库采用什么样的分支策略,但是请铭记于心,我们的配置仓库,一定不要继续采用分支模型!
如果不仔细思考,似乎在各分支间提交合并请求来进行跨环境的版本升级已经是个完美的方案。如果想要在staging
环境中部署当前dev
环境的版本,只需要将dev
分支的代码向staging
环境进行合并,同样的,只要把staging
分支的代码向production
分支合并,就能把版本发布到production
环境。
而且,通过使用git diff
命令,我们也非常容易查看各个环境分支间的代码差异。出于安全的考虑,也可以选择在各分支上用PR
的方式进行合并,并对PR
设置审批流程。目前为止,一切听起来都非常令人满意。但这不过是纸上谈兵罢了,在真实的场景下,却是不如意十之八九。用分支代码合并的方式,通常会遇到很多问题,例如代码冲突,一些意料之外的修改,代码变更的顺序不对等等。
举个例子,如下是一个staging
环境中的应用的deployment
清单:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
replicas: 10
template:
spec:
containers:
- name: backend
image: demo-app:1.0
可以看到,在staging
环境中,当前的应用版本是1.0
, 现在QA团队通知我们1.1
版本已经在qa
环境稳定运行了,希望可以在staging
环境中升级到版本1.1
。 按照之前的方式,我们需要做的就是将qa
分支的代码合并到staging
分支,然后就万事大吉了。
但这个世界上总有一些你不知道的事在时时刻刻的发生着,比如,由于资源的限制,在qa
环境上,这个deployment
中的replicas
配置的值为2
, 当代码合并到staging
分支时, 这个值同样也被覆盖了, 于是staging
环境触发部署时,不仅把应用版本更新到了1.1
, 还把这个应用的副本数减少为了2
个(原本是10
个), 如果在生产环境合并时发生这样的问题,那是非常危险的,一些高负载的应用很可能会发生拥塞进而崩溃,导致不可用的发生。
针对这个问题,一定会有人反驳说:“合并请求一定是需要多人审阅并批准的”。但是别忘了,在真实的场景下,应用的数量往往是很多的,对应的配置清单就更多了,而且多数是通过模版生成的,对于人类来说,去了解每一个配置细节,并在每次审阅时清楚的知道每个配置更改是否是期望的,并不是一件容易的事情,非常容易犯错。
再退一步说,即使我们能够完全清楚的知道每一个细节,能够区分哪些更改应该被合并,哪些不应该被合并,那我们还需要选择性的合并某些commit
(使用git cherry-pick
), 这又会带来额外的工作量,就不仅仅是简单的代码合并了。
除此之外,代码的更改与环境所需的更新之间,顺序可能并不同步, 比如,在qa
环境按序做了下面4个更改:
ingress
中新增了一个hostname
qa
环境应用版本升级到了1.2
, QA开始进行测试qa
分支修改了一个configmap
qa
分支上修改了deployemnt
中的resource limit
由于1.2
版本还在测试中,不能发布到staging
环境, 但是ingress
和deployment
中的更改需要推送到staging
环境中去。如果此时简单的把qa
分支的代码向staging
分支合并,上述的4个变更都会被发布到staging
分支,与我们想要的结果不一样。为了解决这个问题,我们还是需要使用git cherry-pick
或其他方式,只将第1和第4个变更合并到staging
分支。
配置漂移是指在多个部署环境中使用的配置不再一致的现象。这种情况通常发生在手动管理部署环境的情况下,其中配置可能会因为不同的人员、工具或过程而发生变化。理论上说,用代码合并的方式做环境升级不应该会出现这样的情况,但实际上却会常常发生。例如,生产环境发现了一个问题需要快速的解决,这时不太可能先在dev
环境上修改配置,再推送到staging
再到production
,常见的情况是会直接在production
上应用一个修复(比如在deployment
清单中的某个很小的配置修改)。
那么,在此之后,staging
分支再向production
分支提交合并请求时,就会发生代码冲突,导致失败。理论上,这样的情况是可以避免的,比如,在production
环境做完修复后,将production
的代码再合并到staging
,再合并到qa
。但是实际上,大多数企业的实践都是单向合并,也就是说,合并只会从低等级的环境向高等级的环境合并(qa
->staging
->production
), 而不会反向进行合并。所以,这种情况仍然是一个很大的问题。
上面说的这些问题,在环境越来越多的情况下,处理的难度会指数级的上升,因此,在GitOps的实践中,一定不要选用分支的方式来管理多个环境。 下一篇文章中,我们会推荐一种在GitOps中进行多环境管理的方式。