介绍Client-Go版本6

Kubernetes API服务器 公开REST接口 任何客户均可消费。 客户去 是Go编程语言的官方客户端库。 Kubernetes本身在内部(例如,在kubectl内部)以及 众多外部消费者:操作员喜欢 etcd运算符 要么 普罗米修斯算子更高层次的框架,例如 酷比OpenShift;还有很多。

对client-go的版本6更新增加了对Kubernetes 1.9的支持,从而允许访问最新的Kubernetes功能。而 变更日志 包含所有详细信息,此博客文章重点介绍了最重要的更改,并打算指导如何从版本5升级。

该博客文章是使第三方消费者更容易访问客户的众多努力之一。轻松访问是来自众多公司的许多人的共同努力,所有人员都在Google的#client-go-docs渠道中开会 Kubernetes松弛。我们很高兴听到反馈和进一步改进的想法,当然也感谢任何想做出贡献的人。

API组更改

以下API组促销是Kubernetes 1.9的一部分:

  • 工作负载对象(部署,DaemonSet,ReplicaSet和StatefulSet)已经 在Kubernetes 1.9中提升为apps / v1 API组。 客户去遵循此过渡,并允许开发人员通过导入k8s.io/api/apps/v1软件包而不是k8s.io/api/apps/v1beta1并使用Clientset.AppsV1()来使用最新版本。
  • 准入Webhook注册已在Kubernetes 1.9中提升为admissionregistration.k8s.io/v1beta1 API组。以前的ExternalAdmissionHookConfiguration类型已由不兼容的ValidatingWebhookConfiguration和MutatingWebhookConfiguration类型取代。此外,admission.k8s.io中的Webhook接纳有效负载类型AdmissionReview已提升为v1beta1。请注意,现在将版本化的对象传递给webhooks。参考入学网钩 文件资料 有关详细信息。

验证CustomResources

在Kubernetes 1.8中,我们引入了CustomResourceDefinitions(CRD) 持久化前模式验证 作为Alpha功能。在1.9中,该功能已升级为Beta,并且将默认启用。作为访问用户,您可以在k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1中找到API类型。

OpenAPI v3模式 可以在CRD规范中定义为:


apiVersion: apiextensions.k8s.io/v1beta1  
kind: CustomResourceDefinition  
metadata: ...  
spec:  
  ...  
  validation:  
    openAPIV3Schema:  
      properties:  
        spec:  
          properties:  
            version:  
                type: string  
                enum:  
                - "v1.0.0"  
                - "v1.0.1"  
            replicas:  
                type: integer  
                minimum: 1  
                maximum: 10

上面CRD中的模式对实例应用了以下验证:

  1. spec.version必须为字符串,并且必须为“ v1.0.0”或“ v1.0.1”。
  2. spec.replicas必须为整数,最小值为1,最大值为10。 对于spec.version(v1.0.2)和spec.replicas(15)具有无效值的CustomResource将被拒绝:

apiVersion: mygroup.example.com/v1  
kind: App  
metadata:  
  name: example-app  
spec:  
  version: "v1.0.2"  
  replicas: 15

$ kubectl create -f app.yaml

The App "example-app" is invalid: []: Invalid value: map[string]interface {}{"apiVersion":"mygroup.example.com/v1", "kind":"App", "metadata":map[string]interface {}{"creationTimestamp":"2017-08-31T20:52:54Z", "uid":"5c674651-8e8e-11e7-86ad-f0761cb232d1", "clusterName":"", "name":"example-app", "namespace":"default", "deletionTimestamp":interface {}(nil), "deletionGracePeriodSeconds":(\*int64)(nil)}, "spec":map[string]interface {}{"replicas":15, "version":"v1.0.2"}}:
validation failure list:  
spec.replicas in body should be less than 要么  equal to 10  
spec.version in body should be one of [v1.0.0 v1.0.1]

