掘金 后端 ( ) • 2024-04-05 11:18

我们如何与 Kubernetes 进行交互

最常用的方式是使用一个名为 https://github.com/kubernetes/kubectl 的命令行工具。

有时我们需要开发应用程序来与 Kubernetes 集群进行交互。

client-go

client-go 是用于与 kubernetes 集群通信的 Go 客户端。在 client-go 中,我们可以使用 Pod API 与 Kubernetes 进行通信并与 Pod 进行交互。

Pod

Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

// https://github1s.com/kubernetes/kubernetes/blob/master/pkg/apis/core/types.go#L3995-L4010
type Pod struct {
	metav1.TypeMeta
	// +optional
	metav1.ObjectMeta

	// Spec defines the behavior of a pod.
	// +optional
	Spec PodSpec

	// Status represents the current information about a pod. This data may not be up
	// to date.
	// +optional
	Status PodStatus
}

Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及运行这些容器的声明。 Pod 中的内容总是一同调度,在共享的上下文中运行。 Pod构建了一个 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。

我们通过client-go与Kubernetes交互对Pod进行管理,Pod相关的的API如下:

// https://github.com/kubernetes/client-go/blob/master/kubernetes/typed/core/v1/pod.go
// PodInterface has methods to work with Pod resources.
    type PodInterface interface {
    	Create(ctx context.Context, pod *v1.Pod, opts metav1.CreateOptions) (*v1.Pod, error)
    	Update(ctx context.Context, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)
    	UpdateStatus(ctx context.Context, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)
    	Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
    	DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
    	Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Pod, error)
    	List(ctx context.Context, opts metav1.ListOptions) (*v1.PodList, error)
    	Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
    	Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Pod, err error)
    	Apply(ctx context.Context, pod *corev1.PodApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Pod, err error)
    	ApplyStatus(ctx context.Context, pod *corev1.PodApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Pod, err error)
    	UpdateEphemeralContainers(ctx context.Context, podName string, pod *v1.Pod, opts metav1.UpdateOptions) (*v1.Pod, error)
    }

可以看到除了常用的CRUD的操作外,还有ApplyApplyStatusWatch等Kubernetes提供的API

编写程序读取pod信息

我们编写一个小程序,读取集群的pod信息

    ➜  golang mkdir -p client-go-app
    ➜  golang cd client-go-app
    ➜  client-go-app go mod init github.com/jxs1211/client-go-app
    go: creating new go.mod: module github.com/jxs1211/client-go-app
    ➜  client-go-app code .                                                                              
    ➜  client-go-app 

从本地读取配置文件

    package main

    import (
    	"log"
    	"os/exec"
    	"os/user"
    	"strings"
    )

    func main() {
    	user, err := user.Current()
    	if err != nil {
    		log.Fatal(err)
    	}
    	cmd := exec.Command("echo", user.HomeDir+"/.kube/config")
    	output, err := cmd.Output()
    	if err != nil {
    		log.Fatal(err)
    	}

    	configPath := strings.TrimSpace(string(output))
    	log.Println("kube config file path: ", configPath)
    }

加载配置文件

    package main

    import (
    	"log"
    	"os/exec"
    	"os/user"
    	"strings"

    	"k8s.io/client-go/tools/clientcmd"
    )

    func main() {
    	// read kube config path from homedir
    	user, err := user.Current()
    	if err != nil {
    		log.Fatal(err)
    	}
    	cmd := exec.Command("echo", user.HomeDir+"/.kube/config")
    	output, err := cmd.Output()
    	if err != nil {
    		log.Fatal(err)
    	}

    	configPath := strings.TrimSpace(string(output))
    	log.Println("kube config file path: ", configPath)
    	// load configuration
    	config, err := clientcmd.BuildConfigFromFlags("", configPath)
    	if err != nil {
    		log.Fatal(err)
    	}
    	log.Println(config)
    }

安装依赖


    ➜  client-go-app go mod tidy                                 
    go: finding module for package k8s.io/client-go/tools/clientcmd
    go: finding module for package k8s.io/client-go/rest
    go: downloading k8s.io/client-go v0.29.3
    go: found k8s.io/client-go/rest in k8s.io/client-go v0.29.3
    go: found k8s.io/client-go/tools/clientcmd in k8s.io/client-go v0.29.3
    go: downloading k8s.io/apimachinery v0.29.3
    go: downloading k8s.io/api v0.29.3
    go: downloading github.com/golang/protobuf v1.5.4
    go: downloading google.golang.org/protobuf v1.33.0
    go: downloading gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405

读取配置并创建client


    	clientset, err := kubernetes.NewForConfig(config)
    	if err != nil {
    		log.Fatal(err)
    	}
    	log.Println(clientset)

通过client获取集群中pod的信息

