基於 KubeVela 的 GitOps 交付

阿里巴巴雲原生發表於2021-11-07

作者|董天欣(霧霧)
稽核&校對:溪洋、海珠
編輯&排版:雯燕

KubeVela 是一個簡單、易用、且高可擴充套件的雲原生應用管理和交付平臺,能讓開發人員方便快捷地在 Kubernetes 上定義與交付現代微服務應用,無需瞭解任何 Kubernetes 基礎設施相關的細節。

KubeVela 背後的 OAM 模型天然解決了應用構建過程中對複雜資源的組合、編排等管理問題,同時也將後期的運維策略模型化,這意味著 KubeVela 可以結合 GitOps 管理複雜大規模應用,收斂由於團隊與系統規模增長導致的系統複雜度問題。

什麼是 GitOps

它的核心思想是將應用系統所需的基礎架構和應用配置宣告性描述存放在Git倉庫中,並配合一個自動化流程,使每次倉庫被更新後,自動化過程都能逐漸將環境更新到最新配置。

這樣的方式允許開發人員通過直接更改 Git 倉庫中的程式碼和配置來自動部署應用,使用 GitOps 的方式可以為應用研發帶來諸多價值,例如:

• 提高生產效率。通過自動的持續部署能夠加快平均部署時間,增加開發效率。
• 降低開發人員部署的門檻。通過推送程式碼而非容器配置,開發人員可以不需要了解 Kubernetes 的內部實現,便可以輕易部署。
• 使變更記錄可追蹤。通過 Git 來管理叢集,可以使每一次更改都可追蹤,加強了審計跟蹤。
• 可通過 Git 的回滾/分支功能來恢復叢集。

KubeVela 與 GitOps

KubeVela 作為一個宣告式的應用交付控制平面,天然支援以 GitOps 的方式來使用,並使使用者更明顯地感受到由 GitOps 帶來的益處,和端到端的應用交付與管理體驗,包括:

• 應用交付工作流(CD 流水線):即:KubeVela 支援在 GitOps 模式中描述過程式的應用交付,而不只是簡單的宣告終態;
• 處理部署過程中的各種依賴關係和拓撲結構;
• 在現有各種 GitOps 工具的語義之上提供統一的上層抽象,簡化應用交付與管理過程;
• 統一進行雲服務的宣告、部署和服務繫結;
• 提供開箱即用的交付策略(金絲雀、藍綠髮布等);
• 提供開箱即用的混合雲/多雲部署策略(放置規則、叢集過濾規則等);
• 在多環境交付中提供 Kustomize 風格的 Patch 來描述部署差異,而無需學習任何 Kustomize 本身的細節;
• ……

在本文中,我們主要講解直接使用 KubeVela 在 GitOps 模式下進行交付的步驟。

GitOps 工作流

GitOps 工作流分為 CI 和 CD 兩個部分:

• CI(Continuous Integration):持續整合對業務應用進行程式碼構建、構建映象並推送至映象倉庫。目前有許多成熟的 CI 工具,如開源專案常用的 GitHub Action、Travis 等,以及企業中常用的 Jenkins、Tekton 等。在本文中,我們使用 GitHub Action 來完成 CI 這一步,當然你也可以使用別的 CI 工具來代替,KubeVela 圍繞 GitOps 可以對接任意工具下的 CI 流程。
• CD(Continuous Delivery):持續部署會自動更新叢集中的配置,如將映象倉庫中的最新映象更新到叢集中。目前主要有兩種方案的 CD:
1)Push-Based:Push 模式的 CD 主要是通過配置 CI 流水線來完成的,這種方式需要將叢集的訪問祕鑰共享給 CI,從而使得 CI 流水線能夠通過命令將更改推送到叢集中,可以參考我們之前發表的部落格:使用 Jenkins + KubeVela 完成應用的持續交付(詳見文末相關連結)。
2)Pull-Based:Pull 模式的 CD 會在叢集中監聽倉庫(程式碼倉庫或者配置倉庫)的變化,並且將這些變化同步到叢集中。與 Push 模式相比,Pull-Based 由叢集主動拉取更新,從而避免了祕鑰暴露的問題。這也是本文介紹的核心內容。

交付的面向人員有以下兩種,我們將分別介紹:

  1. 面向平臺管理員/運維人員的基礎設施交付,使用者可以通過直接更新倉庫中的配置檔案,從而更新叢集中的基礎設施配置,如系統的依賴軟體、安全策略、儲存、網路等基礎設施配置。
  2. 面向終端開發者的交付,使用者的程式碼一旦合併到應用程式碼倉庫,就自動化觸發叢集中應用的更新,可以更高效的完成應用的迭代,與 KubeVela 的灰度釋出、流量調撥、多叢集部署等功能結合可以形成更為強大的自動化釋出能力。

