乐趣区

关于云计算:全场景效能平台猪齿鱼-Agenthelm组件升级

此前文章猪齿鱼 Agent——基于 GitOps 的云原生继续交付模型介绍了 Choerodon Agent 基于 helm2 版本在猪齿鱼平台继续交付部署流水线中的作用以及实现原理。

当初最新 helm 版本曾经到 helm3,持续应用 helm2 会面临着如下问题:

  1. helm2 版本应用的 k8s api 较老,不利于 Choerodon Agent 对 k8s 高版本进行反对
  2. helm2 架构是 client-server 架构。其中 tiller-pod 须要高集群权限,不不便集群中权限治理。同时在 Choerodon Agent 这边又属于客户端,呈现问题后不不便进行调试

因而 Choerodon Agent 须要反对 helm3 版本,同时迁徙 helm2 版本下装置的实例。

helm2 与 helm3 区别

  1. tiller 被删除

如图所示,helm2 中部署 Release 须要通过 tiller-pod,然而在 helm3 就间接通过 kubeconfig 部署实例

  1. helm2 中 Release 是全局资源,在 helm3 中 Release 存储在各自的命名空间
  2. Values 反对 JSON Schema 校验器,主动查看所有输出的变量格局
  3. 移除了用于本地长期搭建 Chart Repository 的 helm serve 命令
  4. helm install 不再默认生成一个 Release 的名称,除非指定了–generate-name
  5. 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 也产生巨大变化。其中有两局部须要进行批改

  1. helm 客户端获取、装置、降级、卸载实例须要重构
  2. 须要迁徙 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) 操作举例,其余操作 (降级、删除) 大同小异。%E6%93%8D%E4%BD%9C%E4%B8%BE%E4%BE%8B%EF%BC%8C%E5%85%B6%E4%BB%96%E6%93%8D%E4%BD%9C(%E5%8D%87%E7%BA%A7%E3%80%81%E5%88%A0%E9%99%A4)%E5%A4%A7%E5%90%8C%E5%B0%8F%E5%BC%82%E3%80%82)

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 命令的初始化形式,将分为以下几个步骤

  1. 获取 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
    }
    
    
  2. 创立 Install 操作对象

        installClient := action.NewInstall(
            cfg,
            chartPathOptions,
            request.Command,
            request.ImagePullSecrets,
            request.Namespace,
            request.ReleaseName,
            request.ChartName,
            request.ChartVersion,
            request.AppServiceId,
            envkube.AgentVersion,
            "",
            false)
    
    
  3. 校验 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. 调用装置办法,执行装置命令

···
responseRelease, err := installClient.Run(chartRequested, vals, request.Values)
···


具体的逻辑可查看[choerodon-cluster-agent/pkg/helm/helm.go::InstallRelease()](https://github.com/open-hand/choerodon-cluster-agent/blob/master/pkg/helm/helm.go#L172)

总结来说就是以下 4 个步骤:

获取配置对象 -> 生成操作对象 -> 校验 chart 包并生成 values 值 -> 执行操作

## 对已装置的 Release 进行迁徙

对 Release 的迁徙须要用到 helm 迁徙工具,该工具是间接集成到 Choerodon Agent 我的项目代码中的。在 Choeordon Agent 的启动逻辑中,接管到的第一个命令是 agent_init。该命令负责命名空间的创立和监听,因而 Release 迁徙逻辑也就放到这一步操作中。整个流程如下图所示:![](https://oscimg.oschina.net/oscnet/agent_helm-4.png)

1.  首先从 [choerodon-cluster-agent/pkg/command/agent/agent.go::InitAgent()](https://github.com/open-hand/choerodon-cluster-agent/blob/master/pkg/command/agent/agent.go#L25) 办法开始 ```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 监听、以及返回集群信息 }
  1. 在 choerodon-cluster-agent/pkg/command/agent/agent.go::createNamespace()开始初始化命名空间

    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
    }
    
    
  2. 在 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 的迁徙逻辑

常见问题解决

  1. 有时候 Choerodon Agent 重启后,会呈现启动失败的问题,查看日志有实例迁徙失败,tiller-pod 不存在谬误

该问题可能是实例迁徙实现后,命名空间的 label 增加失败。解决办法是手动给该命名空间增加”choerodon.io/helm-version”:“helm3”标签,以此示意该命名空间的实例迁徙已实现,不须要再次迁徙

  1. 批改资源后,部署失败,且错误信息提醒为超时

首先在 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 工具链、从平台工具到体系化方法论,猪齿鱼全面满足协同治理与工程效率需要,贯通端到端全流程,助力团队效力更快更强更稳固。戳此处试用猪齿鱼

退出移动版