Version: v1.2

GitOps 交付

本案例将介绍如何在 GitOps 场景下使用 KubeVela,并介绍这样做的好处是什么。

简介

GitOps 是一种现代化的持续交付手段,它允许开发人员通过直接更改 Git 仓库中的代码和配置来自动部署应用,在提高部署生产力的同时也通过分支回滚等能力提高了可靠性。其具体的好处可以查看这篇文章,本文将不再赘述。

KubeVela 作为一个声明式的应用交付控制平面,天然就可以以 GitOps 的方式进行使用,并且这样做会在 GitOps 的基础上为用户提供更多的益处和端到端的体验,包括:

  • 应用交付工作流(CD 流水线)
    • 即:KubeVela 支持在 GitOps 模式中描述过程式的应用交付,而不只是简单的声明终态;
  • 处理部署过程中的各种依赖关系和拓扑结构;
  • 在现有各种 GitOps 工具的语义之上提供统一的上层抽象,简化应用交付与管理过程;
  • 统一进行云服务的声明、部署和服务绑定;
  • 提供开箱即用的交付策略(金丝雀、蓝绿发布等);
  • 提供开箱即用的混合云/多云部署策略(放置规则、集群过滤规则等);
  • 在多环境交付中提供 Kustomize 风格的 Patch 来描述部署差异,而无需学习任何 Kustomize 本身的细节;
  • …… 以及更多。

在本文中,我们主要讲解直接使用 KubeVela 在 GitOps 模式下进行交付的步骤。

交付的面向人员有以下两种,我们将分别介绍:

  1. 面向平台管理员/运维人员的基础设施交付,用户可以通过直接更新仓库中的配置文件,从而更新集群中的基础设施配置,如系统的依赖软件、安全策略、存储、网络等基础设施配置。
  2. 面向终端开发者的交付,用户的代码一旦合并到应用代码仓库,就自动化触发集群中应用的更新,可以更高效的完成应用的迭代,与 KubeVela 的灰度发布、流量调拨、多集群部署等功能结合可以形成更为强大的自动化发布能力。

提示:你也可以通过类似的步骤使用 ArgoCD 等 GitOps 工具来间接使用 KubeVela,细节的操作文档我们会在后续发布中提供。

面向平台管理员/运维人员的交付

如图所示,对于平台管理员/运维人员而言,他们并不需要关心应用的代码,所以只需要准备一个 Git 配置仓库并部署 KubeVela 配置文件,后续对于应用及基础设施的配置变动,便可通过直接更新 Git 配置仓库来完成,使得每一次配置变更可追踪。

alt

准备配置仓库

具体的配置可参考 示例仓库

在本例中,我们将部署一个 MySQL 数据库软件作为项目的基础设施,同时部署一个业务应用,使用这个数据库。配置仓库的目录结构如下:

  • clusters/ 中包含集群中的 KubeVela GitOps 配置,用户需要将 clusters/ 中的文件手动部署到集群中。这个是一次性的管控操作,执行完成后,KubeVela 便能自动监听配置仓库中的文件变动且自动更新集群中的配置。其中,clusters/apps.yaml 将监听 apps/ 下所有应用的变化,clusters/infra.yaml 将监听 infrastructure/ 下所有基础设施的变化。
  • apps/ 目录中包含业务应用的所有配置,在本例中为一个使用数据库的业务应用。
  • infrastructure/ 中包含一些基础设施相关的配置和策略,在本例中为 MySQL 数据库。
  1. ├── apps
  2. └── my-app.yaml
  3. ├── clusters
  4. ├── apps.yaml
  5. └── infra.yaml
  6. └── infrastructure
  7. └── mysql.yaml

KubeVela 建议使用如上的目录结构管理你的 GitOps 仓库。clusters/ 中存放相关的 KubeVela GitOps 配置并需要被手动部署到集群中,apps/infrastructure/ 中分别存放你的应用和基础设施配置。通过把应用和基础配置分开,能够更为合理的管理你的部署环境,隔离应用的变动影响。

clusters/ 目录

首先,我们来看下 clusters 目录,这也是 KubeVela 对接 GitOps 的初始化操作配置目录