面向平臺管理員/運維人員的交付

如圖所示,對於平臺管理員/運維人員而言,他們並不需要關心應用的程式碼,所以只需要準備一個 Git 配置倉庫並部署 KubeVela 配置檔案,後續對於應用及基礎設施的配置變動,便可通過直接更新 Git 配置倉庫來完成,使得每一次配置變更可追蹤。

1.png

準備配置倉庫

具體的配置可參考 示例倉庫 1(詳見文末相關連結)。

在本例中,我們將部署一個 MySQL 資料庫軟體作為專案的基礎設施,同時部署一個業務應用,使用這個資料庫。配置倉庫的目錄結構如下:

• clusters/ 中包含叢集中的 KubeVela GitOps 配置,使用者需要將 clusters/ 中的檔案手動部署到叢集中。這個是一次性的管控操作,執行完成後,KubeVela 便能自動監聽配置倉庫中的檔案變動且自動更新叢集中的配置。其中,clusters/apps.yaml 將監聽 apps/ 下所有應用的變化,clusters/infra.yaml 將監聽 infrastructure/ 下所有基礎設施的變化。
• apps/ 目錄中包含業務應用的所有配置,在本例中為一個使用資料庫的業務應用。
• infrastructure/ 中包含一些基礎設施相關的配置和策略,在本例中為 MySQL 資料庫。

├── apps
│   └── my-app.yaml
├── clusters
│   ├── apps.yaml
│   └── infra.yaml
└── infrastructure
    └── mysql.yaml

KubeVela 建議使用如上的目錄結構管理你的 GitOps 倉庫。clusters/ 中存放相關的 KubeVela GitOps 配置並需要被手動部署到叢集中,apps/ 和 infrastructure/ 中分別存放你的應用和基礎設施配置。通過把應用和基礎配置分開,能夠更為合理的管理你的部署環境,隔離由應用變動帶來的影響。

clusters/ 目錄

首先,我們來看下 clusters 目錄,這也是 KubeVela 對接 GitOps 的初始化操作配置目錄。

以 clusters/infra.yaml 為例:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: infra
spec:
  components:
  - name: database-config
    type: kustomize
    properties:
      repoType: git
      # 將此處替換成你需要監聽的 git 配置倉庫地址
      url: https://github.com/FogDong/KubeVela-GitOps-Infra-Demo
      # 如果是私有倉庫,還需要關聯 git secret
      # secretRef: git-secret
      # 自動拉取配置的時間間隔,由於基礎設施的變動性較小,此處設定為十分鐘
      pullInterval: 10m
      git:
        # 監聽變動的分支
        branch: main
      # 監聽變動的路徑,指向倉庫中 infrastructure 目錄下的檔案
      path: ./infrastructure

apps.yaml 與 infra.yaml 幾乎保持一致,只不過監聽的檔案目錄有所區別。在 apps.yaml 中,properties.path 的值將改為 ./apps,表明監聽 apps/ 目錄下的檔案變動。

cluster 資料夾中的 GitOps 管控配置檔案需要在初始化的時候一次性手動部署到叢集中,在此之後 KubeVela 將自動監聽 apps/ 以及 infrastructure/ 目錄下的配置檔案並定期更新同步。

apps/ 目錄

apps/ 目錄中存放著應用配置檔案,這是一個配置了資料庫資訊以及 Ingress 的簡單應用。該應用將連線到一個 MySQL 資料庫,並簡單地啟動服務。在預設的服務路徑下,會顯示當前版本號。在 /db 路徑下,會列出當前資料庫中的資訊。

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: my-app
  namespace: default
spec:
  components:
    - name: my-server
      type: webservice
      properties:
        image: ghcr.io/fogdong/test-fog:master-cba5605f-1632714412
        port: 8088
        env:
          - name: DB_HOST
            value: mysql-cluster-mysql.default.svc.cluster.local:3306
          - name: DB_PASSWORD
            valueFrom:
              secretKeyRef:
                name: mysql-secret
                key: ROOT_PASSWORD
      traits:
        - type: ingress
          properties:
            domain: testsvc.example.com
            http:
              /: 8088

這是一個使用了 KubeVela 內建元件型別 webservice 的應用,該應用繫結了 Ingress 運維特徵。通過在應用中宣告運維能力的方式,只需一個檔案,便能將底層的 Deployment、Service、Ingress 集合起來,從而更為便捷地管理應用。

infrastructure/ 目錄

infrastructure/ 目錄下存放一些基礎設施的配置。此處我們使用 mysql controller(詳見文末相關連結)來部署了一個 MySQL 叢集。

