使用Helm在多个Kubernetes集群上部署应用程序


Dailymotion如何使用Kubernetes:应用程序部署


3年前,我们Dailymotion开始在生产中使用Kubernetes。 但是在多个群集上部署应用程序仍然是一种乐趣,因此在过去的几年中,我们尝试改进工具和工作流程。


它从哪里开始


在这里,我们展示了如何在全球多个Kubernetes集群上部署我们的应用程序。


要一次部署多个Kubernetes对象,我们使用Helm ,所有图表都存储在一个git存储库中。 为了从多个服务部署完整的应用程序堆栈,我们使用了所谓的广义图表。 本质上,这是一个声明依赖关系的图表,并允许您使用单个命令来初始化API及其服务。


我们还在Helm之上编写了一个小的Python脚本来进行检查,创建图表,添加机密和部署应用程序。 所有这些任务都是使用docker映像在中央CI平台上执行的。


让我们说清楚。


注意事项 当您阅读本文时,已经宣布了第一个Helm 3发行候选版。 主版本包含一整套改进,旨在解决我们过去遇到的一些问题。

图表开发工作流程


对于应用程序,我们使用分支,我们决定将相同的方法应用于图表。


  • dev分支用于创建将在开发集群上测试的图表。
  • 当池请求转移到master时 ,将在登台中对其进行检查。
  • 最后,我们创建一个池请求,将更改推送到prod分支并将其应用到生产中。

每个环境都有自己的私有存储库,用于存储我们的图表,并且我们将Chartmuseum与非常有用的API一起使用。 因此,我们保证严格隔离环境,并在生产中使用图表之前在实际条件下检查图表。



在不同环境中的图表存储库


值得注意的是,当开发人员发送dev分支时,其图表的版本会自动发送到dev Chartmuseum。 因此,所有开发人员都使用相同的dev存储库,并且您需要仔细指出图表的版本,以免意外使用他人的更改。


而且,我们的小型Python脚本在使用Kubeval将对象发布到Chartmusem之前,根据Kubernetes OpenAPI规范检查Kubernetes对象。


通用图表开发工作流程



  1. 根据gazr.io规范设置管道任务以进行质量控制(皮棉,单元测试)。
  2. 使用部署我们的应用程序的Python工具提交docker映像。
  3. 通过分支名称设置环境。
  4. 使用Kubeval检查yaml Kubernetes文件。
  5. 自动增加图表及其父图表的版本(取决于要更改的图表的图表)。
  6. 向海图博物馆提交与其环境相匹配的海图

集群差异管理


集群联盟


曾经有一段时间我们使用Kubernetes Cluster Federation ,您可以从一个API端点声明Kubernetes对象。 但是有问题。 例如,某些Kubernetes对象无法在联盟的端点创建,因此很难为单个集群维护组合的对象和其他对象。


为了解决该问题,我们开始独立地管理集群,这大大简化了过程(我们使用了联合的第一个版本;在第二个版本中,可能会有所变化)。


地理分布平台


现在,我们的平台分布在6个区域-3个本地区域和3个云区域。



分布式部署


全球掌舵价值观


4个全局Helm值使您能够确定群集之间的差异。 对于我们所有的图表,都有最小默认值。


global: cloud: True env: staging region: us-central1 clusterName: staging-us-central1 

全球价值观


这些值有助于确定我们的应用程序的上下文,并用于不同的任务:监视,跟踪,记录,进行外部调用,缩放等。


  • “云”:我们有一个混合平台Kubernetes。 例如,我们的API部署在GCP区域和数据中心中。
  • “ Env”:对于非工作环境,某些值可能会有所不同。 例如,资源定义和自动缩放配置。
  • “区域”:此信息有助于确定群集的位置,并可用于确定外部服务的最近端点。
  • “ ClusterName”:是否以及何时要确定单个群集的值。

这是一个具体的例子:


 {{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}} {{- define "graphql.hpaReplicas" -}} {{- if eq .Values.global.env "prod" }} {{- if eq .Values.global.region "europe-west1" }} minReplicas: 40 {{- else }} minReplicas: 150 {{- end }} maxReplicas: 1400 {{- else }} minReplicas: 4 maxReplicas: 20 {{- end }} {{- end -}} 

头盔模板示例


在帮助程序模板中定义了此逻辑,以免阻塞Kubernetes YAML。


申请公告


我们的部署工具基于几个YAML文件。 下面是一个示例,说明如何在集群中声明服务及其扩展拓扑(副本数)。


 releases: - foo.world foo.world: # Release name services: # List of dailymotion's apps/projects foobar: chart_name: foo-foobar repo: git@github.com:dailymotion/foobar contexts: prod-europe-west1: deployments: - name: foo-bar-baz replicas: 18 - name: another-deployment replicas: 3 

服务定义


这是定义我们的部署工作流的所有步骤的示意图。 最后一步将应用程序同时部署到多个工作集群。



Jenkins部署步骤


那秘密呢?


在安全性方面,我们跟踪来自各个地方的所有秘密,并将其存储在巴黎唯一的Vault存储库中。


