OpenShift中GitOps的深入和思考
为了实现高可用性,不少客户会在生产环境中遇到多集群多实例的部署问题,相对比较简单的做法是分别部署多套独立的集群,然后通过cicd的流水线,比如jenkins把应用发布到不同的多套集群环境中间去,这种做法多了以后,存在的问题也比较明显,主要存在于
- 后端发布的拓扑结构存在于发布流水线脚本中,一旦需要调整,很难运维。
- 中间有后端环境变化,比如需要多加一个集群,那可能还需要修改流水线,重新运行流水线
- 发布结构的一致性很难保证,有时候为了查错或者应对突然的负载情况,修改了应用的实例或者其他配置,这些改动和前期的规划很难保持一致。
分布式环境最大的问题触发点还是在于规模,在很多客户环境下,部署30-50套应用,采用各种方式其实区别是不明显的,因为应用有限,运维的人数也有限,大家基本上对情况有个基本了解。
但一旦部署规模上去以后,在一个大规模的分布式环境中,面对上百上千的应用,我们要考虑的是如何把握所有应用部署的架构,出现问题后如何最快的恢复,随着时间的推移怎样保证部署架构和设计的一致性。
GitOps就是帮助我们去实现Infrasture as a code的利器,他是一个专门针对多集群的环境,采用yaml文件的描述性的持续发布平台。OpenShift gitops主要是基于ArgoCD的组件进行产品化,覆盖了如下的功能:
- 自动化的ArgoCD的安装和升级
- 多集群的配置管理
- 应用部署结构,环境,以及发布历史的管理
- 和OpenShift pipeline(基于teckton)端到端的集成
1.基本部署单元Application(CRD)
作为ArgoCD本身的项目来说,他的部署单元是一个Application(ArgoCD带来的CRD),这个Application的配置主要是包含了四个方面
- 代码的Git Repository
- Revision/Branch
- 部署的集群和命名空间信息
- 同步策略
比较典型的一个例子如下:
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: pricelist-app namespace: argocd spec: destination: namespace: argocd server: https://kubernetes.default.svc project: default source: path: app-of-apps/apps repoURL: https://github.com/christianh814/gitops-examples targetRevision: master syncPolicy: automated: prune: true selfHeal: true
Application的部署支持Helm和Kustomize(缺省), ArgoCD本身就是以Application这个单元为中心的。所以你在ArgoCD里看到的视图也是基于Application来进行展示
Application的问题和限制:
- 每个应用只能定义一个Cluster
- 只有一种资源类型,或者选择git,或者选择helm
- 只能定义一个git repo和helm chart
如果我是在一个实际的环境中,可能是一堆的应用,需要部署在3,5个集群上,那就需要针对这些环境每个都去写Application,如果我有10个应用,那可能就需要写10*5个Application了。。。。
为了解决这个问题,在ArgoCD中引入了ApplicationSets的概念。
2.复杂部署场景下的ApplicationSets
核心点如下:
- App Pattern支持定义批量的应用(用yaml和Helm都可以,一键部署一批)
- 管理Application的生命周期
- 构建Application的Factory模式
主要引入了Generators的概念,主要有三类
- List Generators
- Cluster Generators
- Git Generators
List Generators
简单来看List Generators, 发布应用到多集群
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: bgd namespace: openshift-gitops spec: generators: - list: elements: - cluster: cluster1 url: https://api.cluster1.chx.osecloud.com:6443 - cluster: cluster2 url: https://api.cluster2.chx.osecloud.com:6443 - cluster: cluster3 url: https://api.cluster3.chx.osecloud.com:6443 template: metadata: name: '{{cluster}}-bgd' spec: project: default syncPolicy: automated: prune: true selfHeal: true source: repoURL: https://github.com/christianh814/gitops-examples targetRevision: master path: applicationsets/list-generator/v0.1/overlays/{{cluster}} destination: server: '{{url}}' namespace: bgd
Cluster generator
ArgoCD 将集群信息保存到Secret中间去,因此查看Secret的信息知道目前的集群
$ oc get secrets -n openshift-gitops -l argocd.argoproj.io/secret-type=cluster NAME TYPE DATA AGE cluster-api.cluster1.chx.osecloud.com-74873278 Opaque 3 23m cluster-api.cluster2.chx.osecloud.com-2320437559 Opaque 3 23m cluster-api.cluster3.chx.osecloud.com-2066075908 Opaque 3 23m $ argocd cluster list SERVER NAME VERSION STATUS MESSAGE https://api.cluster1.chx.osecloud.com:6443 cluster1 1.20 Successful https://api.cluster2.chx.osecloud.com:6443 cluster2 1.20 Successful https://api.cluster3.chx.osecloud.com:6443 cluster3 1.20 Successful
构建ApplicationSet
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: bgd namespace: openshift-gitops spec: generators: - clusters: {} # targets all clusters template: metadata: name: '{{name}}-bgd' # the "name" is the name field in the secret spec: project: default syncPolicy: automated: prune: true selfHeal: true source: repoURL: https://github.com/christianh814/gitops-examples targetRevision: master path: applicationsets/cluster-generator/overlays/dev/ destination: server: '{{server}}' # "server" from the field in the secret namespace: bgd
也可以基于label模式部署到特定的集群,比如开发集群。
Git Generators
Git Generators包含两类,一种是目录类型,一种是文件类型,从例子上看,目录类型更多的是针对了部署多个应用,例如
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: pricelist namespace: openshift-gitops spec: generators: - git: repoURL: https://github.com/christianh814/gitops-examples revision: master directories: - path: applicationsets/git-dir-generator/apps/* template: metadata: name: '{{path.basename}}' spec: project: default syncPolicy: automated: prune: true selfHeal: true source: repoURL: https://github.com/christianh814/gitops-examples targetRevision: master path: '{{path}}' destination: server: https://api.cluster1.chx.osecloud.com:6443 namespace: pricelist
在apps下,可以看到三个应用,支持通过不同的模式部署
$ tree applicationsets/git-dir-generator/apps applicationsets/git-dir-generator/apps ├── pricelist-config │ ├── kustomization.yaml │ ├── pricelist-config-ns.yaml │ └── pricelist-config-rb.yaml ├── pricelist-db │ ├── Chart.yaml │ └── values.yaml └── pricelist-frontend ├── kustomization.yaml ├── pricelist-deploy.yaml ├── pricelist-job.yaml ├── pricelist-route.yaml └── pricelist-svc.yaml 3 directories, 10 files
而对于文件方式,需要指定到一个json文件config.json
apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: bgd namespace: openshift-gitops spec: generators: - git: repoURL: https://github.com/christianh814/gitops-examples revision: master files: - path: "applicationsets/git-generator/cluster-config/**/config.json" template: metadata: name: '{{cluster.name}}-bgd' spec: project: default syncPolicy: automated: prune: true selfHeal: true source: repoURL: https://github.com/christianh814/gitops-examples targetRevision: master path: applicationsets/git-generator/overlays/{{cluster.overlay}} destination: server: '{{cluster.server}}' namespace: bgd
$ tree applicationsets/git-generator/ applicationsets/git-generator/ ├── appset-bgd.yaml ├── base │ ├── bgd-deployment.yaml │ ├── bgd-namespace.yaml │ ├── bgd-route.yaml │ ├── bgd-svc.yaml │ └── kustomization.yaml ├── cluster-config │ ├── cluster1 │ │ └── config.json │ ├── cluster2 │ │ └── config.json │ └── cluster3 │ └── config.json └── overlays ├── cluster1 │ ├── bgd-deployment.yaml │ └── kustomization.yaml ├── cluster2 │ ├── bgd-deployment.yaml │ └── kustomization.yaml └── cluster3 ├── bgd-deployment.yaml └── kustomization.yaml
config.json更多的指定了被部署的集群信息。
3.状态的同步
ArgoCD缺省会每个3分钟进行当前状态的同步,如果你直接修改了集群中的配置,比如replicas, 和配置不符会由ArgoCD直接修改过来。
这个同步时间应该是可以设置,暂时没有研究。
4.一些思考
GitOps是一个很好的理念,在ArgoCD中也针对实际的场景进行实现,并且功能继续在增强过程中,但在我目前接触的客户中相对来说比较少的应用,自己觉得主要是几个方面原因:
- 很多客户的部署规模有限,环境复杂性不高,基本运维人员能搞定
- 在生产环境中,大家还是习惯了直接去改,毕竟改一个集群,不会影响到其他的集群,万一出错,还有别的集群顶着,而如果修改git里的配置,那可能会影响到其他集群,带来关联性影响。
关于第二点,我认为更好的办法是生产环境中停掉自动同步功能,在确认修改一个没有问题以后,再通过修改git,通过argocd同步到其他环境。
总的来说,除了多集群发布和同步的功能,我们需要仔细考虑的一点是,如果一觉醒来,当我们的环境出现各种问题,需要重新构建的时候,从平台方出发,我们如何能在最短的时间内将现有的应用重新发布。
我们不太可能要求在让所有应用团队基于流水线都进行一遍发布,那唯一可行的就是,通过gitops定义现有的部署结构的完整视图,然后在新的环境中批量重建,也许这种场景下的最佳办法。