使用 client-go 直接针对 Kubernetes API 进行“kubectl apply”,并在单个 YAML 文件中使用多种类型

2023-12-26

我在用着https://github.com/kubernetes/client-go https://github.com/kubernetes/client-go一切都很好。

我有官方 Kubernetes 仪表板的清单 (YAML):https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml

我想模仿kubectl apply使用 client-go 在 Go 代码中显示此清单。

我知道我需要将 YAML 字节编组为包中定义的正确 API 类型:https://github.com/kubernetes/api https://github.com/kubernetes/api

我已经成功Create将单个 API 类型添加到我的集群中,但是对于包含不相同的类型列表的清单,我该如何执行此操作?有资源吗kind: List*支持这些不同类型?

我当前的解决方法是使用拆分 YAML 文件csplit以 --- 作为分隔符

csplit /path/to/recommended.yaml /---/ '{*}' --prefix='dashboard.' --suffix-format='%03d.yaml'

接下来,我循环创建新的 (14) 部分,读取它们的字节,打开 UniversalDeserializer 解码器返回的对象类型,并使用我的 k8s 客户端集调用正确的 API 方法。

我想以编程方式执行此操作,以便将仪表板的任何新版本更新到我的集群中。我还需要对 Metrics Server 和许多其他资源执行此操作。另一种(可能更简单)的方法是将安装了 kubectl 的代码发送到容器映像并直接调用kubectl apply -f -;但这意味着我还需要将 kube 配置写入磁盘,或者可能将其内联传递,以便 kubectl 可以使用它。

我发现这个问题很有帮助:https://github.com/kubernetes/client-go/issues/193 https://github.com/kubernetes/client-go/issues/193解码器位于此处:https://github.com/kubernetes/apimachinery/tree/master/pkg/runtime/serializer https://github.com/kubernetes/apimachinery/tree/master/pkg/runtime/serializer

它在 client-go 中公开:https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go#L69 https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go#L69

我还查看了 kubectl 使用的 RunConvert 方法:https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/convert/convert.go#L139 https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/convert/convert.go#L139并假设我可以提供自己的genericclioptions.IOStreams https://github.com/kubernetes/cli-runtime/blob/master/pkg/genericclioptions/io_options.go#L27得到输出?

看起来 RunConvert 正处于弃用路径上 https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/convert/convert.go#L141-L145

我还查看了标记为 [client-go] 的其他问题,但大多数使用旧示例或使用带有单个 YAML 文件kind已定义,并且 API 自此发生了变化。

编辑:因为我需要为多个集群执行此操作,并且正在以编程方式创建集群(AWS EKS API + CloudFormation/eksctl https://github.com/weaveworks/eksctl),我想尽量减少创建的开销ServiceAccount跨许多集群上下文、跨许多 AWS 账户。理想情况下,创建我的客户端集涉及的唯一身份验证步骤是使用AWS-iam-身份验证器 https://github.com/kubernetes-sigs/aws-iam-authenticator使用集群数据(名称、区域、CA 证书等)获取令牌。有一段时间没有发布 aws-iam-authenticator 了,但是内容master允许使用第三方角色跨账户角色和外部ID进行传递。 IMO,这比使用更干净ServiceAccount (and IRSA https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)因为应用程序(创建附加组件并将其应用到这些集群的后端 API)需要与其他 AWS 服务进行交互。

编辑:我最近发现https://github.com/ericchiang/k8s https://github.com/ericchiang/k8s。从高层来看,它肯定比 client-go 使用起来更简单,但不支持这种行为。


听起来您已经弄清楚如何将 YAML 文件反序列化到 Kubernetes 中runtime.Objects,但问题是动态部署runtime.Object无需为每种类型编写特殊代码。

kubectl通过与REST API https://godoc.org/k8s.io/client-go/rest直接地。具体来说,通过资源助手 https://godoc.org/k8s.io/cli-runtime/pkg/resource#Helper.

在我的代码中,我有类似的内容:

import (
    meta "k8s.io/apimachinery/pkg/api/meta"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/cli-runtime/pkg/resource"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/restmapper"
)

func createObject(kubeClientset kubernetes.Interface, restConfig rest.Config, obj runtime.Object) (runtime.Object, error) {
    // Create a REST mapper that tracks information about the available resources in the cluster.
    groupResources, err := restmapper.GetAPIGroupResources(kubeClientset.Discovery())
    if err != nil {
        return nil, err
    }
    rm := restmapper.NewDiscoveryRESTMapper(groupResources)

    // Get some metadata needed to make the REST request.
    gvk := obj.GetObjectKind().GroupVersionKind()
    gk := schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}
    mapping, err := rm.RESTMapping(gk, gvk.Version)
    if err != nil {
        return nil, err
    }

    namespace, err := meta.NewAccessor().Namespace(obj)
    if err != nil {
        return nil, err
    }

    // Create a client specifically for creating the object.
    restClient, err := newRestClient(restConfig, mapping.GroupVersionKind.GroupVersion())
    if err != nil {
        return nil, err
    }

    // Use the REST helper to create the object in the "default" namespace.
    restHelper := resource.NewHelper(restClient, mapping)
    return restHelper.Create(namespace, false, obj)
}

func newRestClient(restConfig rest.Config, gv schema.GroupVersion) (rest.Interface, error) {
    restConfig.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
    restConfig.GroupVersion = &gv
    if len(gv.Group) == 0 {
        restConfig.APIPath = "/api"
    } else {
        restConfig.APIPath = "/apis"
    }

    return rest.RESTClientFor(&restConfig)
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 client-go 直接针对 Kubernetes API 进行“kubectl apply”,并在单个 YAML 文件中使用多种类型 的相关文章

随机推荐