在单个YAML文件中直接对多种类型的Kubernetes API使用client-go来对Kubernetes API进行kubectl apply [英] Using client-go to `kubectl apply` against the Kubernetes API directly with multiple types in a single YAML file

查看:298
本文介绍了在单个YAML文件中直接对多种类型的Kubernetes API使用client-go来对Kubernetes API进行kubectl apply的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 https://github.com/kubernetes/client-go 和一切正常.

I'm using https://github.com/kubernetes/client-go and all works well.

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

I have a manifest (YAML) for the official Kubernetes Dashboard: https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml

我想使用client-go在Go代码中模仿此清单的kubectl apply.

I want to mimic kubectl apply of this manifest in Go code, using client-go.

我了解我需要对YAML字节进行一些(非)编组,以将其定义为程序包中定义的正确API类型: https://github.com/kubernetes/api

I understand that I need to do some (un)marshalling of the YAML bytes into the correct API types defined in package: https://github.com/kubernetes/api

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

I have successfully Createed single API types to my cluster, but how do I do this for a manifest that contains a list of types that are not the same? Is there a resource kind: List* that supports these different types?

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

My current workaround is to split the YAML file using csplit with --- as the delimiter

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

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

Next, I loop over the new (14) parts that were created, read their bytes, switch on the type of the object returned by the UniversalDeserializer's decoder and call the correct API methods using my k8s clientset.

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

I would like to do this to programmatically to make updates to any new versions of the dashboard into my cluster. I will also need to do this for the Metrics Server and many other resources. The alternative (maybe simpler) method is to ship my code with kubectl installed to the container image and directly call kubectl apply -f -; but that means I also need to write the kube config to disk or maybe pass it inline so that kubectl can use it.

我发现此问题有帮助: https://github.com/kubernetes/client-go/issues/193 解码器位于此处: https://github.com/kubernetes/apimachinery/树/主/pkg/运行时/序列化器

I found this issue to be helpful: https://github.com/kubernetes/client-go/issues/193 The decoder lives here: https://github.com/kubernetes/apimachinery/tree/master/pkg/runtime/serializer

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

It's exposed in client-go here: https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go#L69

我还看了kubectl使用的RunConvert方法: genericclioptions.IOStreams 来获取输出?

I've also taken a look at the RunConvert method that is used by kubectl: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/convert/convert.go#L139 and assume that I can provide my own genericclioptions.IOStreams to get the output?

它看起来像RunConvert在弃用路径上

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

I've also looked at other questions tagged [client-go] but most use old examples or use a YAML file with a single kind defined, and the API has changed since.

因为我需要对多个集群执行此操作,并且正在以编程方式创建集群(AWS EKS API + CloudFormation/ eksctl ),我希望将在许多群集上下文中,在许多AWS账户中创建ServiceAccount的开销降至最低.理想情况下,创建我的客户端集所涉及的唯一身份验证步骤是使用 aws-iam-authenticator 使用集群数据(名称,区域,CA证书等)获取令牌.一段时间没有发布aws-iam-authenticator,但是master的内容允许使用第三方角色交叉帐户角色和要传递的外部ID. IMO,这比使用ServiceAccount(和

Because I need to do this for more than one cluster and am creating clusters programmatically (AWS EKS API + CloudFormation/eksctl), I would like to minimize the overhead of creating ServiceAccounts across many cluster contexts, across many AWS accounts. Ideally, the only authentication step involved in creating my clientset is using aws-iam-authenticator to get a token using cluster data (name, region, CA cert, etc). There hasn't been a release of aws-iam-authenticator for a while, but the contents of master allow for the use of a third-party role cross-account role and external ID to be passed. IMO, this is cleaner than using a ServiceAccount (and IRSA) because there are other AWS services the application (the backend API which creates and applies add-ons to these clusters) needs to interact with.

我最近发现了 https://github.com/ericchiang/k8s .在高层上,它肯定比client-go更简单,但不支持此行为.

I have recently found https://github.com/ericchiang/k8s. It's definitely simpler to use than client-go, at a high-level, but doesn't support this behavior.

推荐答案

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

It sounds like you've figured out how to deserialize YAML files into Kubernetes runtime.Objects, but the problem is dynamically deploying a runtime.Object without writing special code for each Kind.

kubectl通过直接与 REST API 进行交互来实现.具体来说,通过 resource.Helper .

kubectl achieves this by interacting with the REST API directly. Specifically, via resource.Helper.

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

In my code, I have something like:

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

func createObject(kubeClientset kubernetes.Interface, restConfig rest.Config, obj 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 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 err
    }

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

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

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

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)
}

这篇关于在单个YAML文件中直接对多种类型的Kubernetes API使用client-go来对Kubernetes API进行kubectl apply的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