注意,請確保你的叢集中有一個 secret,並通過 ROOT_PASSWORD 宣告瞭 MySQL 密碼。

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: mysql
  namespace: default
spec:
  components:
    - name: mysql-controller
      type: helm
      properties:
        repoType: helm
        url: https://presslabs.github.io/charts
        chart: mysql-operator
        version: "0.4.0"
    - name: mysql-cluster
      type: raw
      dependsOn:
        - mysql-controller
      properties:
        apiVersion: mysql.presslabs.org/v1alpha1
        kind: MysqlCluster
        metadata:
          name: mysql-cluster
        spec:
          replicas: 1
          # 關聯 secret 名稱
          secretName: mysql-secret

在這個 MySQL 應用中,我們使用了 KubeVela 工作流的能力。工作流分為兩個步驟,第一個步驟會去部署 MySQL 的 controller。當 controller 部署成功且正確執行後,第二個步驟將開始部署 MySQL 叢集。

部署 clusters/ 目錄下的檔案

配置完以上檔案並存放到 Git 配置倉庫後,我們需要在叢集中手動部署 clusters/ 目錄下的 KubeVela GitOps 配置檔案。

首先,在叢集中部署 clusters/infra.yaml。可以看到它自動在叢集中拉起了 infrastructure/ 目錄下的 MySQL 部署檔案:

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

接著,在叢集中部署

clusters/apps.yaml,可以看到它自動拉起了 apps/ 目錄下的應用部署檔案:

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

至此,我們通過部署 KubeVela GitOps 配置檔案,自動在叢集中拉起了應用及資料庫。

通過 curl 應用的 Ingress,可以看到目前的版本是 0.1.5,並且成功地連線到了資料庫:

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

修改配置

完成了首次部署後,我們可以通過修改配置倉庫中的配置,來完成叢集中應用的配置更新。

修改應用 Ingress 的 Domain:

...
      traits:
        - type: ingress
          properties:
            domain: kubevela.example.com
            http:
              /: 8089

經過一段時間後,重新檢視叢集中的 Ingress:

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

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

通過這種方式,我們可以方便地通過更新 Git 配置倉庫中的檔案,從而自動化更新叢集中的配置。

面向終端開發者的交付

對於終端開發者而言,在 KubeVela Git 配置倉庫以外,還需要準備一個應用程式碼倉庫。如圖所示,在使用者更新了應用程式碼倉庫中的程式碼後,需要配置一個 CI 來自動構建映象並推送至映象倉庫中。KubeVela 會監聽映象倉庫中的最新映象,並自動更新配置倉庫中的映象配置,最後再更新叢集中的應用配置。使使用者可以達成在更新程式碼後,叢集中的配置也自動更新的效果。

2.png

準備程式碼倉庫

準備一個程式碼倉庫,裡面包含一些原始碼以及對應的 Dockerfile。

這些程式碼將連線到一個 MySQL 資料庫,並簡單地啟動服務。在預設的服務路徑下,會顯示當前版本號。在 /db 路徑下,會列出當前資料庫中的資訊。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        _, _ = fmt.Fprintf(w, "Version: %s\n", VERSION)
    })
    http.HandleFunc("/db", func(w http.ResponseWriter, r *http.Request) {
        rows, err := db.Query("select * from userinfo;")
        if err != nil {
            _, _ = fmt.Fprintf(w, "Error: %v\n", err)
        }
        for rows.Next() {
            var username string
            var desc string
            err = rows.Scan(&username, &desc)
            if err != nil {
                _, _ = fmt.Fprintf(w, "Scan Error: %v\n", err)
            }
            _, _ = fmt.Fprintf(w, "User: %s \nDescription: %s\n\n", username, desc)
        }
    })
    if err := http.ListenAndServe(":8088", nil); err != nil {
        panic(err.Error())
    }

我們希望使用者改動程式碼進行提交後,自動構建出最新的映象並推送到映象倉庫。這一步 CI 可以通過整合 GitHub Actions、Jenkins 或者其他 CI 工具來實現。在本例中,我們通過藉助 GitHub Actions 來完成持續整合。具體的程式碼檔案及配置可參考 示例倉庫 2(詳見文末相關連結)。

配置祕鑰資訊

在新的映象推送到映象倉庫後,KubeVela 會識別到新的映象,並更新倉庫及叢集中的 Application 配置檔案。因此,我們需要一個含有 Git 資訊的 Secret,使 KubeVela 向 Git 倉庫進行提交。部署如下檔案,將其中的使用者名稱和密碼替換成你的 Git 使用者名稱及密碼(或 Token):

apiVersion: v1
kind: Secret
metadata:
  name: git-secret
