项目作者: ericchiang

项目描述 :
一个简单的Kubernetes Go客户端
高级语言: Go
项目地址: git://github.com/ericchiang/k8s.git
创建时间: 2016-11-26T07:29:17Z
项目社区:https://github.com/ericchiang/k8s

开源协议:Apache License 2.0

下载


A simple Go client for Kubernetes

GoDoc
Build Status

A slimmed down Go client generated using Kubernetes’ protocol buffer support. This package behaves similarly to official Kubernetes’ Go client, but only imports two external dependencies.

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "github.com/ericchiang/k8s"
  7. corev1 "github.com/ericchiang/k8s/apis/core/v1"
  8. )
  9. func main() {
  10. client, err := k8s.NewInClusterClient()
  11. if err != nil {
  12. log.Fatal(err)
  13. }
  14. var nodes corev1.NodeList
  15. if err := client.List(context.Background(), "", &nodes); err != nil {
  16. log.Fatal(err)
  17. }
  18. for _, node := range nodes.Items {
  19. fmt.Printf("name=%q schedulable=%t\n", *node.Metadata.Name, !*node.Spec.Unschedulable)
  20. }
  21. }

Requirements

Usage

Create, update, delete

The type of the object passed to Create, Update, and Delete determine the resource being acted on.

  1. configMap := &corev1.ConfigMap{
  2. Metadata: &metav1.ObjectMeta{
  3. Name: k8s.String("my-configmap"),
  4. Namespace: k8s.String("my-namespace"),
  5. },
  6. Data: map[string]string{"hello": "world"},
  7. }
  8. if err := client.Create(ctx, configMap); err != nil {
  9. // handle error
  10. }
  11. configMap.Data["hello"] = "kubernetes"
  12. if err := client.Update(ctx, configMap); err != nil {
  13. // handle error
  14. }
  15. if err := client.Delete(ctx, configMap); err != nil {
  16. // handle error
  17. }

Get, list, watch

Getting a resource requires providing a namespace (for namespaced objects) and a name.

  1. // Get the "cluster-info" configmap from the "kube-public" namespace
  2. var configMap corev1.ConfigMap
  3. err := client.Get(ctx, "kube-public", "cluster-info", &configMap)

When performing a list operation, the namespace to list or watch is also required.

  1. // Pods from the "custom-namespace"
  2. var pods corev1.PodList
  3. err := client.List(ctx, "custom-namespace", &pods)

A special value AllNamespaces indicates that the list or watch should be performed on all cluster resources.

  1. // Pods in all namespaces
  2. var pods corev1.PodList
  3. err := client.List(ctx, k8s.AllNamespaces, &pods)

Watches require a example type to determine what resource they’re watching. Watch returns an type which can be used to receive a stream of events. These events include resources of the same kind and the kind of the event (added, modified, deleted).

  1. // Watch configmaps in the "kube-system" namespace
  2. var configMap corev1.ConfigMap
  3. watcher, err := client.Watch(ctx, "kube-system", &configMap)
  4. if err != nil {
  5. // handle error
  6. }
  7. defer watcher.Close()
  8. for {
  9. cm := new(corev1.ConfigMap)
  10. eventType, err := watcher.Next(cm)
  11. if err != nil {
  12. // watcher encountered and error, exit or create a new watcher
  13. }
  14. fmt.Println(eventType, *cm.Metadata.Name)
  15. }

Both in-cluster and out-of-cluster clients are initialized with a primary namespace. This is the recommended value to use when listing or watching.

  1. client, err := k8s.NewInClusterClient()
  2. if err != nil {
  3. // handle error
  4. }
  5. // List pods in the namespace the client is running in.
  6. var pods corev1.PodList
  7. err := client.List(ctx, client.Namespace, &pods)

Custom resources