clusters/infra.yaml 为例:

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: Application
  3. metadata:
  4. name: infra
  5. spec:
  6. components:
  7. - name: database-config
  8. type: kustomize
  9. properties:
  10. repoType: git
  11. # 将此处替换成你需要监听的 git 配置仓库地址
  12. url: https://github.com/FogDong/KubeVela-GitOps-Infra-Demo
  13. # 如果是私有仓库,还需要关联 git secret
  14. # secretRef: git-secret
  15. # 自动拉取配置的时间间隔,由于基础设施的变动性较小,此处设置为十分钟
  16. pullInterval: 10m
  17. git:
  18. # 监听变动的分支
  19. branch: main
  20. # 监听变动的路径,指向仓库中 infrastructure 目录下的文件
  21. path: ./infrastructure

apps.yamlinfra.yaml 几乎保持一致,只不过监听的文件目录有所区别。 在 apps.yaml 中,properties.path 的值将改为 ./apps,表明监听 apps/ 目录下的文件变动。

cluster 文件夹中的 GitOps 管控配置文件需要在初始化的时候一次性手动部署到集群中,在此之后 KubeVela 将自动监听 apps/ 以及 infrastructure/ 目录下的配置文件并定期更新同步。

apps/ 目录

apps/ 目录中存放着应用配置文件,这是一个配置了数据库信息以及 Ingress 的简单应用。该应用将连接到一个 MySQL 数据库,并简单地启动服务。在默认的服务路径下,会显示当前版本号。在 /db 路径下,会列出当前数据库中的信息。

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: Application
  3. metadata:
  4. name: my-app
  5. namespace: default
  6. spec:
  7. components:
  8. - name: my-server
  9. type: webservice
  10. properties:
  11. image: ghcr.io/fogdong/test-fog:master-cba5605f-1632714412
  12. port: 8088
  13. env:
  14. - name: DB_HOST
  15. value: mysql-cluster-mysql.default.svc.cluster.local:3306
  16. - name: DB_PASSWORD
  17. valueFrom:
  18. secretKeyRef:
  19. name: mysql-secret
  20. key: ROOT_PASSWORD
  21. traits:
  22. - type: ingress
  23. properties:
  24. domain: testsvc.example.com
  25. http:
  26. /: 8088

infrastructure/ 目录

infrastructure/ 目录下存放一些基础设施的配置。此处我们使用 mysql controller 来部署了一个 MySQL 集群。

注意,请确保你的集群中有一个 secret,并通过 ROOT_PASSWORD 声明了 MySQL 密码。

  1. apiVersion: core.oam.dev/v1beta1
  2. kind: Application
  3. metadata:
  4. name: mysql
  5. namespace: default
  6. spec:
  7. components:
  8. - name: mysql-controller
  9. type: helm
  10. properties:
  11. repoType: helm
  12. url: https://presslabs.github.io/charts
  13. chart: mysql-operator
  14. version: "0.4.0"
  15. - name: mysql-cluster
  16. type: raw
  17. dependsOn:
  18. - mysql-controller
  19. properties:
  20. apiVersion: mysql.presslabs.org/v1alpha1
  21. kind: MysqlCluster
  22. metadata:
  23. name: mysql-cluster
  24. spec:
  25. replicas: 1
  26. # 关联 secret 名称
  27. secretName: mysql-secret

部署 clusters/ 目录下的文件

配置完以上文件并存放到 Git 配置仓库后,我们需要在集群中手动部署 clusters/ 目录下的 KubeVela GitOps 配置文件。

首先,在集群中部署 clusters/infra.yaml。可以看到它自动在集群中拉起了 infrastructure/ 目录下的 MySQL 部署文件:

  1. vela up -f clusters/infra.yaml
  1. $ vela ls
  2. APP COMPONENT TYPE TRAITS PHASE HEALTHY STATUS CREATED-TIME
  3. infra database-config kustomize running healthy 2021-09-26 20:48:09 +0800 CST
  4. mysql mysql-controller helm running healthy 2021-09-26 20:48:11 +0800 CST
  5. └─ mysql-cluster raw running healthy 2021-09-26 20:48:11 +0800 CST

接着,在集群中部署 clusters/apps.yaml,可以看到它自动拉起了 apps/ 目录下的应用部署文件:

  1. vela up -f clusters/apps.yaml
  1. APP COMPONENT TYPE TRAITS PHASE HEALTHY STATUS CREATED-TIME
  2. apps apps kustomize running healthy 2021-09-27 16:55:53 +0800 CST
  3. infra database-config kustomize running healthy 2021-09-26 20:48:09 +0800 CST
  4. my-app my-server webservice ingress running healthy 2021-09-27 16:55:55 +0800 CST
  5. mysql mysql-controller helm running healthy 2021-09-26 20:48:11 +0800 CST
  6. └─ mysql-cluster raw running healthy 2021-09-26 20:48:11 +0800 CST

