Skip to content

09 集群组件管理:自动化之道,轻松管理百个集群

你好,我是潘野。

通过前面的课程,我们学习了通过GitOps的方式来管理公有云里的资源,也顺利地启动了一个Kubernetes集群。

但是在真正的生产环境中,一个“光秃秃”的集群业务人员是无法使用的。比如业务需要Ingress来对外暴露流量,SRE需要集群内有Prometheus来监控整个应用的状态。所以像Ingress、Prometheus这些组件依然属于基础设施的管理范畴。也就是说,快速、可靠和可重复的管理Kubernetes集群组件也是IaC中的一环。

我们不妨试着想象一下,假如你是公司Kubernetes平台管理员,需要管理100个Kubernetes集群,而每个集群都有10个组件的时候,你应该如何来做呢?

常见的Kubernetes集群组件

我们先看看交付给业务团队使用的Kubernetes集群一般需要哪些组件。

这些组件分成两类,一类是控制平面组件,一类是数据平面组件。控制平面的组件里面涉及到网络插件、安全组件等,数据平面的组件主要是以Ingress、cert-manger和Grafana这样的业务辅助组件为主。我将常用的Kubernetes集群组件用表格的形式列在下面,供你参考。

前面我们预设的场景是100个集群,每个集群10个组件,那么一共就有1000个组件。我们来分析一下有哪些通用的管理需求,主要是三类。

  1. 组件类型管理:因为100个集群可能因为用途不同,就需要针对性的安装不同的组件。例如给AI用的GPU集群就需要安装device-plugin这些组件,而普通集群显然不需要这样的组件。
  2. 组件版本管理:这100个集群的Kubernetes版本可能不一样,那么依赖的组件版本也会不一样。例如HPA的API version在1.21时候是v2beta1,但是到了1.24之后就升级到了v2,那么在1.21集群上涉及到HPA的组件可能就不能安装最新版本。
  3. 组件功能管理:我们还得考虑不同环境下组件配置不一样的问题。比如在测试环境的集群,我们需要开启组件的一些功能来做测试,而到了正式的生产环境,这些组件中用来测试的功能就需要关闭。

基于这三类的需要,我们怎么做才能同时实现需求定制,还有集中管理组件这两个要求呢?

如何按需定制集群组件

其实我们仔细想一想,这100个Kubernetes集群,即便是业务场景不同,但是其中部分集群组件都是一样的。

我们结合自己的经验,很容易就能找到一些共性规律。比如说,集群总需要监控吧?那么就需要采集节点状态node-exportor;再比如,应用总需要对外暴露自己服务的访问地址吧?那么ingress-controller也是必不可少的,所以这些属于必要组件。

和必要组件相对应,还有一些是可选的功能。比如说,虽然我们要对所有集群进行监控,但是查看监控数据的组件Grafana并不是每个集群都要安装,只需要安装在某一个集群即可,所以这类组件就属于可选组件。

那么我们是不是可以维护一个集合,来表述一个集群需要安装哪些组件呢?为了帮你理解这个集群组件集合如何实现,我们来看一段非常简单的yaml配置文件示例。

---
addons:
  ingress:
    enabled: true
  grafana:
    enabled: false
  node-exportor:
    enabled: true

熟悉helm的同学,看到这里是不是觉得有点眼熟?在helm的values.yaml中,我们经常会看到 enabled: false 或者是 enabled: true 这个字段?既然在helm中我们可以使用 enabled 这个关键词来决定是否开启功能,那我们是不是也可以套用在这里呢?

这肯定是可以的。这时候我们还需要配套使用一个 技巧,这个技巧来自官方文档。

The current best practice for composing a complex application from discrete parts is to create a top-level umbrella chart that exposes the global configurations, and then use the charts/ subdirectory to embed each of the components.

中文翻译过来就是:

构建复杂应用的最佳实践是创建顶层的伞状 Chart (umbrella chart),用于暴露全局配置,然后使用 charts/ 子目录嵌入每个组件。

那么如何理解顶层的umbrella chart呢?

结合我们上面示例的yaml配置文件,addons这个顶层的伞状chart,在addons这个chart里,会通过 enabled 这个字段来决定是否在集群上启用这些组件。你可以结合下图来理解原理。

那么问题来了,在顶层的chart中包含子系统的chart,这个需求要如何实现呢?