// main.go
...
    	podList, err := clientset.CoreV1().Pods("kube-system").List(context.Background(), metav1.ListOptions{})
    	if err != nil {
    		log.Fatal(err)
    	}
    	for _, pod := range podList.Items {
    		log.Println(pod.Name)
    	}
...

启动程序

    ➜  client-go-app go run main.go
    2024/03/22 18:12:41 kube config file path:  /home/going/.kube/config
    2024/03/22 18:12:41 &{0xc00049d320 0xc0003c92d0 0xc0003c92e0 0xc0003c92f0 0xc0003c9300 0xc0003c9310 0xc0003c9320 0xc0003c9330 0xc0003c9340 0xc0003c9350 0xc0003c9360 0xc0003c9370 0xc0003c9380 0xc0003c9390 0xc0003c93a0 0xc0003c93b0 0xc0003c93c0 0xc0003c93d0 0xc0003c93e0 0xc0003c93f0 0xc0003c9400 0xc0003c9410 0xc0003c9420 0xc0003c9430 0xc0003c9440 0xc0003c9450 0xc0003c9460 0xc0003c9470 0xc0003c9480 0xc0003c9490 0xc0003c94a0 0xc0003c94b0 0xc0003c94c0 0xc0003c94d0 0xc0003c94e0 0xc0003c94f0 0xc0003c9500 0xc0003c9510 0xc0003c9520 0xc0003c9530 0xc0003c9540 0xc0003c9550 0xc0003c9560 0xc0003c9570 0xc0003c9580 0xc0003c9590 0xc0003c95a0 0xc0003c95b0 0xc0003c95c0 0xc0003c95d0 0xc0003c95e0 0xc0003c95f0}
    2024/03/22 18:12:41 coredns-76f75df574-2xpv8
    2024/03/22 18:12:41 coredns-76f75df574-ncccv
    2024/03/22 18:12:41 etcd-test-control-plane
    2024/03/22 18:12:41 kindnet-cvbck
    2024/03/22 18:12:41 kube-apiserver-test-control-plane
    2024/03/22 18:12:41 kube-controller-manager-test-control-plane
    2024/03/22 18:12:41 kube-proxy-9428x
    2024/03/22 18:12:41 kube-scheduler-test-control-plane

创建一个deployment,通过client-go获取deployment的信息。


    ➜  client-go-app cat nginx-deployment.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80

创建deployment

    ➜  client-go-app ka -f nginx-deployment.yaml       
    deployment.apps/nginx-deployment created
    ➜  client-go-app kg pod
    NAME                                READY   STATUS    RESTARTS   AGE
    nginx-deployment-7c79c4bf97-4bgnf   1/1     Running   0          9s
    nginx-deployment-7c79c4bf97-9qscr   1/1     Running   0          9s
    nginx-deployment-7c79c4bf97-kzpb9   1/1     Running   0          9s
    ➜  client-go-app kg deploy     
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           111s

使用client获取特定namespace下的deployment

    	// create a deployment with nginx image
    	deploy, err := clientset.AppsV1().Deployments("default").Get(context.Background(), "nginx-deployment", metav1.GetOptions{})
    	if err != nil {
    		log.Fatal(err)
    	}
    	log.Println("deployment name: ", deploy.Name)

执行程序

    ➜  client-go-app go run main.go
    ...
    2024/03/22 18:30:21 deployment name:  nginx-deployment

client-go版本与Kubernetes的版本的兼容性

由于 Kubernetes 向后兼容客户端,旧版本的 client-go 可与许多不同版本的 Kubernetes 集群一起使用。我们在开发是最好保持client-go和Kubernetes的版本兼容性。

Compatibility matrix

Kubernetes 1.23 Kubernetes 1.24 Kubernetes 1.25 Kubernetes 1.26 Kubernetes 1.27 Kubernetes 1.28 kubernetes-1.23.0/v0.23.0 ✓ +- +- +- +- +- kubernetes-1.24.0/v0.24.0 +- ✓ +- +- +- +- kubernetes-1.25.0/v0.25.0 +- +- ✓ +- +- +- kubernetes-1.26.0/v0.26.0 +- +- +- ✓ +- +- kubernetes-1.27.0/v0.27.0 +- +- +- +- ✓ +- kubernetes-1.28.0/v0.28.0 +- +- +- +- +- ✓ HEAD +- +- +- +- +- +-
  • 代表client-go 和 Kubernetes 版本中的功能和 API 对象完全相同。
  • + 代表client-go 具有一些在 Kubernetes 集群中可能不存在的功能或 API 对象,这可能是因为 client-go 具有额外的新 API,或者服务器已删除了旧的 API。但是,它们共有的部分(即大多数 API)将正常工作。请注意,alpha API 可能会在单个版本中消失或发生重大变化。