大型组织利用GitOps难免会遇到在多环境中部署的问题,本文剖析了应用环境分支策略会遇到到问题,介绍了利用文件夹策略解决这些问题的计划。原文:Stop Using Branches for Deploying to Different GitOps Environments[1], How to Model Your Gitops Environments and Promote Releases between Them[2]
在对于GitOps问题的指南中,咱们简要解释了(参见第3和第4点)以后GitOps工具在反对不同环境部署以及多集群配置建模时的问题。
“如何将公布部署到下一个环境?”的问题在心愿采纳GitOps的组织中越来越受到重视[4],并且有几种可能的答案。但在这篇文章中,咱们将重点探讨在这一过程中不应该做什么。
咱们不应该应用Git分支来建模不同的环境。如果保留配置的Git存储库(在Kubernetes的例子中是manifests/templates)有名为“预发”、“QA”、“生产”等分支,那就掉进了陷阱。
重要的事件说三遍:\
应用Git分支来建模不同的环境是一种反模式,不要这样做!\
应用Git分支来建模不同的环境是一种反模式,不要这样做!\
应用Git分支来建模不同的环境是一种反模式,不要这样做!
咱们将从以下几点探讨为什么这个实际是反模式:
- 在部署环境中应用不同的Git分支是过来的遗留问题。
- 不同分支之间的pull request和合并是有问题的。
- 人们偏向于蕴含特定于环境的代码并创立不同的配置。
- 一旦环境数量增多,环境的保护就会变得难以管制。
- 每个环境的分支模型违反了现有的Kubernetes生态系统。
在不同环境中采纳分支应该只利用于遗留应用程序。
当问到为什么抉择Git分支来建模不同的环境时,答复简直总是“咱们始终都是这样做的”,“感觉很天然”,“这是开发人员晓得的”等等。
这没有错,大多数人都相熟在不同环境中应用分支。这一实际是由古老的Git-Flow模型[3]大力推广的。但自从引入这种模式以来,状况产生了很大的变动,甚至最后的作者也从宏观角度收回了重大正告,倡议人们不要在不理解结果的状况下采纳这种模式。
事实上,Git-flow模型……
- 专一于应用程序源代码,而不是环境配置(更不用说Kubernetes manifest了)。
- 如果须要在生产环境中反对多个利用版本,这一模型很适合,通常没有这种场景,但也时有发生。
因为本文是对于GitOps环境而不是应用程序源代码的,因而不打算在这里过多探讨Git-flow及其毛病,总而言之,如果须要为不同的环境反对不同的个性,那么应该遵循基于骨干的开发[5]并应用个性标记[6]。
在GitOps上下文中,应用程序源代码和配置也应该在不同的Git存储库中(一个存储库只有利用程序代码,一个存储库有Kubernetes manifests/templates)。这意味着应用程序源代码分支不应该影响环境存储库中的分支。
当咱们在我的项目中采纳GitOps时,应用程序开发人员能够为源代码抉择想要的任何分支策略(甚至应用Git-flow),然而环境配置Git存储库(蕴含所有Kubernetes manifests/templates)不应该遵循每个环境一个分支的模型。
部署降级绝不是简略的Git合并
既然咱们曾经理解了在部署中应用按环境辨别分支的办法的历史,就能够探讨其毛病了。
这种办法的次要长处是“部署降级是一个简略的git合并”。实践上,如果想要将一个版本从QA环境降级部署到预发环境,只需将QA分支合并到预发分支即可。当咱们筹备好生产环境时,再次将预发分支合并到生产分支,就能够确定来自预发的所有变更曾经部署到了生产环境中。
想晓得生产环境和预发环境之间有什么不同吗?只须要在两个分支之间做一个规范的git diff[7]就能够了。想要将配置变更从预发环境反向移植到QA环境?从预发分支到QA分支的一个简略的Git合并就能够做到这一点。
如果想对部署降级施加额定的限度,能够应用Pull Requests。一方面任何人都能够触发从QA到预发的合并,另一方面如果想在生产分支中合入一些货色,能够触发Pull Request并要求所有利益相关者手动批准。
这在实践上听起来很棒,一些琐碎的场景实际上能够像这样工作。但在实践中,状况并非如此。通过Git合并来降级一个版本可能会遇到合并抵触、引入不想要的变更,甚至触发谬误的变更程序。
上面咱们以Kubernetes部署为例看一个简略的例子,以后部署位于预发分支中:
apiVersion: apps/v1kind: Deploymentmetadata: name: example-deploymentspec: replicas: 15 template: metadata: labels: app: my-app spec: containers: - name: backend image: my-app:2.2 ports: - containerPort: 80
QA团队曾经告诉咱们说版本2.3(位于QA分支中)看起来曾经筹备好了,能够转移到交付阶段。咱们将QA分支合并到预发分支,部署应用程序,并认为所有都很好。
但咱们不晓得,因为某些资源限度,有人将QA分支中的正本数量更改为2。应用Git合并,不仅将2.3部署到了预发环境,而且还将正本改成了2个(而不是15个),这可能并不是咱们想要的。
你可能会说,在合并之前查看正本个数很容易,但请记住,在理论场景中,有大量的应用程序,其中有大量的manifests被模板化(通过Helm或Kustomize)。因而,了解想要带来什么变动,留下什么变动并不是一件小事件。
即便咱们的确发现了不应该被合并的变更,也须要应用git cherry-pick[8]或其余非标准办法手动抉择“好的”局部,这与最后的“简略的”git合并相去甚远。
然而,即便咱们晓得了所有能够合并的变更,也会呈现合并的程序与提交的程序不同的状况。例如,QA环境上有以下4个更改。
- 更新了利用ingress[9]的主机名。
- 版本2.5被部署到QA环境,所有QA人员开始测试。
- 在2.5版本中发现了一个问题,并修复了Kubernetes的configmap。
- 资源限度[10]进行了微调,并提交到QA分支。
而后咱们决定ingress设置和资源限度应该部署到下一个环境(预发),然而QA团队还没有实现2.5版本的测试。
如果咱们自觉的将QA分支合并到预发分支,就将同时合并所有4个变更,包含2.5的降级。
为了解决这个问题,须要再次应用git cherry-pick或其余手动办法。
在更简单的状况下,提交之间存在依赖关系,因而即便是cherry-pick也帮不上忙。
在下面的示例中,版本1.24必须部署到生产环境。问题是其中一个提交(hotfix)蕴含了大量的变更,而其中某些变更又依赖于另一个提交(ingress配置变更),而后者自身无奈部署到生产环境(因为只实用于预发环境)。因而,即便是精心筛选,也不可能只将所需的变更从筹备阶段引入到生产阶段。
最终的后果是,部署降级绝不是简略的Git合并。大多数组织还领有大量利用,这些利用位于大量集群中,由大量manifests组成,手动抉择变更将是一场失败的战斗。
特定于环境的变更更容易造成配置漂移
实践上,配置漂移不应该成为Git合并的问题。如果在预发环境中进行了变更,而后将该分支合并到生产环境,那么所有变更都应该迁徙到新环境中。
然而在实践中,事件是不一样的,因为大多数组织只向一个方向合并,团队成员很容易扭转上游环境,而从不将这些扭转迁徙到上游环境。
在QA、预发和生产三个环境的经典例子中,Git合并的方向只有一个。人们将QA分支合并到预发,将预发分支合并到生产,这意味着变动只会向上流动。
QA -> 预发(Staging) -> 生产(Production).
典型场景是,在生产环境中须要对配置进行疾速变更(一个hotfix),而后有人部署了该修复程序。在Kubernetes的状况下,这个修补程序能够是任何货色,比方对现有manifest的更改,甚至是一个全新的manifest。
当初生产环境有了一个与预发齐全不同的配置。下次一个版本从长期版本升级到生产版本时,Git只会告诉咱们将从长期版本升级到生产版本。生产上的长期变更永远不会呈现在Pull Request中的任何中央。
因为当初生产中有一个没有文档化的变更,这意味着所有后续部署都可能失败,而这个变更永远不会被任何后续降级检测到。
实践上,咱们能够反向迁徙这些变更,并周期性的将所有提交从生产阶段合并到交付阶段(以及交付阶段合并到QA阶段)。实际上,因为后面提到的起因,这种状况从未产生过。
能够设想,如果有很多环境,就会进一步放大这个问题。
总而言之,通过Git合并来部署公布版本并不能解决配置漂移问题,而且实际上团队会试图做出一些不按程序合并的非凡变更,因而会使问题更加重大。
在大量环境中治理不同的Git分支是一场注定失败的战斗
在后面的所有示例中,我只应用了3个环境(QA环境->预发环境->生产环境)来阐明基于分支的环境部署的毛病。
依据组织的大小,兴许有更多的环境,如果思考地理位置等其余因素,那么环境的数量就会迅速减少。
咱们以某个公司为例,它有5个工作环境:
- 负载测试
- 集成测试
- QA
- 预发
- 生产
咱们假如最初3个环境也部署在欧洲、美国和亚洲,而前2个环境也有GPU和非GPU变体,这意味着该公司共有13个环境,而这只是针对单个利用的。
如果应用基于分支的办法:
- 在任何时候都须要有13个长期Git分支。
- 须要13个pull requests能力跨所有环境部署一个变更。
- 有一个二维的部署降级矩阵,纵向5步,横向2-3步。
- 谬误合并、配置漂移和特地变更的可能性在所有环境组合中都有可能呈现。
在这个示例组织的上下文中,所有以前的问题当初都更加广泛了。
branch-per-environment模型与Helm/Kustomize南辕北辙
形容应用程序的两个最风行的Kubernetes工具是Helm和Kustomize,咱们看看这两种工具如何对不同环境进行建模。
对于Helm,须要创立一个通用chart,该chart自身承受values.yaml模式的参数,如果心愿领有不同的环境,则须要多个values文件[11]。
对于Kustomize,须要创立一个“base”配置,而后每个环境被建模为一个overlay,有本人的文件夹:
在这两种状况下,不同的环境应用不同的文件夹/文件进行建模。Helm和Kustomize对Git分支、Git merge或Pull Requests无所不知,只应用一般文件。
再反复一遍:Helm和Kustomize在不同的环境下应用一般文件,而不是Git分支。这是一个很好的提醒,阐明如何应用这两种工具建模不同的Kubernetes配置。
如果引入Git分支,不仅会引入额定的复杂性,还会违反本人的工具。
在GitOps环境中部署公布的举荐办法
建模不同的Kubernetes环境,并在环境之间部署公布,对于所有采纳GitOps的团队来说都是十分广泛的问题。只管十分风行的办法是在每个环境中应用Git分支,并假如每次部署都是一个“简略的”Git合并,但在本文中曾经看到,这是一个反模式。
上面咱们将介绍一种更好的办法来为不同的环境建模,从而在不同的Kubernetes集群上部署公布,之前的介绍(对于Helm/Kustomize)应该曾经给了你一点对于这种计划的提醒。
上面我会解释如何在同一个Git分支上应用不同的文件夹对GitOps环境进行建模,以及如何通过简略的文件复制操作来解决环境降级(简略的和简单的)。
首先理解应用程序
在创立文件夹构造之前,须要先做一些钻研,理解应用程序的“设置”。只管一些人以通用的形式探讨应用程序配置,但实际上并不是所有的配置设置都同样重要。
在Kubernetes利用的上下文中,咱们有以下几类“环境配置”:
- 容器tag模式的利用版本。这可能是Kubernetes manifest中最重要的设置(就环境降级而言)。依据不同的用例,只需更改容器镜像版本即可。不过有可能源代码中的新变更也须要更改部署环境。
- 利用相干的Kubernetes特定配置。包含利用的正本和其余Kubernetes相干信息,如资源限度、运行状况查看、长久卷、亲和性规定等。
- 根本动态业务配置。这是一组与Kubernetes无关的设置,但与利用业务无关。可能是内部url、外部队列大小、UI默认值、身份验证配置文件等。所谓“根本动态”,我指的是为每个环境定义一次的设置,而后永远不会更改。例如,咱们总是心愿生产环境应用production.paypal.com,而非生产环境应用staging.paypal.com。在不同的环境中,这是一个咱们永远不心愿迁徙的设置。
- 非动态业务配置。和上一点一样,但蕴含了心愿在不同环境之间迁徙的设置,能够是寰球VAT设置、举荐引擎参数、可用的比特率编码,以及任何其余特定于业务的配置。
必须理解所有不同的设置是什么,更重要的是,哪些属于第4类,因为这些是咱们心愿随应用程序版本一起推广的设置。
这样就能够笼罩所有可能的部署场景:
- 利用在QA中从版本1.34降级到1.35,这是一个简略的源代码变更,因而只须要在QA环境中更改容器镜像属性。
- 利用在预发环境中从版本3.23降级到3.24,这不是一个简略的源代码变更,岂但须要更新容器镜像属性,而且从QA环境带来了新的设置“recommender.batch_size”。
我看到很多团队不了解不同配置参数之间的区别,而只应用一个配置文件(或机制)来设置不同域的值(即运行时和利用业务配置)。
有了配置列表以及所属区域之后,就能够创立环境构造并优化须要常常变更并且须要在不同环境之间迁徙的文件复制操作。
5个GitOps环境及其变更示例
咱们来看一个理论的例子。
咱们将对之前提到的环境进行建模,该公司有5个不同的环境:
- 负载测试
- 集成测试
- QA
- 预发
- 生产
咱们假如最初两个环境也部署在欧洲、美国和亚洲,而前两个环境也有GPU和非GPU变体,这意味着该公司共有11个环境。
能够在 https://github.com/kostis-codefresh/gitops-environment-promotion 找到倡议的文件夹构造,所有环境都是同一分支中的不同文件夹,对于不同的环境没有分支。如果想晓得在一个环境中部署了什么,只需查看repo的主分支中的envs/。
在解释构造之前,有一些免责申明:
免责申明1: 写这篇文章花了我很长时间,因为不确定应该探讨Kustomize[12]、Helm[13]还是一般的manifests。我抉择了Kustomize,因为它更简略(在文章的最初我也提到了Helm)。然而请留神,示例repo中的Kustomize模板只是为了演示目标。本文不是Kustomize教程。在理论利用中,你可能有Configmap生成器[14]、定制补丁[15],并采纳和这里展现的齐全不同的“组件”构造。如果你不相熟Kustomize,请先花些工夫了解它的性能,而后再回来。
免责申明2: 我用于部署的利用[16]齐全只是为了演示,它的配置因为简洁和简略的起因而疏忽了几个最佳实际。例如,某些部署短少运行状况查看[17],所有部署都短少资源限度[18]。同样,本文不会探讨如何创立Kubernetes部署,你应该曾经晓得正确的部署manifests是什么样子的。如果想理解更多对于生产级最佳实际的信息,请参阅另一篇文章 https://codefresh.io/kubernetes-tutorial/kubernetes-antipatte...
抛开免责申明不说,上面是存储库的构造:
base目录保留对所有环境通用的配置,不会常常扭转。如果同时对多个环境进行更改,最好应用“variants”文件夹。
variants文件夹(或者叫mixins、components)保留不同环境之间的独特特色。在钻研上一节探讨的应用程序之后,能够自行定义你认为的环境之间的“共同之处”。
在示例利用中,咱们为所有prod和非prod环境以及地区提供了variants。上面是一个实用于所有生产环境的prod variant[19]示例。
---apiVersion: apps/v1kind: Deploymentmetadata: name: simple-deploymentspec: template: spec: containers: - name: webserver-simple env: - name: ENV_TYPE value: "production" - name: PAYPAL_URL value: "production.paypal.com" - name: DB_USER value: "prod_username" - name: DB_PASSWORD value: "prod_password" livenessProbe: httpGet: path: /health port: 8080
在下面的示例中,咱们确保所有生产环境都应用了生产DB凭证、生产领取网关和流动探针(这是一个精心设计的示例,请参阅本节结尾的免责申明2)。这些设置属于咱们不心愿在不同环境之间迁徙的配置集,咱们假如在整个利用生命周期中这些都是动态的。
筹备好base和variants之后,能够用这些属性的组合来定义每个最终环境。
上面是一个ASIA环境的示例[20]:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationnamespace: stagingnamePrefix: staging-asia-resources:- ../../basecomponents: - ../../variants/non-prod - ../../variants/asiapatchesStrategicMerge:- deployment.yml- version.yml- replicas.yml- settings.yml
首先定义一些公共属性,从base环境、非prod环境和asia的所有环境中继承所有配置。
这里的关键点是咱们利用的补丁。version.yml[21]和replicas.yml[22]是自解释的,只定义本人的镜像和正本,其余什么都没有。
version.yml文件(这是环境间最重要的货色)只定义了利用的镜像,其余什么都没有。
---apiVersion: apps/v1kind: Deploymentmetadata: name: simple-deploymentspec: template: spec: containers: - name: webserver-simple image: docker.io/kostiscodefresh/simple-env-app:2.0
咱们心愿在不同环境之间部署的每个版本的相干设置也在settings.yml[23]中定义。
---apiVersion: apps/v1kind: Deploymentmetadata: name: simple-deploymentspec: template: spec: containers: - name: webserver-simple env: - name: UI_THEME value: "dark" - name: CACHE_SIZE value: "1024kb" - name: PAGE_LIMIT value: "25" - name: SORTING value: "ascending" - name: N_BUCKETS value: "42"
请随便查看整个存储库[16],以了解所有kustomizations的结构形式。
通过GitOps执行初始部署
要将应用程序部署到相干的环境中,只需将GitOps控制器指向相应的“env”文件夹,kustomize将创立残缺的settings和values层次结构。
上面是在Staging/Asia中运行的示例应用程序[16]。
能够在命令行上应用Kustomize预览将为每个环境部署的内容,例如:
kustomize build envs/staging-asiakustomize build envs/qakustomize build envs/integration-gpu
当然,也能够将上述命令的输入通过管道输入到kubectl来部署每个环境,但在GitOps的上下文中,应该始终让GitOps控制器部署环境,防止手动kubectl操作。
比拟两个环境的配置
对于软件团队来说,一个十分广泛的需要是了解两个环境之间的不同之处。我看到一些团队有这样的误会,他们认为只有应用分支能力很容易的发现不同环境之间的差别。
这与事实相去甚远。通过比拟文件和文件夹,能够很容易的应用成熟的文件diff工具来查找环境之间的不同之处。
最简略的办法是只辨别对应用程序至关重要的设置。
vimdiff envs/integration-gpu/settings.yml envs/integration-non-gpu/settings.yml
在kustomize的帮忙下,还能够比拟任意数量的环境,获取整体的概念:
kustomize build envs/qa/> /tmp/qa.ymlkustomize build envs/staging-us/ > /tmp/staging-us.ymlkustomize build envs/prod-us/ > /tmp/prod-us.ymlvimdiff /tmp/staging-us.yml /tmp/qa.yml /tmp/prod-us.yml
集体认为这种形式和在环境分支之间执行“git diff”没有什么差异。
如何在GitOps环境中进行部署降级
当初文件构造曾经很分明了,终于能够答复这个古老的问题:“我如何用GitOps部署公布”?
让咱们看看上面一些部署场景。如果你有关注文件构造,应该曾经理解到所有部署降级都能够解析为简略的文件复制操作。
场景: 在美国将利用版本从QA降级到预发环境:
- cp envs/qa/version.yml envs/staging-us/version.yml
- commit/push变更
场景: 从GPU集成测试到GPU负载测试,再到QA的利用版本升级。这是一个两步的过程:
- cp envs/integration-gpu/version.yml envs/load-gpu/version.yml
- commit/push变更
- cp envs/load-gpu/version.yml envs/qa/version.yml
- commit/push变更
场景: 通过额定配置,将应用程序从prod-eu降级到prod-us。这里咱们还复制了settings文件。
- cp envs/prod-eu/version.yml envs/prod-us/version.yml
- cp envs/prod-eu/settings.yml envs/prod-us/settings.yml
- commit/push变更
场景: 确保QA领有与staging-asia雷同的正本数量
- cp envs/staging-asia/replicas.yml envs/qa/replicas.yml
- commit/push变更
场景: 从QA到移植所有配置到集成测试(非gpu版本)
- cp envs/qa/settings.yml envs/integration-non-gpu/settings.yml
- commit/push变更
场景: 一次性对所有非prod环境进行全局更改(但请参阅下一节,以理解对于此操作的一些探讨)
- 在variants/non-prod/non-prod.yml中做出变更
- commit/push变更
场景: 向所有美国环境(包含生产环境和预发环境)增加新的配置文件。
- 在variants/us文件夹中增加新的manifest
- 批改variants/us/kustomization.yml引入新的manifest
- commit/push变更
一般来说,所有的部署降级只是复制操作。与branch-per-environment办法不同,当初能够自在的将任何货色从任何环境推广到其余环境,不用放心进行谬误的变更。特地是当波及到反向移植配置时,environment-per-folder的确很杰出,因为能够简略地“向上”或“向后”挪动配置,甚至能够在不相干的环境之间挪动配置。
留神,我应用cp操作只是为了演示。在理论的应用程序中,此操作将由CI零碎或其余编排工具主动执行。依据环境的不同,你可能想先创立一个Pull Request,而不是间接在主分支中编辑文件夹。
一次对多个环境进行更改
首先,咱们须要定义“多重”环境的确切含意,假如以下两种状况。
- 同时更改同一“级别”上的多个环境。例如,想要同时变更“prod-us”、“prod-eu”和“prod-asia”。
- 同时更改不在同一级别上的多个环境。例如,想同时更改“integration”和“staging-eu”。
第一种状况是无效场景,咱们将在上面探讨。然而,我认为第二个场景是反模式,领有不同环境的关键在于可能以一种渐进的形式公布内容,并推动从一个环境到下一个环境的变动。因而,如果你发现自己在不同的环境中部署了雷同的变动,问问本人是否真的须要这样做以及为什么。
对于部署单个更改到多个“相似”环境的无效场景,有两种策略:
- 如果你确定更改是相对“平安的”,并且心愿立刻利用到所有环境,那么能够在适当的variant(或各自的文件夹)中进行更改。例如,如果你在variants/non-prod文件夹中提交/推送一个更改,那么所有非生产环境都会同时利用这个更改。我集体拥护这种办法,因为有些更改在实践上看起来是“平安的”,但在实践中可能会有问题。
- 更可取的办法是将更改利用于每个独自的文件夹,而后将其挪动到“父”variant(当它在所有环境中都存在时)。
让咱们举个例子。咱们想做一个影响所有EU环境的扭转(例如GDPR性能[24])。简略的办法是将配置更改间接提交/推送到variants/eu文件夹。这的确会影响到所有的EU环境(prod-eu和staging-eu)。然而,这有一点危险,因为如果部署失败,就会导致生产环境解体。
倡议采纳如下办法:
- 首先在envs/staging-eu中做出变更
- 而后对envs/prod-eu做同样的批改
- 最初,从两个环境中删除更改,并将其增加到variants/eu中(通过一个commit/push操作)。
你能够从渐进的数据库重构[25]中意识到这种模式。最初的提交是“过渡性的”,不会以任何形式影响任何环境。Kustomize将在这两种状况下创立完全相同的定义,GitOps控制器应该不会发现任何差别。
这种办法的长处是,当咱们在环境中挪动更改时,能够轻松回滚/复原更改。毛病是须要减少工作(和提交)将更改推广到所有环境,然而我置信这些工作的益处大于危险。
如果采纳这种办法,意味着永远不会间接对base文件夹利用新的更改。如果心愿对所有环境进行更改,则首先将更改利用于单个环境和/或variants,而后将其反向移植到base文件夹,同时将其从所有上游文件夹中删除。
“environment-per-folder”办法的长处
既然咱们曾经剖析了“environment-per-folder”办法的所有外部工作原理,当初就该解释为什么它比“branch-per-environment”办法更好了。如果你曾经看过后面的局部,那么应该曾经了解了“environment-per-folder”办法是如何防止之前剖析的所有问题的。
环境分支最突出的问题是提交的程序,以及从一个环境合并到另一个环境时带来不必要更改的危险。应用文件夹办法,这个问题就齐全打消了:
- 提交程序当初曾经无关紧要了。当你将一个文件从一个文件夹复制到下一个文件夹时,不须要关怀它的提交历史,只须要关怀它的内容。
- 通过只复制四周的文件,只拿须要的货色,而不拿其余货色。当你复制envs/qa/version.yml到env/staging-asia/version.yml中,能够确定只降级了容器镜像,没有其余货色。如果其他人在QA环境中扭转了正本,并不会影响降级流程。
- 不须要应用git cherry-picks或任何其余高级的git办法来降级版本,只须要复制文件,并且能够拜访用于文件解决的实用程序的成熟生态系统。
- 能够自在的从任何环境对上游或上游环境进行任何更改,而不受环境正确“程序”的任何限度。例如,如果想将设置从prod-us反向移植到staging-us,能够简略的将env/prod-us/settings.yml拷贝到env/staging-us/settings.yml,而不必放心可能会无心中部署了不相干的只应在生产环境中利用的修补程序。
- 能够容易的应用文件diff操作来理解各个环境之间的不同之处(源环境和指标环境,反之亦然)
我认为这些劣势对于任何重要的应用程序都是十分重要的,我敢打赌大型组织中总会有几个“失败的部署”能够间接或间接归因于有问题的environment-per-branch模型。
之前咱们提到的第二个问题是,将一个分支合并到下一个环境时,会呈现配置漂移。这样做的起因是,当你执行“git merge”时,git只会告诉你它将带来的更改,而不会通知你指标分支中曾经产生了什么更改。
同样,文件夹计划齐全打消了这个问题。正如后面说的,文件diff操作没有“方向”的概念,能够从任何环境向上或向下复制任何设置,如果对文件执行diff操作,能够看到环境之间的所有更改,而不论它们的上游/上游地位如何。
对于环境分支的最初一点是随着环境数量的增长,分支复杂性将会线性减少。对于5个环境,须要在5个分支之间切换更改,而对于20个环境,须要解决20个分支。在大量的分支之间正确迁徙公布版本是一个繁琐的过程,在生产环境中,这是一场劫难。
应用文件夹办法,分支的数量不仅是动态的,而且只有一个。如果有5个环境,能够用“主”分支来治理,如果须要更多的环境,你只须要增加额定的文件夹。如果20个环境,依然只须要一个Git分支。当只有一个分支时,取得部署的集中视图是很简略的。
在GitOps环境中应用Helm
如果你不应用Kustomize而是更喜爱Helm,也能够创立一个文件夹层次结构,其中蕴含所有环境的“通用”设置,特定的个性/mixins/组件,以及特定于每个环境的最终文件夹。
上面是文件夹构造的样子:
chart/ [...chart files here..]common/ values-common.ymlvariants/ prod/ values-prod.yml non-prod/ Values-non-prod.yml [...other variants…] envs/ prod-eu/ values-env-default.yaml values-replicas.yaml values-version.yaml values-settings.yaml [..other environments…]
同样,你须要花一些工夫来查看利用属性,并决定如何将它们宰割成不同的values文件,以获得最佳的降级速度。
除此之外,在环境降级方面,大多数过程都是一样的。
场景: 在US将利用版本从QA晋升到预发环境:
- cp envs/qa/values-version.yml envs/staging-us/values-version.yml
- commit/push变更
场景: 从GPU集成测试到GPU负载测试,再到QA的利用版本升级。这是一个两步的过程:
- cp envs/integration-gpu/values-version.yml envs/load-gpu/values-version.yml
- commit/push变更
- cp envs/load-gpu/values-version.yml envs/qa/values-version.yml
- commit/push变更
场景: 通过额定配置,将利用从prod-eu晋升到prod-us。这里咱们还复制了settings文件。
- cp envs/prod-eu/values-version.yml envs/prod-us/values-version.yml
- cp envs/prod-eu/values-settings.yml envs/prod-us/values-settings.yml
- commit/push变更
了解Helm(或者你的GitOps代理解决Helm)如何解决多个values文件以及它们互相笼罩的程序也是十分重要的。
如果心愿预览某个环境,能够应用以下命令,而不是“kustomize build”:
helm template chart/ --values common/values-common.yaml --values variants/prod/values-prod.yaml –values envs/prod-eu/values-env-default.yml –values envs/prod-eu/values-replicas.yml –values envs/prod-eu/values-version.yml –values envs/prod-eu/values-settings.yml
能够看到,如果在每个环境文件夹中都有大量的variants或文件,那么Helm比Kustomize更麻烦一些。
environment-per-git-repo办法
当我与大型组织探讨文件夹办法时,听到的第一个拥护意见是,人们(尤其是平安团队)不喜爱看到单个Git存储库中的单个分支同时蕴含产品化和非产品化环境。
这是一个能够了解的拥护意见,能够说是文件夹办法绝对于“environment-per-branch”范式的惟一弱点。毕竟,在Git存储库中爱护各个分支比在单个分支中爱护文件夹要容易得多。
这个问题能够很容易的通过自动化、验证查看甚至手工批准(如果这对你的组织至关重要的话)来解决。我想再次强调,在文件操作中应用“cp”来降级公布版本,只是为了演示的目标,并不意味着当降级产生时,须要在交互式终端中手动运行cp。
现实状况下,应该有一个自动化零碎来复制文件并commit/push它们,能够是继续集成(CI)零碎或处理软件生命周期的其余平台。如果依然有人本人做出扭转,不应该间接commit “main”目录,而是应该发动一个Pull Request,而后通过适当的流程,在合并之前查看Pull Request。
然而,我意识到有些组织对平安问题特地敏感,当波及到Git爱护时,他们更喜爱齐全隔离的办法。对于这些组织,能够应用2个Git存储库,一个保留base配置、所有生产variants和所有生产环境(以及所有与生产相干的货色),而第二个Git存储库保留所有非生产的货色。
这种办法让降级变得有点艰难,因为当初须要在做任何降级之前签出2个git仓库。另一方面,它容许平安团队向“生产”Git存储库搁置额定的平安束缚,并且无论部署到多少环境中,依然领有动态数量的Git存储库(只有2个)。
集体认为这种办法有些过分,至多在我看来,它显示出开发和运维不足信赖。对于人们是否应该间接拜访生产环境的探讨是一个简单的问题,可能须要独自探讨。
拥抱文件夹,遗记分支
心愿通过这篇文章,能够解决在多环境中部署的问题,当初你曾经很好的了解了文件夹办法的益处以及应该应用它的起因。
GitOps部署高兴!
References: \
[1] Stop Using Branches for Deploying to Different GitOps Environments: https://medium.com/containers-101/stop-using-branches-for-dep... \
[2] How to Model Your Gitops Environments and Promote Releases between Them: https://codefresh.io/about-gitops/how-to-model-your-gitops-en... \
[3] Multiple environments(dev, stage, ..,. prod ) example: https://github.com/argoproj/argocd-example-apps/issues/57 \
[4] A successful git branching model: https://nvie.com/posts/a-successful-git-branching-model/ \
[5] Trunk based development: https://trunkbaseddevelopment.com/ \
[6] Feature flags: https://trunkbaseddevelopment.com/feature-flags/ \
[7] git diff: https://git-scm.com/docs/git-diff \
[8] git cherry-pick: https://git-scm.com/docs/git-cherry-pick \
[9] Ingress: https://kubernetes.io/docs/concepts/services-networking/ingress/ \
[10] Manage resources containers: https://kubernetes.io/docs/concepts/configuration/manage-reso... \
[11] Helm deployment evnironments: https://codefresh.io/helm-tutorial/helm-deployment-environments/ \
[12] Kustomize: https://kustomize.io/ \
[13] Helm: https://helm.sh/ \
[14] Configmap generator: https://kubectl.docs.kubernetes.io/references/kustomize/kusto... \
[15] Patches strategic merge: https://kubectl.docs.kubernetes.io/references/kustomize/kusto... \
[16] GitOps promotion source code: https://github.com/kostis-codefresh/gitops-promotion-source-code \
[17] Configure liveness readiness startup probes: https://kubernetes.io/docs/tasks/configure-pod-container/conf... \
[18] Manage resources containers: https://kubernetes.io/docs/concepts/configuration/manage-reso... \
[19] Sample prod: https://raw.githubusercontent.com/kostis-codefresh/gitops-env... \
[20] Sample staging-asia: https://github.com/kostis-codefresh/gitops-environment-promotion/tree/main/envs/staging-asia \
[21] Sample version.yml: https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/version.yml \
[22] Sample replicas.yml: https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/replicas.yml \
[23] Sample settings.yml: https://github.com/kostis-codefresh/gitops-environment-promotion/blob/main/envs/staging-asia/settings.yml \
[24] GDPR: https://gdpr-info.eu/ \
[25] Database refactoring: https://databaserefactoring.com/你好,我是俞凡,在Motorola做过研发,当初在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓重的趣味,平时喜爱浏览、思考,置信继续学习、一生成长,欢送一起交流学习。 \
微信公众号:DeepNoMind
本文由mdnice多平台公布