作者|董天欣(霧霧)
審核&校對:溪洋、海珠
編輯&排版:雯燕
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 由集群主動拉取更新,從而避免了秘鑰暴露的問題。這也是本文介紹的核心內容。
交付的面向人員有以下兩種,我們將分別介紹:
- 面向平台管理員/運維人員的基礎設施交付,用戶可以通過直接更新倉庫中的配置文件,從而更新集群中的基礎設施配置,如系統的依賴軟件、安全策略、存儲、網絡等基礎設施配置。
- 面向終端開發者的交付,用戶的代碼一旦合並到應用代碼倉庫,就自動化觸發集群中應用的更新,可以更高效的完成應用的迭代,與 KubeVela 的灰度發布、流量調撥、多集群部署等功能結合可以形成更為強大的自動化發布能力。
面向平台管理員/運維人員的交付
如圖所示,對於平台管理員/運維人員而言,他們並不需要關心應用的代碼,所以只需要准備一個 Git 配置倉庫並部署 KubeVela 配置文件,后續對於應用及基礎設施的配置變動,便可通過直接更新 Git 配置倉庫來完成,使得每一次配置變更可追蹤。
准備配置倉庫
具體的配置可參考 示例倉庫 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 會監聽鏡像倉庫中的最新鏡像,並自動更新配置倉庫中的鏡像配置,最后再更新集群中的應用配置。使用戶可以達成在更新代碼后,集群中的配置也自動更新的效果。
准備代碼倉庫
准備一個代碼倉庫,里面包含一些源代碼以及對應的 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 字段中追加你所需要的信息。
值得注意的是,如果你希望將代碼和配置放在同一個倉庫,需要過濾掉來自 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/2021/09/02/kubevela-jenkins-cicd
2)示例倉庫 1:
https://github.com/oam-dev/samples/tree/master/9.GitOps_Demo/for-SREs
3)mysql controller:
https://github.com/bitpoke/mysql-operator
4)示例倉庫 2:
https://github.com/oam-dev/samples/tree/master/9.GitOps_Demo/for-developers/app-code
了解更多相關信息,請釘釘掃描下方二維碼或搜索釘釘群號(35922870)加入阿里雲原生資訊交流群!獲取更多相關資訊!