client-go
Client-go
The Client Library– k8s.io/client-go
The kubernetes programming interface in Go mainly consists of the k8s.io/client-go
library (for brevity we will just call it client-go
going foward).
k8s.io/client-go
is a typical web service client library that supports all API types that are officially part of Kubernetes. It can be used to execute the usual REST verbs.
- Create
- Get
- List
- Update
- Delete
- Patch
- Watch
For each Kubernetes 1.x.y release, there is a client-go release with a matching tag kubernetes-1.x.y.
Most of your code that speaks to Kubernetes APIs will use tools/clientcmd/
to set up a client from a kubeconfig
file, and kubernetes/
for the actual Kubernetes API clients.
Kubernetes API Types–k8s.io/api
As we have seen, client-go
holds the client interfaces. The Kubernetes API Go types for objects like pods, services, and deployments are located in their oven repository. It is accessed as ki8.io/api
in Go code.
Pods are part of the legacy API group(often also called the “core” group) version v1
Hence, the Pod Go types is found in k8s.io/api/core/v1
, and similarly for all other API types in Kubernetes. The actual Go types are contained in a type.go
file. In addition, there are other files, most of them automatically generated by a code generator.
1# k8s.io/api/core/v1
2Pod
3Service
4ReplicaSet
API Machinery–k8s.io/apimachinery
Last but not least, there is a third repository called API Machinery, which is used as k8s.io/apimachinery
in Go. It include all the generic building blocks to implement a Kubernetes-like API. API machinery is not restricted to container management, so, for example, it could be used to build APIs for an online shop or any other business-specific domain.
Nevertheless, you’ll meet a lot of API Machinery packages in Kubernetes-native Go code. An important one is k8s.io/apimachinery/pkg/api/meta/v1
. It contains many of the generic API types such as ObjectMeta
, TypeMeta
, GetOptions
, and ListOptions
.
1# pkg/apis/meta/v1
2ObjectMeta
3TypeMeta
4ListOptions
5DeleteOptions
6GetOptions
7Status
8Events
Create and Using a client
when running a binary inside of a pod in a cluster, the kubelet
will automatically mount a service account into the container at /var/run/secrets/kuberntes.io/serviceaccount
. It replaces the kubeconfig
file just mentioned and can easily be turned into a rest.Config
via the rest.InClusterConfig()
method.
1package main
2
3import (
4 "context"
5 "encoding/json"
6 "flag"
7 "fmt"
8 "os"
9 // "path/filepath"
10
11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 "k8s.io/client-go/kubernetes"
13 // "k8s.io/client-go/rest"
14 "k8s.io/client-go/tools/clientcmd"
15)
16
17func main() {
18 kubeconfig := flag.String("kubeconfig", "./config", "kubeconfig file")
19 flag.Parse()
20
21 //************ Running a Binary Inside of a Pod in Cluster *****************
22 // config, err := rest.InClusterConfig()
23 // if err != nil {
24 // // fallback to kubeconfig
25 // kubeconfig2 := filepath.Join("~", ".kube", "config")
26 // if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
27 // kubeconfig2 = envvar
28 // }
29 // }
30
31 // Import clientcmd from client-go in order to parse the kubernetes config.
32 // The client configuration with server name, credentials.
33 // Retrun a rest.Config
34 config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
35 if err != nil {
36 fmt.Printf("The kuber config can not be loaded: %v\n", err)
37 os.Exit(1)
38 }
39
40 // You can enable protobuf for native kubernetes resource cliensts by modifying
41 config.AcceptContentTypes =
42 "application/vnd.kubernetes.protobuf,application/json"
43
44 config.ContentType = "application/vnd.kubernetes.protobuf"
45
46 // Clinetset contains multiple clients for all native kubernetes resources.
47 // Create actual kubernetes client set.
48 clientset, err := kubernetes.NewForConfig(config)
49 if err != nil {
50 fmt.Printf("create clientset failed: %v", err)
51 os.Exit(1)
52 }
53
54 // The Get call send and HTTP GET request to
55 // /api/v1/namespace/calico-apiserver/pods/calico-apiserver-xxx
56 pod, err := clientset.CoreV1().Pods("calico-apiserver").Get(context.TODO(),
57 "calico-apiserver-5b68b6b54-ngfdw", metav1.GetOptions{})
58
59 if err != nil {
60 os.Exit(1)
61 }
62
63 strByte, _ := json.Marshal(pod)
64 fmt.Println(string(strByte))
65
66}
group ?
Versioning and Compatibility
We have seen in the previous section that pods are in v1
of core group
. The core group actually exists in only one version today. There are other groups, though– for example, the apps group
s, which exists in v1
, v1beta2,
and v1beta1
.
Clients are hardcode to a version, and the application developer has to select the right API group version in order to speak to the cluster at hand.
A second aspect of compatibility is the meta API features of the API server that client-go is speaking to.
There are options structs for CURD verbs, like CreateOptions
,GetOptions
,UpdateOptions
, and DeleteOptions
. Another important one is ObjectMeta
, which part of every kind. All of these are frequently extended with new features; we usually call them API machinery features
.
1// k8s.io/apimachinery/pkg/apis/meta/v1/types.go
2// Delete options may be provided when deleting an API object
3type DeleteOptions struct{
4 TypeMeta
5 GracePeriodSeconds *int64
6 Preconditions *Preconditions
7 OrphanDependents *bool
8 PropagationPolicy *DeletePropagation
9
10 // When present, indicates that modifications should not be
11 // persisted. An invalid or unrecognized dryRun directive will
12 // result in an error response and no further processing of the
13 // request. Valid values are:
14 // - All: all dry run stages will be processed
15 // +optional
16 DryRun []string
17 // Was added in Kubernetes in 1.12.
18}
API versions and Compatibility Guarantees
Kubernetes versions all API Groups. A common Kubernetes-style versioning scheme is used, which consists of alpha, beta, and GA(general availability) versions.
-
alpha versions
v1alpha1, v1alpha2, v2alpha1
-
beta versions
v1beta1, v1beta2, v2beta1
-
v1, v2
GA
In connections to API group versions, there are two important points to keep in mind.
- API groups versions apply to API resources as a whole, like the format of pods or service.
- Furthermore, API groups versions play a role in accessing the API.
Kubernetes Objects in Go
From the type system point of view, Kubenetes objects fulfill a Go interface called runtime.Object form the package k8s.io/apimachinery/pkg/runtime
.
1// Object interface must be support by all API types registered with Scheme.
2// Since Objects in a scheme are expected to be serialized to the wire, the interface an Object
3// must provide to the Scheme allows serializers to set the kind, version, and group the object
4// is represented as. An Object may choose to return a no-op ObjectKindAccessor in case where
5// it is not expected to be serialized.
6type Object interface{
7 GetObjectKind() schema.ObjectKind
8 DeepCopyObject() Object
9}
Here, scheme.ObjectKind
is a another simple interface from k8s.io/apimachinery/pkg/runtime/schema
.
1// All objects that are serialized form a Scheme encode their type information.
2// This interface is used by serialization to set type information from the Scheme onto the
3// serialized version of an Object. For objects that cannot be serialized or have unique
4// requirements, this interface may be no-op.
5type ObjectKind interface{
6 SetGroupVersionKind(kind GroupVersionKind)
7 GroupVersionKind() GroupVersionKind
8}
In other words, a Kubernetes Object in Go is a data structure that can:
- Return and set the
GroupVersionKind
- Be deep-copied
A deep copy is a clone of the data structure such that it does not share any memory the the original object. It is used wherever code has to mutate an object without modifying the original.
TypeMeta
Kubernetes objects form k8s.io/api
implement the type getter and setter of scheme.ObjectKind
by embedding the metav1.TypeMeta
struct form the package k8s.io/apimachinery/apis/meta/v1
.
1// TypeMeta describes an individual object in an API response or request
2// with strings representing the type of the object and its API schema version.
3// Structures that are versioned or persisted should inline TypeMeta.
4//
5// +k8s:deepcopy-gen=false
6type TypeMeta struct {
7 // Kind is a string value representing the REST resource this object represents.
8 // Servers may infer this from the endpoint the client submits requests to.
9 // Cannot be updated.
10 // In CamelCase.
11 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
12 // +optional
13 Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"`
14
15 // APIVersion defines the versioned schema of this representation of an object.
16 // Servers should convert recognized schemas to the latest internal value, and
17 // may reject unrecognized values.
18 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
19 // +optional
20 APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,2,opt,name=apiVersion"`
21}
with this, a pod declaration in Go looks like this form package k8s.io/api/core/v1/types.go
.
1// Pod is a collection of containers that can run on a host. This resource is created
2// by clients and scheduled onto hosts.
3type Pod struct {
4 metav1.TypeMeta `json:",inline"`
5 // Standard object's metadata.
6 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
7 // +optional
8 metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
9
10 // Specification of the desired behavior of the pod.
11 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
12 // +optional
13 Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
14
15 // Most recently observed status of the pod.
16 // This data may not be up to date.
17 // Populated by the system.
18 // Read-only.
19 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
20 // +optional
21 Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
22}
As you can see, TypeMeta is embedded. Moreover, the pod type has JSON tags that also declare TypeMeta as being inlined.
This match the YAML representation of a Pod.
1apiVersion: v1
2kind: Pod
3metadata:
4 namespace: default
5 name: example
6spec:
7 containers:
8 - name: hello
9 images: debian:latest
10 command:
11 - /bin/sh
12 args:
13 - -c
14 - echo "hello world"; sleep 10000
The version is stored in TypeMeta.APIVersion, the kind in TypeMeta.Kind.
The Core Group is different for historic reasons
Pods and many other types that were added to Kubernetes very early on are part of the
core group
– often also called thelegacy group
– which is represented by the empty string. Hence,apiVersion
is just set to “v1
”.Eventually API groups were added to Kubernetes, and the group name separated by slash, was prepended to apiVersion. In the case of apps, the version would be
apps/v1
. Hence, the apiVersion field is actually misnamed; it stores the APIgroup name
and theversion string
. This is for historic reasons because apiVersion was defined when only thecore group
–and none of these other API groups–existed.
ObjectMeta
most top-level objects have a field of type metav1.ObjectMeta, again from the package k8s.io/apimachinery/pkgs/meta/v1
.
1// ObjectMeta id metadata that all persisted resources must have, which includes all objects user must create.
2type ObjectMeta struct{
3 // Name must be unique within a namespace.
4 Name string
5 GenerateName string
6 // Namespace defines the space within which each name must be unique.
7 Namespace string
8 SelfLink string
9 UID types.UID
10 // An opaque value that represents the internel version of this object that can be used by
11 // clients to determine when objects have changes. corresponds to a key in etcd.
12 ResourceVersion string
13 Generation int64
14 CreateTimestamp Time
15 DeleteTimestamp *Time
16 DeleteGracePeriodSeconds *int64
17 // Map of string keys and values that can be used to organize and categorize objects.
18 Labels map[string]string
19 // Annotations is an unstructrued key value map stored with a resource that may be set
20 // by externel tools to store and retrieve arbitrary metadata.
21 Annotations map[string]string
22 OwnerReferences []OwnerReference
23 // Finalizers must be empty before the object is deleted from the registry.
24 Finalizers []string
25 // The name of cluster which the object belongs to.
26 ClusterName string
27 ManagedFields []ManagedFieldsEntry
28}
spec and status
Finally, nearly every top-level object has a spec
and a status
section. This conventions comes from the declarative nature
of the Kubernetes API: spec
is the user desire, and status
it the outcome of that desire, usually filled by a controller in the system.
There are only a few exception to the spec and status convention in the system-for example, endpoints
in the core groups, or RBAC objects like ClusterRole
.
Client Set
A client set gives access to clients for multiple API groups and resources. In the case of kubernetes.NewForConfig(config)
from k8s.io/client-go/kubernetes
, we get access to all API groups and resources defined in k8s.io/api
. This is, with a few exception–such as APIService
and CustomerResourcesDefinition
– the whole set of resources served by the Kubernetes API server.
The client set main interface in k8s.io/client-go/kubernetes/clientset.go
for Kubernetes-native resources like this:
1type Interface interface{
2 Discover() discover.DiscoverInterface
3 AppsV1() appsv1.AppsV1Interface
4 AppsV1beta1() appsv1beta1.AppsV1beta1Interface
5 AppsV1beta2() appsv1beta2.AppsV1beta2Interface
6 AuthenticationV1() authenticationv1.AuthenticationV1Interface
7 AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1betaInterface
8 AuthorizationV1() authorizationv1.AuthorizationV1Interface
9 AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface
10 ...
11}
Behind each GroupVersion method, we find the resource of the API group.
1type AppsV1beta1Interface interface {
2 RESTClinet() rest.Interface
3 ControllerRevisionGetter
4 DeploymentsGetter
5 StatefulSetsGetter
6}
With RESTClinet being a generic REST client, and one interface per resource, as in:
1// DeploymentsGetter has a method to return a DeploymentInterface.
2// A group's client should implement this interface.
3type DeploymentsGetter interface{
4 Deployments(name string) DeploymentInterface
5}
6
7// DeploymentInterface has methods to work with Deployment resources.
8type DeploymentInterface interface {
9 Create(ctx context.Context, deployment *v1beta1.Deployment, opts v1.CreateOptions) (*v1beta1.Deployment, error)
10 Update(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (*v1beta1.Deployment, error)
11 UpdateStatus(ctx context.Context, deployment *v1beta1.Deployment, opts v1.UpdateOptions) (*v1beta1.Deployment, error)
12 Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
13 DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
14 Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Deployment, error)
15 List(ctx context.Context, opts v1.ListOptions) (*v1beta1.DeploymentList, error)
16 Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
17 Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Deployment, err error)
18 Apply(ctx context.Context, deployment *appsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error)
19 ApplyStatus(ctx context.Context, deployment *appsv1beta1.DeploymentApplyConfiguration, opts v1.ApplyOptions) (result *v1beta1.Deployment, err error)
20 DeploymentExpansion
21}
Depending on the scope of the resource–that is , whether it is cluster or namespace scoped– the accessor(here DeploymentsGetter) may or may not have a namespace argument.
Status Subresources: UpdateStatus
Deployments have a so-called status subresource
. This means that UpdateStatus
uses an additional HTTP endpoint suffixed with /status
. While updates on the /api/apps/v1beta1/namespace/ns/deployments/name
endpoints can change only the spce of the deployment, the endpoint /api/apps/v1beta1/namespace/ns/deployments/name/status
can change only the status of the object.
By default the client-gen
generates the UpdateStatus()
method.
Listings and Deletions
DeleteCollections
allows us to delete multiple objects of namespace at once. The ListOptions
parameters allows us to define which objects should be deleted using a filed
or label selector
:
1// k8s.io/apimachinery/pkg/apis/meta/v1/types.go
2// ListOptions is the query options to a standard REST list call.
3type ListOptions struct{
4 TypeMeta
5 // A selector to restrict the list of returned objects by their labels.
6 LabelSelector string
7 // A selector to restrict the list of returned objects by their fields.
8 FieldSelector string
9 Watch bool
10 AllowWatchBookmarks bool
11 ResourceVersion string
12 ResourceVersionMatch ResourceVersionMatch
13 TimeSecond *int64
14 Limit int64
15 Continue string
16}
Watches
Watch
gives an event interface for all changes(adds, removes, and updates) to objects. The returned watch.Interface
form k8s.io/apimachinery/pkg/watch/watch.go
.
1// Interface can be implemented by anything that knows how to watch and report changes.
2type Interface interface{
3 // Stop watching. Will close the channel returned by ResoultChan(). Release any resources
4 // used by watch.
5 Stop()
6 // Returns a chan which will receive all the events. If an errors occurs or Stop()
7 // is canceled, the implementation will close this channel and release any resources
8 // used by watch.
9 ResultChan() <-chan Event
10}
The result channel of watch interface returns three kinds of events.
1// EventType defines the possible types of events
2type EventTypes string
3const (
4 Added EventType = "ADDED"
5 Modified EventType = "MODIFIED"
6 Deleted EventType = "DELETED"
7 Bookmark EventType = "BOOKMARK"
8 Error EventType = "ERROR"
9)
10
11// Event represents a single event to watched resource.
12Type Event struct{
13 Type EventType
14
15 Object runtime.Object
16}
While it is tempting to use this interface directly, in practice it is actually discouraged in favor of informers.
Informers are a combination of this event interface and in-memory cache with indexed lookup. This is by far the most common use case for watches. Under the hood informers first call List
on the client to get the set of all objects(as a baseline for the cache) and then Watch
to update the cache.
Client Expansion
DeploymentExpansion
is actually an empty interface. It is used to add custom client behavior, but it’s hardly used in Kubernetes nowdays. Instead, the client generator allows up to add custom methods in a declarative way.
Note again that all of those methods in DeploymentInterface
neither expect valid information in the TypeMeta
fields Kind
and APIVersion
, nor set those fields on Get() and List(). These fields are filled with real values only on the wire
.
Client Options
Client-go
What is clientset?
ClientSet: every Resource has their own client, and ClientSet is a client set for different Resources. ClientSet on handle the k8s internal resource, generate by client-gen.
DynamicClient is for CRD resources.
DiscoverClient: find all api-resources
获取kube conf的方式:
- file path
~/.kube/config
KUBECONFIG
合并多个kubeconfig 信息