作者|董天欣(霧霧)
稽核&校對:溪洋、海珠
編輯&排版:雯燕
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 資料庫軟體作為項目的基礎設施,同時部署一個業務應用,使用這個資料庫。配置倉庫的目錄結構如下:
-
中包含叢集中的 KubeVela GitOps 配置,使用者需要将 clusters/
中的檔案手動部署到叢集中。這個是一次性的管控操作,執行完成後,KubeVela 便能自動監聽配置倉庫中的檔案變動且自動更新叢集中的配置。其中,clusters/
将監聽 clusters/apps.yaml
下所有應用的變化,apps/
clusters/infra.yaml
下所有基礎設施的變化。infrastructure/
-
目錄中包含業務應用的所有配置,在本例中為一個使用資料庫的業務應用。apps/
-
中包含一些基礎設施相關的配置和政策,在本例中為 MySQL 資料庫。infrastructure/
├── apps
│ └── my-app.yaml
├── clusters
│ ├── apps.yaml
│ └── infra.yaml
└── infrastructure
└── mysql.yaml
KubeVela 建議使用如上的目錄結構管理你的 GitOps 倉庫。 中存放相關的 KubeVela GitOps 配置并需要被手動部署到叢集中,
clusters/
和
apps/
中分别存放你的應用和基礎設施配置。通過把應用和基礎配置分開,能夠更為合理的管理你的部署環境,隔離由應用變動帶來的影響。
infrastructure/
clusters/
目錄
clusters/
首先,我們來看下 clusters 目錄,這也是 KubeVela 對接 GitOps 的初始化操作配置目錄。
以
clusters/infr
a.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/
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-cicd2)示例倉庫 1:
https://github.com/oam-dev/samples/tree/master/9.GitOps_Demo/for-SREs3)mysql controller:
https://github.com/bitpoke/mysql-operator4)示例倉庫 2:
https://github.com/oam-dev/samples/tree/master/9.GitOps_Demo/for-developers/app-code了解更多相關資訊,請釘釘掃描下方二維碼或搜尋釘釘群号(35922870)加入阿裡雲原生資訊交流群!擷取更多相關資訊!