至此,我们通过部署 KubeVela GitOps 配置文件,自动在集群中拉起了应用及数据库。

通过 curl 应用的 Ingress,可以看到目前的版本是 0.1.5,并且成功地连接到了数据库:

  1. $ kubectl get ingress
  2. NAME CLASS HOSTS ADDRESS PORTS AGE
  3. my-server <none> testsvc.example.com <ingress-ip> 80 162m
  4. $ curl -H "Host:testsvc.example.com" http://<ingress-ip>
  5. Version: 0.1.5
  6. $ curl -H "Host:testsvc.example.com" http://<ingress-ip>/db
  7. User: KubeVela
  8. Description: It's a test user

修改配置

完成了首次部署后,我们可以通过修改配置仓库中的配置,来完成集群中应用的配置更新。

修改应用 Ingress 的 Domain:

  1. ...
  2. traits:
  3. - type: ingress
  4. properties:
  5. domain: kubevela.example.com
  6. http:
  7. /: 8089

经过一段时间后,重新查看集群中的 Ingress:

  1. NAME CLASS HOSTS ADDRESS PORTS AGE
  2. my-server <none> kubevela.example.com <ingress-ip> 80 162m

可以看到,Ingress 的 Host 地址已被成功更新。

通过这种方式,我们可以方便地通过更新 Git 配置仓库中的文件,从而自动化更新集群中的配置。

面向终端开发者的交付

如图所示,对于终端开发者而言,在 KubeVela Git 配置仓库以外,还需要准备一个应用代码仓库。在用户更新了应用代码仓库中的代码后,需要配置一个 CI 来自动构建镜像并推送至镜像仓库中。KubeVela 会监听镜像仓库中的最新镜像,并自动更新配置仓库中的镜像配置,最后再更新集群中的应用配置。使用户可以达成在更新代码后,集群中的配置也自动更新的效果。

alt

准备代码仓库

准备一个代码仓库,里面包含一些源代码以及对应的 Dockerfile。

这些代码将连接到一个 MySQL 数据库,并简单地启动服务。在默认的服务路径下,会显示当前版本号。在 /db 路径下,会列出当前数据库中的信息。

  1. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  2. _, _ = fmt.Fprintf(w, "Version: %s\n", VERSION)
  3. })
  4. http.HandleFunc("/db", func(w http.ResponseWriter, r *http.Request) {
  5. rows, err := db.Query("select * from userinfo;")
  6. if err != nil {
  7. _, _ = fmt.Fprintf(w, "Error: %v\n", err)
  8. }
  9. for rows.Next() {
  10. var username string
  11. var desc string
  12. err = rows.Scan(&username, &desc)
  13. if err != nil {
  14. _, _ = fmt.Fprintf(w, "Scan Error: %v\n", err)
  15. }
  16. _, _ = fmt.Fprintf(w, "User: %s \nDescription: %s\n\n", username, desc)
  17. }
  18. })
  19. if err := http.ListenAndServe(":8088", nil); err != nil {
  20. panic(err.Error())
  21. }

我们希望用户改动代码进行提交后,自动构建出最新的镜像并推送到镜像仓库。这一步 CI 可以通过集成 GitHub Actions、Jenkins 或者其他 CI 工具来实现。在本例中,我们通过借助 GitHub Actions 来完成持续集成。具体的代码文件及配置可参考 示例仓库

配置秘钥信息

在新的镜像推送到镜像仓库后,KubeVela 会识别到新的镜像,并更新仓库及集群中的 Application 配置文件。因此,我们需要一个含有 Git 信息的 Secret,使 KubeVela 向 Git 仓库进行提交。部署如下文件,将其中的用户名和密码替换成你的 Git 用户名及密码(或 Token):

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: git-secret
  5. type: kubernetes.io/basic-auth
  6. stringData:
  7. username: <your username>
  8. password: <your password>

准备配置仓库

配置仓库与之前面向运维人员的配置大同小异,只需要加上与镜像仓库相关的配置即可。具体配置请参考 示例仓库