我们需要结合部署集群组件的过程来找到答案。接下来,我们就分三步走,先从部署单个集群组件入手,然后升级到同时部署多个集群组件,最后再进入如何部署多个集群的组件。

ArgoCD:如何部署单个组件

我们一般会通过Helm配合ArgoCD这个工具来部署 单个 集群组件。这里我以部署Grafana为例,快速地讲一下ArgoCD部署单个组件的过程,一共分两步。

第一步,在ArgoCD中配好Helm的仓库。你可以通过ArgoCD的UI来添加Helm仓库,也可以通过命令行来添加仓库。这里的操作也很简单,我们先在UI中点击settings -> Repositories -> connect repo,然后选择repo的类型为helm,再填上repo的URL即可。

当正确配置了helm repo之后,ArgoCD中就会显示successful的提示。

第二步,通过UI或者Kubernetes命令行创建ArgoCD的Application,配置好相关参数即可部署。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: grafana
  namespace: argocd
spec:
  destination:
    namespace: addons-system
    server: https://Kubernetes.default.svc
  project: default
  source:
    chart: grafana
    repoURL: https://grafana.github.io/helm-charts
    targetRevision: 7.2.4
  syncPolicy:
    automated: {}

完成上面的步骤以后,最终我们就会看到Grafana部署在了集群中,如下图所示。

umbrella chart - 管理集群所有组件

一个组件是这样部署的,其他组件也同理,也就是说,所有的集群组件都可以通过Helm配合ArgoCD部署。而umbrella chart要做的事情,就是根据 enabled 这个字段,渲染出所需要的Application,这样不就可以解决我们的需求了吗?

我们这就来看看具体实现思路,我们先为ArgoCD的Application这类资源自定义一个helm chart包,将变化的参数转变成可配置的value。你可以先看看下面的配置示例 ,再听我分析。

在template中grafana.yaml中,我们用 addon.enabled 来控制helm是否渲染出这个配置文件,如果enabled是true,那么接下来会根据values.yaml里面的值生成真正的ArgoCD的配置文件。下面是grafana argocd application的样例代码:

{{- $addon := .Values.addons.grafana }}
{{- if $addon.enabled }}
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: {{ $addon.names.app }}
  namespace: argocd
spec:
  destination:
    namespace: {{ $addon.namespace | default "addons-system" }}
    server: https://Kubernetes.default.svc
  project: default
  source:
    chart: {{ $addon.names.chart }}
    helm:
      valueFiles:
      - values.yaml
    repoURL: {{ $addon.repoURL}}
    targetRevision: {{ $addon.targetVersion }}
  syncPolicy:
    automated: {}
  {{- end }}

基于上面的样例代码,我们发现在helm中的value定义无非就是这么几个参数,分别用来说明是否在集群中启用,chart的仓库地址,还有需要在集群中安装哪个版本等等信息。你可以参考后面这个例子看一下。

grafana:
  enabled: false
  names:
    app: grafana
    chart: grafana
  repoURL: https://grafana.github.io/helm-charts
  targetVersion: 7.2.4

如何集中化管理集群组件

前面,我们解决了集群组件定制的需求,那么我们如何通过一份代码来管理100个集群的组件呢?

Helm里的values.yaml是可以采用层层递进式覆盖的。你可以结合后面这个配置案例来理解。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: addons
  namespace: argocd
spec:
  destination:
    namespace: addons-system
    server: https://Kubernetes.default.svc
  project: default
  source:
    chart: addonsmgr
    helm:
      valueFiles:
        - values.yaml
        - values/aks/infra.yaml
    repoURL: https://cloudnative-automation.github.io/addon-manager/repo
    targetRevision: 0.1.*
  syncPolicy:
    automated: {}

可以看到,我们只要为每个集群单独配置一个values.yaml,就能控制集群可以安装哪些组件。这是因为valueFiles会默认读取chart包中的values.yaml,并覆盖掉默认的values。

例如,我们在 values/aks/infra.yaml 中定义了Grafana开启,而ingressNginx则没有开启,这样就能精细地控制这个集群可以安装哪些组件。

---
clusterURL: infra-dev.hcp.japaneast.azmk8s.io

addons:

  grafana:
    enabled: true

  ingressNginx:
    enabled: false

效果图

