Introducing client-go version 6
The Kubernetes API server numerous external consumers:operators like the
The version 6 update to client-go adds support for Kubernetes 1.9, allowing access to the latest Kubernetes features. While the
This blog post is one of a number of efforts to make client-go more accessible to third party consumers. Easier access is a joint effort by a number of people from numerous companies, all meeting in the #client-go-docs channel of the
The following API group promotions are part of Kubernetes 1.9: In Kubernetes 1.8 we introduced CustomResourceDefinitions (CRD) pre-persistence schema validation as an alpha feature. With 1.9, the feature got promoted to beta and will be enabled by default. As a client-go user, you will find the API types at k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1. The
The schema in the above CRD applies following validations for the instance: Note that with Admission Webhooks, Kubernetes 1.9 provides another beta feature to validate objects before they are created or updated. Starting with 1.9, these webhooks also allow mutation of objects (for example, to set defaults or to inject values). Of course, webhooks work with CRDs as well. Moreover, webhooks can be used to implement validations that are not easily expressible with CRD validation. Note that webhooks are harder to implement than CRD validation, so for many purposes, CRD validation is the right tool. Often objects in one namespace or only with certain labels are to be processed in a controller. Informers
Note that the corresponding lister will only know about the objects matching the namespace and the given ListOptions. Note that the same restrictions apply for a List or Watch call on a client. This
Historically, only types in the extensions API group would work with autogenerated Scale clients. Furthermore, different API groups use different Scale types for their /scale subresources. To remedy these issues, k8s.io/client-go/scale provides a
The returned scale object is generic and is exposed as the autoscaling/v1.Scale object. It is backed by an internal Scale type, with conversions defined to and from all the special Scale types in the API groups supporting scaling. We planto . If you’re implementing support for the scale subresource, we recommend that you expose the autoscaling/v1.Scale object. Deeply copying an object formerly required a call to Scheme.Copy(Object) with the notable disadvantage of losing type safety. A typical piece of code from client-go version 5 required type casting: Thanks to
newNode := node.DeepCopy() No error handling is necessary: this call never fails. If and only if the node is nil does DeepCopy() return nil. To copy runtime.Objects there is an additional DeepCopyObject() method in the runtime.Object interface. With the old method gone for good, clients need to update their copy invocations accordingly. Using client-go’s dynamic client to access CustomResources is discouraged and superseded by type-safe code using the generators in
You can now place tags in the comment block just above a type or function, or in the second block above. There is no distinction anymore between these two comment blocks. This used to a be a source of : You can now use extended tag definitions to create custom verbs . This lets you expand beyond the verbs defined by HTTP. This opens the door to higher levels of customization. For example, this block leads to the generation of the method UpdateScale(s *autoscaling.Scale) (*autoscaling.Scale, error): In more complex API groups it’s possible for Kinds, the group name, the Go package name, and the Go group alias name to conflict. This was not handled correctly prior to 1.9. The following tags resolve naming conflicts and make the generated code prettier: These are usually
clientset.SecondExampleV1() It’s finally possible to have dots in Go package names. In this section’s example, you would put the groupName snippet into the pkg/apis/example2.example.com directory of your project. Kubernetes 1.9 includes a number of example projects which can serve as a blueprint for your own projects: In order to update from the previous version 5 to version 6 of client-go, the library itself as well as certain third-party dependencies must be updated. Previously, this process had been tedious due to the fact that a lot of code got refactored or relocated within the existing package layout across releases. Fortunately, far less code had to move in the latest version, which should ease the upgrade procedure for most users. In the past
These tags have limited test coverage, but can be used by early adopters of client-go and the other libraries. Moreover, they help to vendor the correct version of
Also note that only these tags correspond to tested releases of Kubernetes. If you depend on the release branch, e.g., release-1.9, your client is running on unreleased Kubernetes code. In general, the list of which dependencies to vendor is automatically generated and written to the file Godeps/Godeps.json. Only the revisions listed there are tested. This means especially that we do not and cannot test the code-base against master branches of our dependencies. This puts us in the following situation depending on the used vendoring tool: Even with the deficiencies of golang/dep today, dep is slowly becoming the de-facto standard in the Go ecosystem. With the necessary care and the awareness of the missing features, dep can be (and is!) used successfully. Here’s a demonstration of how to update a project with client-go 5 to the latest version 6 using dep: (If you are still running client-go version 4 and want to play it safe by not skipping a release, now is a good time to check out
API group changes
Validation for CustomResources
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
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 or equal to 10
spec.version in body should be one of [v1.0.0 v1.0.1]
Creating namespaced informers
import “k8s.io/client-go/informers”
...
sharedInformers := informers.NewFilteredSharedInformerFactory(
client,
30\*time.Minute,
“some-namespace”,
func(opt \*metav1.ListOptions) {
opt.LabelSelector = “foo=bar”
},
)
Polymorphic scale client
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")
Type-safe DeepCopy
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)
}
Code generation and CustomResources
Comment Blocks
// second block above
// +k8s:some-tag
// first block above
// +k8s:another-tag
type Foo struct {}
Custom Client Methods
// genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/kubernetes/pkg/apis/autoscaling.Scale,result=k8s.io/kubernetes/pkg/apis/autoscaling.Scale
Resolving Golang Naming Conflicts
// +groupName=example2.example.com
// +groupGoName=SecondExample
Example projects
Vendoring
State of the published repositories
State of vendoring of client-go
Updating dependencies – golang/dep