我们的部署工具会从Vault中提取机密值,并在部署时间到来时将其插入Helm中。


为此,我们确定了Vault中的机密与应用程序所需的机密之间的映射:


 secrets: - secret_id: "stack1-app1-password" contexts: - name: "default" vaultPath: "/kv/dev/stack1/app1/test" vaultKey: "password" - name: "cluster1" vaultPath: "/kv/dev/stack1/app1/test" vaultKey: "password" 

  • 我们已经确定了向Vault写入机密时必须遵循的一般规则。
  • 如果机密指向特定的上下文或集群 ,则需要添加特定的条目。 (这里,cluster1的上下文对于密钥stack-app1-password具有其自己的值)。
  • 否则,将使用默认值。
  • 对于此列表中的每个项目,将一个“键值对”插入Kubernetes secret中 。 因此,我们图表中的秘密模式非常简单。

 apiVersion: v1 data: {{- range $key,$value := .Values.secrets }} {{ $key }}: {{ $value | b64enc | quote }} {{ end }} kind: Secret metadata: name: "{{ .Chart.Name }}" labels: chartVersion: "{{ .Chart.Version }}" tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}" type: Opaque 

问题与局限


使用多个存储库


现在,我们分享图表和应用程序的开发。 这意味着开发人员必须在两个git存储库中工作:一个用于应用程序,第二个用于确定其在Kubernetes中的部署。 2个git存储库是2个工作流,对于新手来说很容易混淆。


管理汇总图表很麻烦


正如我们已经说过的,通用图表对于定义依赖关系和快速部署多个应用程序非常方便。 但是,我们使用--reuse-values来避免每次部署此通用图表中包含的应用程序时传递所有值。


在连续交付工作流程中,我们只有两个定期更改的值:副本数和图像标签(版本)。 手动更改其他更稳定的值,这相当复杂。 此外,正如我们从自己的经验中看到的那样,在部署通用图表时出现的一个错误可能会导致严重的故障。


更新多个配置文件


当开发人员添加新应用程序时,他必须更改几个文件:应用程序的公告,机密列表,根据通用图表中是否包含该应用程序来添加应用程序。


Jenkins权限在保险柜中也扩展了


现在,我们有一个AppRole可以从Vault中读取所有机密。


回滚过程不是自动的


要回滚,您需要在多个群集上运行该命令,这充满了错误。 我们手动执行此操作,以确保指定了正确的版本标识符。


我们正在朝着GitOps迈进


我们的目标


我们想将图表返回到它所部署的应用程序的存储库中。


工作流程将与开发相同。 例如,将分支发送到向导后,部署将自动启动。 这种方法与当前工作流程之间的主要区别在于, 所有内容都将在git中管理 (应用程序本身以及如何在Kubernetes中进行部署)。


有几个优点:


  • 对于开发人员来说要清晰得多 。 学习如何将更改应用于本地图表会更容易。
  • 可以服务代码所在的位置指定服务部署定义。
  • 删除广义图表的管理 。 该服务将拥有自己的Helm版本。 这将使您可以最小程度地管理应用程序生命周期(回滚,升级),以免影响其他服务。
  • git用于管理图表的好处是:撤消更改,审核跟踪等。如果需要撤消对图表的更改,则可以使用git进行。 部署将自动开始。
  • 您可能会考虑使用Skaffold之类的工具来改进您的开发工作流程,开发人员可以使用它们在类似生产的环境中测试更改。

两阶段迁移


我们的开发人员已经使用此工作流已有2年了,因此我们需要最轻松的迁移。 因此,我们决定在实现目标的路上增加一个中间阶段。
第一步很简单:


  • 我们维护用于配置应用程序部署的类似结构,但在名为DailymotionRelease的同一对象中。

 apiVersion: "v1" kind: "DailymotionRelease" metadata: name: "app1.ns1" environment: "dev" branch: "mybranch" spec: slack_channel: "#admin" chart_name: "app1" scaling: - context: "dev-us-central1-0" replicas: - name: "hermes" count: 2 - context: "dev-europe-west1-0" replicas: - name: "app1-deploy" count: 2 secrets: - secret_id: "app1" contexts: - name: "default" vaultPath: "/kv/dev/ns1/app1/test" vaultKey: "password" - name: "dev-europe-west1-0" vaultPath: "/kv/dev/ns1/app1/test" vaultKey: "password" 

  • 每个应用程序1个版本(没有通用图表)。
  • git应用程序存储库中的图表。

我们与所有开发人员进行了交谈,因此迁移过程已经开始。 第一阶段仍使用CI平台进行控制。 很快,我将写另一篇关于第二阶段的文章:我们如何通过Flux切换到GitOps工作流程。 我将告诉您我们所有人的设置方式以及遇到的困难(几个存储库,秘密等)。 关注新闻。


在这里,我们试图描述近年来在应用程序部署工作流程中的进展,这引发了人们对GitOps方法的思考。 我们尚未达到目标,并会报告结果,但是现在我们坚信,当我们决定简化一切并使之更接近开发人员的习惯时,我们做对了。

Source: https://habr.com/ru/post/zh-CN458934/


All Articles