请注意, 入学网钩,Kubernetes 1.9提供了另一个beta功能,可以在对象创建或更新之前对其进行验证。从1.9开始,这些webhook还允许对象的突变(例如,设置默认值或注入值)。当然,webhooks也可与CRD一起使用。此外,可以使用Webhooks来实现用CRD验证不易表达的验证。请注意,Webhooks比CRD验证更难实现,因此对于许多目的而言,CRD验证是正确的工具。

创建命名空间的告密者

通常,一个名称空间中或仅带有某些标签的对象将在控制器中进行处理。告密者 现在允许 您可以调整用于查询API服务器的ListOptions以列出和监视对象。未初始化的对象(供消费 初始化器可以通过将IncludeUnitialized设置为true使其可见。所有这些都可以使用新的NewFilteredSharedInformerFactory构造函数用于共享通知者来完成:


import “k8s.io/client-go/informers”
...  
sharedInformers := informers.NewFilteredSharedInformerFactory(  
 client,  
 30\*time.Minute,   
 “some-namespace”,  
 func(opt \*metav1.ListOptions) {  
  opt.LabelSelector = “foo=bar”  
 },  
)  

请注意,相应的列表器将仅知道与名称空间和给定ListOptions匹配的对象。请注意,相同的限制适用于客户端上的列表或监视呼叫。

这个 生产代码示例 证书管理器的演示了如何在真实代码中使用名称空间通知者。

多态规模客户

历史上,只有扩展API组中的类型才能与自动生成的Scale客户端一起使用。此外,不同的API组对其/ scale子资源使用不同的Scale类型。为了解决这些问题,k8s.io / 客户去 / scale提供了 多态规模客户 以一致的方式扩展不同API组中的不同资源:


import (


apimeta "k8s.io/apimachinery/pkg/api/meta"

 discocache "k8s.io/client-go/discovery/cached"  
 "k8s.io/client-go/discovery"

"k8s.io/client-go/dynamic"

“k8s.io/client-go/scale”  
)

...

cachedDiscovery := discocache.NewMemCacheClient(client.Discovery())  
restMapper := discovery.NewDeferredDiscoveryRESTMapper(

cachedDiscovery,

apimeta.InterfacesForUnstructured,

)  
scaleKindResolver := scale.NewDiscoveryScaleKindResolver(

client.Discovery(),

)  
scaleClient, err := scale.NewForConfig(

client, restMapper,

dynamic.LegacyAPIPathResolverFunc,

scaleKindResolver,

)
scale, err := scaleClient.Scales("default").Get(groupResource, "foo")

返回的scale对象是通用对象,并作为autoscaling / v1.Scale对象公开。它由内部Scale类型支持,并定义了支持缩放的API组中所有特殊Scale类型之间的转换。我们计划 将其扩展到1.10中的CustomResources.

如果您要实现对scale子资源的支持,建议您公开autoscaling / v1.Scale对象。

类型安全的DeepCopy

深度复制对象以前需要调用Scheme.Copy(Object),其显着缺点是失去类型安全性。客户端执行版本5中的典型代码需要类型转换:


newObj, err := runtime.NewScheme().Copy(node)


if err != nil {

    return fmt.Errorf("failed to copy node %v: %s”, node, err)

}


newNode, ok := newObj.(\*v1.Node)

if !ok {

    return fmt.Errorf("failed to type-assert node %v", newObj)


}

谢谢 k8s.io/代码生成器,现在,Copy已由位于每个对象上的类型安全的DeepCopy方法所取代,这使您可以在数量和API错误表面方面显着简化代码:

newNode:= node.DeepCopy()

无需错误处理:此调用永远不会失败。当且仅当节点为nil时,DeepCopy()才返回nil。

要复制runtime.Objects,在runtime.Object接口中有一个附加的DeepCopyObject()方法。

随着旧方法的消逝,客户需要相应地更新其副本调用。

代码生成和CustomResources

不鼓励使用client-go的动态客户端访问CustomResources,并使用类型生成器中的类型安全代码来取代它们。 k8s.io/代码生成器。看看 Open Shift博客上的Dive Dive 了解如何在client-go中使用代码生成。

评论块

现在,您可以将标签放置在类型或函数上方的注释块中,或上方的第二个块中。这两个注释块之间不再存在区别。这曾经是 使用发电机时的细微错误:

// second block above  
// +k8s:some-tag  

// first block above  
// +k8s:another-tag  
type Foo struct {}

自定义客户端方法

现在,您可以使用扩展标签定义来创建自定义动词。这使您可以扩展到HTTP定义的动词之外。这为更高级别的定制打开了大门。

例如,此块导致方法UpdateScale(s * autoscaling.Scale)的生成(* autoscaling.Scale,错误):

// genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/autoscaling.Scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale

解决Golang命名冲突

在更复杂的API组中,“种类”,组名,Go软件包名称和Go组别名可能会发生冲突。在1.9之前,此操作未正确处理。以下标记可解决命名冲突并使生成的代码更美观:

// +groupName=example2.example.com  
// +groupGoName=SecondExample

这些通常是 在API包的doc.go文件中。当使用HTTP与API服务器进行RESTful交谈时,第一个用作CustomResource组名称。第二个用于生成的Golang代码(例如,在客户端集中)以访问组版本:

clientset.SecondExampleV1()

最终,Go包名称中可能会有点。在本部分的示例中,您需要将groupName片段放入项目的pkg / apis / example2.example.com目录中。

示例项目

Kubernetes 1.9包含许多示例项目,它们可以作为您自己的项目的蓝图:

供应商

为了从client-go的先前版本5更新到版本6,必须更新库本身以及某些第三方依赖项。以前,由于许多代码在各个版本的现有程序包布局中进行了重构或重新放置,因此该过程很繁琐。幸运的是,在最新版本中只需移动很少的代码,这将简化大多数用户的升级过程。

已发布存储库的状态

以往 k8s.io/client-go, k8s.io/apik8s.io/apimachinery 很少更新。标签(例如v4.0.0)是在Kubernetes发行后的相当一段时间内创建的。在1.9版本中,我们恢复了运行夜间机器人的功能,该机器人甚至在手动标记之前都更新了所有存储库以供公众使用。这包括分支:

  • 版本1.8 /版本5.0
  • 版本1.9 /版本6.0 Kubernetes标记(例如,v1.9.1-beta1)也将自动应用于已发布存储库,并以kubernetes-(例如,kubernetes-1.9.1-beta1)为前缀。

这些标签的测试范围有限,但是供client-go和其他库的早期采用者使用。此外,它们有助于供应商提供正确版本的 k8s.io/apik8s.io/apimachinery。请注意,我们仅在上创建类似于v6.0.3的语义版本标记 k8s.io/client-go。 k8s.io/api和k8s.io/apimachinery的对应标签是kubernetes-1.9.3。

还请注意,只有这些标签对应于经过测试的Kubernetes版本。如果您依赖发行分支,例如release-1.9,则您的客户端正在未发行的Kubernetes代码上运行。

客户转到的状态

通常,将自动生成与供应商的依存关系列表,并将其写入文件Godeps / Godeps.json。仅列出其中列出的修订版本。特别是这意味着我们不并且也不能针对依赖项的主分支测试代码库。根据所使用的供应商工具,这使我们处于以下情况:

  • Godep 通过从GOPATH中的k8s.io/client-go运行godep restore读取Godeps / Godeps.json。然后在您的项目中使用godep保存到供应商。 Godep将从您的GOPATH中选择正确的版本。
  • 滑行 在初始化和更新时都从其依赖项(包括从k8s.io/client-go)自动读取Godeps / Godeps.json。因此,只要没有冲突,滑行应该基本上是自动的。
  • 深度 当前不以一致的方式尊重Godeps / Godeps.json,尤其是在更新时不是如此。对于非k8s.io/*依赖项,手动指定客户端运行依赖项作为约束或替代至关重要。如果没有这些,dep只会选择依赖项主分支,这会在频繁更新时引起问题。
  • Kubernetes和golang / 深度社区意识到了这些问题[问题#1124, 问题#1236]和 正在共同致力于解决方案。在此之前,必须格外小心。 请参阅客户访问的 安装.md 更多细节。

更新依赖项– golang / 深度

即使在当今golang / 深度缺乏的情况下,dep仍逐渐成为Go生态系统中的实际标准。通过必要的护理和对缺失功能的了解,dep可以成功(并且是成功!)使用。这是有关如何使用dep将client-go 5项目更新到最新版本6的演示:

(如果您仍在运行客户端运行的第4版,并且希望通过不跳过发行版来安全地运行它,那么现在便是结帐的好时机 这个优秀的博客文章 介绍如何升级到版本5,由Heptio的朋友共同整理。)

在开始之前,重要的是要了解client-go是否依赖于其他两个Kubernetes项目: k8s.io/apimachineryk8s.io/api。此外,如果您使用CRD,则可能还取决于 k8s.io/apiextensions-apiserver 对于CRD客户。第一种公开了较低级别的API机制(例如,方案,序列化和类型转换),第二种公开了API定义,第三种公开了与CustomResourceDefinitions相关的API。为了使client-go正常运行,它需要以相应的匹配版本提供其配套库。每个库存储库都提供一个名为release-的分支。<version> 哪里 <version> 指特定的Kubernetes版本;对于客户端版本6,必须参考 发布-1.9在每个存储库上的分支。

假设客户端的最新版本5修补程序版本是通过dep提供的,则Gopkg.toml清单文件应类似于以下内容(可能使用分支而不是版本):






[[constraint]]


  name = "k8s.io/api"

  version = "kubernetes-1.8.1"


[[constraint]]

  name = "k8s.io/apimachinery"

  version = "kubernetes-1.8.1"


[[constraint]]

  name = "k8s.io/apiextensions-apiserver"

  version = "kubernetes-1.8.1"


[[constraint]]

  name = "k8s.io/client-go"




  version = "5.0.1"

请注意,如果客户端实际上不需要某些库,则可能会丢失它们。

升级到客户端使用的版本6意味着按如下方式更改版本和标记标识符( 重点 给定):






[constraint]]


  name = "k8s.io/api"

  version = "kubernetes-1.9.0"


[[constraint]]

  name = "k8s.io/apimachinery"

  version = "kubernetes-1.9.0"


[[constraint]]

  name = "k8s.io/apiextensions-apiserver"

  version = "kubernetes-1.9.0"


[[constraint]]

  name = "k8s.io/client-go"




  version = "6.0.0"



可以找到升级结果 这里.

注意事项:如上所述,dep无法以可靠且可复制的方式捕获完整的依赖项集。这意味着对于一个100%面向未来的项目,您必须向客户端go Godeps / Godeps.json中列出的许多其他软件包添加约束(甚至替代)。如果出现问题,请准备添加它们。我们正在与golang / 深度社区合作,以使其变得更轻松,更流畅。

最后,我们需要通过执行dep sure来告诉dep升级到指定版本。如果一切顺利,命令调用的输出应该为空,唯一表明成功的是供应商文件夹中的许多更新文件。

如果使用CRD,则可能还使用代码生成。 Gopkg.toml的以下块将向您的项目添加所需的代码生成包:


required = [  
  "k8s.io/代码生成器/cmd/client-gen",  
  "k8s.io/代码生成器/cmd/conversion-gen",  
  "k8s.io/代码生成器/cmd/deepcopy-gen",  
  "k8s.io/代码生成器/cmd/defaulter-gen",  
  "k8s.io/代码生成器/cmd/informer-gen",  
  "k8s.io/代码生成器/cmd/lister-gen",  
]


[[constraint]]

  branch = "kubernetes-1.9.0"


  name = "k8s.io/代码生成器"

此时,您是否还想通过dep修剪不需要的软件包(例如测试文件)还是将更改提交到VCS中都由您决定-但是从升级的角度来看,您现在应该准备好利用所有新功能Kubernetes 1.9通过client-go带来的功能。