此前文章豬齒魚 Agent——基於GitOps的雲原生持續交付模型介紹了Choerodon Agent基於helm2版本在豬齒魚平臺持續交付部署流水線中的作用以及實現原理。
現在最新helm版本已經到helm3,繼續使用helm2會面臨着如下問題:
- helm2版本使用的k8s api較老,不利於Choerodon Agent對k8s高版本進行支持
- helm2架構是client-server架構。其中tiller-pod需要高集羣權限,不方便集羣中權限管理。同時在Choerodon Agent這邊又屬於客戶端,出現問題後不方便進行調試
因此Choerodon Agent需要支持helm3版本,同時遷移helm2版本下安裝的實例。
helm2與helm3區別
- tiller被刪除
如圖所示,helm2中部署Release需要經過tiller-pod,但是在helm3就直接通過kubeconfig部署實例
-
helm2中Release是全局資源,在helm3中Release存儲在各自的命名空間
-
Values支持JSON Schema校驗器,自動檢查所有輸入的變量格式
-
移除了用於本地臨時搭建Chart Repository的helm serve 命令
-
helm install 不再默認生成一個Release的名稱,除非指定了–generate-name
-
Helm Cli個別更名
helm2到helm3的遷移
helm2到helm3的遷移包括如下步驟:
-
helm2的配置遷移
-
helm2的release遷移
-
清除helm2的配置、release數據以及Tileer deployment
使用helm-2to3進行數據遷移
安裝2to3插件
helm3 plugin install https://github.com/helm/helm-2to3
插件特性
支持功能:
-
遷移helm2的配置
-
遷移helm2的releases
-
清除helm2的配置,rel ease 數據以及Tiller deployment
遷移helm2的配置
首先需要遷移helm2的配置和數據文件夾,包括如下內容:
- Chart starters
- Repositories
- Plugins
通過如下命令開始遷移:
helm3 2to3 move config
遷移helm2的實例
通過如下命令開始遷 移:
helm3 2to3 convert [ReleaseName]
清除helm2的數據
如果遷移完成後沒有出現錯誤,就可以通過 此條命令清楚helm2的數據,包括如下內容:
- Configuration(Helm homedirectory)
- v2release data
- Tiller deployment
通過如下命令開始清楚數據:
helm3 2to3 cleanup
注意:如果運行清楚命令,所有被刪掉的 數據都不能恢復。所以沒必要的話,還是將以前的數據保留下來
Choerodon Agent的升級處理
helm2到helm3的變動非常大,所以Choerdon Agent調用helm也發生巨大變化。其中有兩部分需要進行修改
-
helm客戶端獲取、安裝、升級、卸載實例需要重構
-
需要遷移helm2安裝的實例到helm3,不然升級後Choerodon Agent無法繼續管理以前的實例
helm客戶端重構
在helm2的時候,Choerodon Agent直接將helm源代碼作爲Choerodon Agent部分代碼進行使用。而在helm3,直接對helm3的源碼進行二次開發,然後通過依賴引用。這樣做的好處是將helm代碼與Choerodon Agent代碼解藕,有利於helm相關代碼更新升級。
在Choerodon Agent裏面,安裝或升級實例會對Chart中的資源添加Choeordon Agent相關的label,比如choerodon.io/release、choeroodn.io/command等等,所以helm3的二次開發主要是添加資源label,以安裝(Install)操作舉例,其他操作(升級、刪除)大同小異。
1. 修改模塊名稱
進行二次開發,首先需要修改該項目的模塊名稱,該步驟也是最麻煩的,因爲修改後需要修改代碼裏面所有的包引用路徑
如圖所示,go.mod文件中的module進行如下修改
github.com/choerodon/helm => github.com/open-hand/helm
然後代碼文件中修改引用路徑
2. 加入添加label邏輯
通過斷點調試,找到helm3安裝邏輯由open-hand-helm/pkg/action/install.go::Run()方法實現,在該方法中插入添加標籤步驟。下面省略不必要的代碼
func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}, valsRaw string) (*release.Release, error) {
// ···省略的步驟是helm對chart包進行校驗渲染,生成k8s對象,並保存到resources變量中
// 以下爲修改的內容,遍歷resources對象,添加Label
for _, r := range resources {
err = action.AddLabel(i.ImagePullSecret, i.Command, i.AppServiceId, r, i.ChartVersion, i.ReleaseName, i.ChartName, i.AgentVersion, "", i.TestLabel, i.IsTest, false, nil)
if err != nil {
return nil, err
}
}
// ···省略的步驟是helm將resources更新到集羣中
}
接下來看看open-hand-helm/pkg/agent/action/label.go::AddLabel()方法
func AddLabel(imagePullSecret []v1.LocalObjectReference,
command int64,
appServiceId int64,
info *resource.Info,
version, releaseName, chartName, agentVersion, testLabel, namespace string,
isTest bool,
isUpgrade bool,
clientSet *kubernetes.Clientset) error {
// 該方法內容比較多,不在這裏展示,具體可參考源代碼。其作用就是根據不同的資源類型添加不同的Label值
}
3. Choerodon Agent 引用二次開發的helm庫
參照helm3源碼install命令的初始化方式,將分爲以下幾個步驟
-
獲取helm配置信息
// 獲取helm的配置信息 func getCfg(namespace string) (*action.Configuration, *cli.EnvSettings) { settings := cli.New() settings.SetNamespace(namespace) actionConfig := &action.Configuration{} helmDriver := os.Getenv("HELM_DRIVER") if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { log.Fatal(err) } return action config, settings }
-
創建Install操作對象
installClient := action.NewInstall( cfg, chartPathOptions, request.Command, request.ImagePullSecrets, request.Namespace, request.ReleaseName, request.ChartName, request.ChartVersion, request.AppServiceId, envkube.AgentVersion, "", false)
-
校驗chart包並生成values值 ```go ··· valueOpts := getValueOpts(request.Values) p := getter.All(envSettings) vals, err := valueOpts.MergeValues(p) if err != nil { return nil, err }
// Check chart dependencies to make sure all are present in /charts chartRequested, err := loader.Load(cp) if err != nil { return nil, err }
validInstallableChart, err := isChartInstallable(chartRequested) if !validInstallableChart { return nil, err } ···
4. 調用安裝方法,執行安裝命令
```go
···
responseRelease, err := installClient.Run(chartRequested, vals, request.Values)
···
具體的邏輯可查看choerodon-cluster-agent/pkg/helm/helm.go::InstallRelease()
總結來說就是以下4個步驟:
獲取配置對象->生成操作對象->校驗chart包並生成values值->執行操作
對已安裝的Release進行遷移
對Release的遷移需要用到helm遷移工具,該工具是直接集成到Choerodon Agent項目代碼中的。
在Choeordon Agent的啓動邏輯中,接收到的第一個命令是agent_init。該命令負責命名空間的創建和監聽,因此Release遷移邏輯也就放到這一步操作中。
整個流程如下圖所示:
- 首先從choerodon-cluster-agent/pkg/command/agent/agent.go::InitAgent()方法開始 ```go func InitAgent(opts *commandutil.Opts, cmd *model.Packet) ([]*model.Packet, *model.Packet) { // ···省略的步驟是處理初始化的參數
// 下面的代碼開始對需要監聽的命名空間進行初始化 for _, envPara := range agentInitOpts.Envs { nsList = append(nsList, envPara.Namespace) err := createNamespace(opts, envPara.Namespace, envPara.Releases) if err != nil { return nil, commandutil.NewResponseError(cmd.Key, cmd.Type, err) } }
// ···省略的步驟是開啓gitops監聽、controller監聽、以及返回集羣信息 }
2. 在[choerodon-cluster-agent/pkg/command/agent/agent.go::createNamespace()](https://github.com/open-hand/choerodon-cluster-agent/blob/master/pkg/command/agent/agent.go#L196)開始初始化命名空間
```go
func createNamespace(opts *commandutil.Opts, namespaceName string, releases []string) error {
ns, err := opts.KubeClient.GetKubeClient().CoreV1().Namespaces().Get(namespaceName, metav1.GetOptions{})
if err != nil {
// 如果命名空間不存在的話,則創建
if errors.IsNotFound(err) {
_, err = opts.KubeClient.GetKubeClient().CoreV1().Namespaces().Create(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespaceName,
Labels: map[string]string{model.HelmVersion: "helm3"},
},
})
return err
}
return err
}
labels := ns.Labels
annotations := ns.Annotations
// 如果命名空間存在,則檢查labels標籤
if _, ok := labels[model.HelmVersion]; !ok {
// 開始遷移實例
return update(opts, releases, namespaceName, labels, annotations)
}
return nil
}
-
在choerodon-cluster-agent/pkg/command/agent/agent.go::update()中遷移實例 ```go func update(opts *commandutil.Opts, releases []string, namespaceName string, labels, annotations map[string]string) error { releaseCount := len(releases) upgradeCount := 0
// 此處不對choerodon命名空間下的實例進行遷移處理 // 安裝agent的時候,會直接創建choerodon命名空間而不打上 model.HelmVersion 標籤 // 然後用戶直接創建pv,會導致choerodon沒有標籤也納入環境管理(如果通過agent安裝了prometheus或者cert-manager就會出現問題) // 所以直接默認choeordon不需要進行helm遷移 if namespaceName != “choerodon” && releaseCount != 0 { for i := 0; i < releaseCount; i++ { getReleaseRequest := &helm.GetReleaseContentRequest{ ReleaseName: releases[i], Namespace: namespaceName, }
// 查看該實例是否helm3管理,如果是upgradeCount加1,如果不是,進行遷移操作然後再加1 _, err := opts.HelmClient.GetRelease(getReleaseRequest) if err != nil { // 實例不存在有可能是實例未遷移,嘗試遷移操作 if strings.Contains(err.Error(), helm.ErrReleaseNotFound) { helm2to3.RunConvert(releases[i]) if opts.ClearHelmHistory { helm2to3.RunCleanup(releases[i]) } upgradeCount++ } } else { // 實例存在表明實例被helm3管理,嘗試進行數據清理,然後upgradeCount加1 if opts.ClearHelmHistory { helm2to3.RunCleanup(releases[i]) } upgradeCount++ } } if releaseCount != upgradeCount { return fmt.Errorf("env %s : failed to upgrade helm2 to helm3 ", namespaceName) }
}
// 添加label if labels == nil { labels = make(map[string]string) }
labels[model.HelmVersion] = "helm3"
_, err := opts.KubeClient.GetKubeClient().CoreV1().Namespaces().Update(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespaceName,
Labels: labels,
Annotations: annotations,
},
})
return err
} ``` 由此完成了Choerodon Agent對Release的遷移邏輯
常見問題解決
- 有時候Choerodon Agent重啓後,會出現啓動失敗的問題,查看日誌有實例遷移失敗,tiller-pod不存在錯誤
該問題可能是實例遷移完成後,命名空間的label添加失敗。解決辦法是手動給該命名空間添加”choerodon.io/helm-version”:“helm3” 標籤,以此表示該命名空間的實例遷移已完成,不需要再次遷移
- 修改資源後,部署失敗,且錯誤信息提示爲超時
首先在devops的環境層檢查三個commit值是否一致,有如下情況:
- 前兩個commit不一致:說明devops在gitlab的webhook回調處理上有問題,應該從gitlab的webhook執行記錄以及devops日誌進行排查
- 前兩個一致,第三個落後於前兩個:說明devops同步相關gitops操作已完成,但是在Choerodon Agent同步gitops庫上出了問題。
這時先保留一份日誌,供開發人員查找分析,然後kubectl -n choerodon delete [podName]刪除Choerodon Agent進行重啓。
如果重啓完成後,Choerodon Agent仍然沒有同步gitops庫,這時應該考慮該環境庫在gitlab的密鑰是否與devops數據庫中存儲的一致。先在本地驗證能否通過該密鑰拉取gitops庫。如果不行,重置該gitops庫的密鑰,最好的辦法就是刪掉該環境重新創建。如果可以,那麼說明Choerodon Agent與gitlab連接有問題,檢查gitlab的端口開發情況以及Choerodon Agent與外部網絡的訪問連接情況
- 三個commit都一致,但是實例部署失敗,且提示訪問chart倉庫超時:這個問題經常遇到。排查後發現是Choerodon Agent與Chart Museum網絡連接有問題
本文由豬齒魚技術團隊原創,轉載請註明出處:豬齒魚官網
關於豬齒魚
豬齒魚Choerodon全場景效能平臺,提供體系化方法論和協作、測試、DevOps及容器工具,幫助企業拉通需求、設計、開發、部署、測試和運營流程,一站式提高管理效率和質量。從團隊協同到DevOps工具鏈、從平臺工具到體系化方法論,豬齒魚全面滿足協同管理與工程效率需求,貫穿端到端全流程,助力團隊效能更快更強更穩定。戳此處試用豬齒魚