type: kubernetes.io/basic-auth
stringData:
  username: <your username>
  password: <your password>

準備配置倉庫

配置倉庫與之前面向運維人員的配置大同小異,只需要加上與映象倉庫相關的配置即可。具體配置請參考 示例倉庫 1(詳見文末相關連結)。

修改 clusters/ 中的 apps.yaml,該 GitOps 配置會監聽倉庫中 apps/ 下的應用檔案變動以及映象倉庫中的映象更新:

...
  imageRepository:
    # 映象地址
    image: <your image>
    # 如果這是一個私有的映象倉庫,可以通過 `kubectl create secret docker-registry` 建立對應的映象祕鑰並相關聯
    # secretRef: imagesecret
    filterTags:
      # 可對映象 tag 進行過濾
      pattern: '^master-[a-f0-9]+-(?P<ts>[0-9]+)'
      extract: '$ts'
    # 通過 policy 篩選出最新的映象 Tag 並用於更新
    policy:
      numerical:
        order: asc
    # 追加提交資訊
    commitMessage: "Image: {{range .Updated.Images}}{{println .}}{{end}}"

修改 apps/my-app.yaml 中的 image 欄位,在後面加上 # {"$imagepolicy": "default:apps"} 的註釋。KubeVela 會通過該註釋去更新對應的映象欄位。default:apps 是上面 GitOps 配置對應的名稱空間和名稱。

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

將 clusters/ 中包含映象倉庫配置的檔案更新到叢集中後,我們便可以通過修改程式碼來完成應用的更新。

修改程式碼

將程式碼檔案中的 Version 改為 0.1.6,並修改資料庫中的資料:

const VERSION = "0.1.6"
...
func InsertInitData(db *sql.DB) {
    stmt, err := db.Prepare(insertInitData)
    if err != nil {
        panic(err)
    }
    defer stmt.Close()
    _, err = stmt.Exec("KubeVela2", "It's another test user")
    if err != nil {
        panic(err)
    }
}

提交該改動至程式碼倉庫,可以看到,我們配置的 CI 流水線開始構建映象並推送至映象倉庫。

而 KubeVela 會通過監聽映象倉庫,根據最新的映象 Tag 來更新配置倉庫中 apps/ 下的應用 my-app。

此時,可以看到配置倉庫中有一條來自 kubevelabot 的提交,提交資訊均帶有 Update image automatically. 字首。你也可以通過 {{range .Updated.Images}}{{println .}}{{end}} 在 commitMessage 欄位中追加你所需要的資訊。

3.png

值得注意的是,如果你希望將程式碼和配置放在同一個倉庫,需要過濾掉來自 kubevelabot 的提交來防止流水線的重複構建。可以在 CI 中通過如下配置過濾:

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

重新檢視叢集中的應用,可以看到經過一段時間後,應用 my-app 的映象已經被更新。

KubeVela 會通過你配置的 interval 時間間隔,來每隔一段時間分別從配置倉庫及映象倉庫中獲取最新資訊:

• 當 Git 倉庫中的配置檔案被更新時,KubeVela 將根據最新的配置更新叢集中的應用。
• 當映象倉庫中多了新的 Tag 時,KubeVela 將根據你配置的 policy 規則,篩選出最新的映象 Tag,並更新到 Git 倉庫中。而當程式碼倉庫中的檔案被更新後,KubeVela 將重複第一步,更新叢集中的檔案,從而達到了自動部署的效果。

通過 curl 對應的 Ingress 檢視當前版本和資料庫資訊:

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

版本已被成功更新!至此,我們完成了從變更程式碼,到自動部署至叢集的全部操作。

總結

在運維側,如若需要更新基礎設施(如資料庫)的配置,或是應用的配置項,只需要修改配置倉庫中的檔案,KubeVela 將自動把配置同步到叢集中,簡化了部署流程。

在研發側,使用者修改程式碼倉庫中的程式碼後,KubeVela 將自動更新配置倉庫中的映象。從而進行應用的版本更新。

通過與 GitOps 的結合,KubeVela 加速了應用從開發到部署的整個流程。

戳原文,檢視 KubeVela 專案官方主頁與文件!!

相關連結
1)使用 Jenkins + KubeVela 完成應用的持續交付:
https://kubevela.io/zh/blog/2...
2)示例倉庫 1:
https://github.com/oam-dev/sa...
3)mysql controller:
https://github.com/bitpoke/my...
4)示例倉庫 2:
https://github.com/oam-dev/sa...

瞭解更多相關資訊,請釘釘掃描下方二維碼或搜尋釘釘群號(35922870)加入阿里雲原生資訊交流群!獲取更多相關資訊!

相關文章