Client operations support user defined resources, such as resources provided by CustomResourceDefinitions and aggregated API servers. To use a custom resource, define an equivalent Go struct then register it with the k8s package. By default the client will use JSON serialization when encoding and decoding custom resources.

  1. import (
  2. "github.com/ericchiang/k8s"
  3. metav1 "github.com/ericchiang/k8s/apis/meta/v1"
  4. )
  5. type MyResource struct {
  6. Metadata *metav1.ObjectMeta `json:"metadata"`
  7. Foo string `json:"foo"`
  8. Bar int `json:"bar"`
  9. }
  10. // Required for MyResource to implement k8s.Resource
  11. func (m *MyResource) GetMetadata() *metav1.ObjectMeta {
  12. return m.Metadata
  13. }
  14. type MyResourceList struct {
  15. Metadata *metav1.ListMeta `json:"metadata"`
  16. Items []MyResource `json:"items"`
  17. }
  18. // Require for MyResourceList to implement k8s.ResourceList
  19. func (m *MyResourceList) GetMetadata() *metav1.ListMeta {
  20. return m.Metadata
  21. }
  22. func init() {
  23. // Register resources with the k8s package.
  24. k8s.Register("resource.example.com", "v1", "myresources", true, &MyResource{})
  25. k8s.RegisterList("resource.example.com", "v1", "myresources", true, &MyResourceList{})
  26. }

Once registered, the library can use the custom resources like any other.

  1. func do(ctx context.Context, client *k8s.Client, namespace string) error {
  2. r := &MyResource{
  3. Metadata: &metav1.ObjectMeta{
  4. Name: k8s.String("my-custom-resource"),
  5. Namespace: &namespace,
  6. },
  7. Foo: "hello, world!",
  8. Bar: 42,
  9. }
  10. if err := client.Create(ctx, r); err != nil {
  11. return fmt.Errorf("create: %v", err)
  12. }
  13. r.Bar = -8
  14. if err := client.Update(ctx, r); err != nil {
  15. return fmt.Errorf("update: %v", err)
  16. }
  17. if err := client.Delete(ctx, r); err != nil {
  18. return fmt.Errorf("delete: %v", err)
  19. }
  20. return nil
  21. }

If the custom type implements proto.Message, the client will prefer protobuf when encoding and decoding the type.

Label selectors

Label selectors can be provided to any list operation.

  1. l := new(k8s.LabelSelector)
  2. l.Eq("tier", "production")
  3. l.In("app", "database", "frontend")
  4. var pods corev1.PodList
  5. err := client.List(ctx, "custom-namespace", &pods, l.Selector())

Subresources

Access subresources using the Subresource option.

  1. err := client.Update(ctx, &pod, k8s.Subresource("status"))

Creating out-of-cluster clients

Out-of-cluster clients can be constructed by either creating an http.Client manually or parsing a Config object. The following is an example of creating a client from a kubeconfig:

  1. import (
  2. "io/ioutil"
  3. "github.com/ericchiang/k8s"
  4. "github.com/ghodss/yaml"
  5. )
  6. // loadClient parses a kubeconfig from a file and returns a Kubernetes
  7. // client. It does not support extensions or client auth providers.
  8. func loadClient(kubeconfigPath string) (*k8s.Client, error) {
  9. data, err := ioutil.ReadFile(kubeconfigPath)
  10. if err != nil {
  11. return nil, fmt.Errorf("read kubeconfig: %v", err)
  12. }
  13. // Unmarshal YAML into a Kubernetes config object.
  14. var config k8s.Config
  15. if err := yaml.Unmarshal(data, &config); err != nil {
  16. return nil, fmt.Errorf("unmarshal kubeconfig: %v", err)
  17. }
  18. return k8s.NewClient(&config)
  19. }

Errors

Errors returned by the Kubernetes API are formatted as unversioned.Status objects and surfaced by clients as *k8s.APIErrors. Programs that need to inspect error codes or failure details can use a type cast to access this information.

  1. // createConfigMap creates a configmap in the client's default namespace
  2. // but does not return an error if a configmap of the same name already
  3. // exists.
  4. func createConfigMap(client *k8s.Client, name string, values map[string]string) error {
  5. cm := &v1.ConfigMap{
  6. Metadata: &metav1.ObjectMeta{
  7. Name: &name,
  8. Namespace: &client.Namespace,
  9. },
  10. Data: values,
  11. }
  12. err := client.Create(context.TODO(), cm)
  13. // If an HTTP error was returned by the API server, it will be of type
  14. // *k8s.APIError. This can be used to inspect the status code.
  15. if apiErr, ok := err.(*k8s.APIError); ok {
  16. // Resource already exists. Carry on.
  17. if apiErr.Code == http.StatusConflict {
  18. return nil
  19. }
  20. }
  21. return fmt.Errorf("create configmap: %v", err)
  22. }