修改 clusters/ 中的 apps.yaml,该 GitOps 配置会监听仓库中 apps/ 下的应用文件变动以及镜像仓库中的镜像更新:

  1. ...
  2. imageRepository:
  3. # 镜像地址
  4. image: <your image>
  5. # 如果这是一个私有的镜像仓库,可以通过 `kubectl create secret docker-registry` 创建对应的镜像秘钥并相关联
  6. # secretRef: imagesecret
  7. filterTags:
  8. # 可对镜像 tag 进行过滤
  9. pattern: '^master-[a-f0-9]+-(?P<ts>[0-9]+)'
  10. extract: '$ts'
  11. # 通过 policy 筛选出最新的镜像 Tag 并用于更新
  12. policy:
  13. numerical:
  14. order: asc
  15. # 追加提交信息
  16. commitMessage: "Image: {{range .Updated.Images}}{{println .}}{{end}}"

修改 apps/my-app.yaml 中的 image 字段,在后面加上 # {"$imagepolicy": "default:apps"} 的注释。KubeVela 会通过该注释去更新对应的镜像字段。default:apps 是上面 GitOps 配置对应的命名空间和名称。

  1. spec:
  2. components:
  3. - name: my-server
  4. type: webservice
  5. properties:
  6. image: ghcr.io/fogdong/test-fog:master-cba5605f-1632714412 # {"$imagepolicy": "default:apps"}

clusters/ 中包含镜像仓库配置的文件更新到集群中后,我们便可以通过修改代码来完成应用的更新。

修改代码

将代码文件中的 Version 改为 0.1.6,并修改数据库中的数据:

  1. const VERSION = "0.1.6"
  2. ...
  3. func InsertInitData(db *sql.DB) {
  4. stmt, err := db.Prepare(insertInitData)
  5. if err != nil {
  6. panic(err)
  7. }
  8. defer stmt.Close()
  9. _, err = stmt.Exec("KubeVela2", "It's another test user")
  10. if err != nil {
  11. panic(err)
  12. }
  13. }

提交该改动至代码仓库,可以看到,我们配置的 CI 流水线开始构建镜像并推送至镜像仓库。

而 KubeVela 会通过监听镜像仓库,根据最新的镜像 Tag 来更新配置仓库中 apps/ 下的应用 my-app

此时,可以看到配置仓库中有一条来自 kubevelabot 的提交,提交信息均带有 Update image automatically. 前缀。你也可以通过 {{range .Updated.Images}}{{println .}}{{end}}commitMessage 字段中追加你所需要的信息。

alt

值得注意的是,如果你希望将代码和配置放在同一个仓库,需要过滤掉来自 kubevelabot 的提交来防止流水线的重复构建。可以在 CI 中通过如下配置过滤:

  1. jobs:
  2. publish:
  3. if: "!contains(github.event.head_commit.message, 'Update image automatically')"

重新查看集群中的应用,可以看到经过一段时间后,应用 my-app 的镜像已经被更新。

KubeVela 会通过你配置的 interval 时间间隔,来每隔一段时间分别从配置仓库及镜像仓库中获取最新信息:

  • 当 Git 仓库中的配置文件被更新时,KubeVela 将根据最新的配置更新集群中的应用。
  • 当镜像仓库中多了新的 Tag 时,KubeVela 将根据你配置的 policy 规则,筛选出最新的镜像 Tag,并更新到 Git 仓库中。而当代码仓库中的文件被更新后,KubeVela 将重复第一步,更新集群中的文件,从而达到了自动部署的效果。

通过 curl 对应的 Ingress 查看当前版本和数据库信息:

  1. $ kubectl get ingress
  2. NAME CLASS HOSTS ADDRESS PORTS AGE
  3. my-server <none> kubevela.example.com <ingress-ip> 80 162m
  4. $ curl -H "Host:kubevela.example.com" http://<ingress-ip>
  5. Version: 0.1.6
  6. $ curl -H "Host:kubevela.example.com" http://<ingress-ip>/db
  7. User: KubeVela
  8. Description: It's a test user
  9. User: KubeVela2
  10. Description: It's another test user

版本已被成功更新!至此,我们完成了从变更代码,到自动部署至集群的全部操作。

总结

在运维侧,如若需要更新基础设施(如数据库)的配置,或是应用的配置项,只需要修改配置仓库中的文件,KubeVela 将自动把配置同步到集群中,简化了部署流程。

在研发侧,用户修改代码仓库中的代码后,KubeVela 将自动更新配置仓库中的镜像。从而进行应用的版本更新。

通过与 GitOps 的结合,KubeVela 加速了应用从开发到部署的整个流程。