让我们来看下这样做的效果如何。

对照截图可以看到,addons是顶层的umbrella chart,在这个集群中,Grafana是它的子chart。详细代码我已经放在 GitHub 上,你可以结合我前面的讲述来深入理解。

看到这里,有同学可能会问,想要建立100个集群,岂不是要执行100次创建命令了么?

这一点其实你无需担心。在工作中,我们同时建立的集群一般不超过10个。我们只是在集群初始化时,才会去创建这个addons的application,部署addons这个顶层chart。之后,ArgoCD将会通过 targetRevision: 0.1.* 这样的方式来监听Helm仓库的变化,一旦有新的版本出现,便会自己同步过来,进行更新。

如何维护helm chart的仓库地址

除了创建命令执行的自动化,对于helm char的仓库地址的维护,我们也可以自动化实现。

我们可以看到,每个子chart都有一个repoURL的配置,常用的管理方式有两种方式。

第一种是自己维护一个chart repo,将所有需要安装的chart包导入自己维护的repo中,同学们可以参考课程 GitHub仓库 中关于自建chart仓库的说明。

第二种是依然使用原始chart的仓库地址,这里需要保证集群环境网络对外的连通性。

source:
  chart: grafana
  repoURL: https://grafana.github.io/helm-charts
  targetRevision: 7.2.4

无论是哪一种管理方式,都需要提前将Chart的Repositories导入ArgoCD。这一讲里我已经写了如何在ArgoCD中导入仓库的方法,这步动作也是在集群初始化的时候先完成,你可以把后面这段代码放在Terraform的代码中。

resource "repo_resource" "add helm repos" {

  provisioner "local-exec" {
    command = <<EOF
      argocd repo add https://charts.jetstack.io --username devops;
    EOF

    environment = {
      AWS_REGION = var.region
    }
  }

GitOps维护

讲到这里,我们已经完成了所有的工作。

如果我们想在某个集群里打开一个组件,应该如何操作呢?

例如我们在集群中打开cert- manager这个组件,只需要提交一个PR,经过代码的审核,然后merge进代码主干。

这样就能触发GitHub Action的流水线,将我们的Chart自动打包并上传到镜像仓库,ArgoCD监测到chart版本变化之后开始更改集群组件配置。

如果我们需要回滚某个配置,只需要重新提交一个git revert的PR,之后GitHub Action的流水线以及ArgoCD会遵循同样的方法部署出去。

进行到这里,我们实践了如何用GitOps方式来管理Kubernetes集群配置。在这个 仓库 里,你可以看到整个集群的配置更改历史,都显示在Git的commit中,而且使用了Git作为唯一真实数据源的运维模式。

这种方式提供了版本控制、审计日志以及回滚等功能,完整地实现了我们在课程最初提出来的 快速可靠可重复 的部署和管理过程。

总结

今天这一讲是基础架构自动化管理中相当重要的一节课。

我们的目标是让Kubernetes基础组件既可以按需求定制,又能够集中管理。为此,我们从我们umbrella chart切入为你做了详细演示。

我们先从部署单个集群组件入手,然后升级到同时部署多个集群组件,最后再进入如何部署多个集群的组件。

由此,我们就解决了基础设施自动化管理的最后一公里 ,也就是Kubernetes集群交付。同时也遵循了我们在课程最初提出的 快速可靠可重复 的部署和管理过程。

到今天为止,我们完成了基础设施即代码环节,但是目前我们仅仅完成了交付给业务使用的环节。在此基础上,我们如何保证交付的基础设施的可用性与稳定性呢?这些问题后面我们再继续讨论,敬请期待。

思考题

请你根据 代码仓库 里提供的样例,来完成其他集群组件的部署。

---
clusterURL: 127.0.0.1

addons:

  namespaces:
    default: addons-system

  grafana:
    enabled: false
    names:
      app: grafana
      chart: grafana
    repoURL: https://grafana.github.io/helm-charts
    targetVersion: 7.2.4

  ingressNginx:
    enabled: false
    names:
      app: ingress-nginx
      chart: ingress-nginx/ingress-nginx
    repoURL: https://kubernetes.github.io/ingress-nginx
    targetVersion: 4.9.0

欢迎在评论区与我讨论。如果这一讲对你有启发,也欢迎分享给身边更多朋友。