1. 初始化项目
git:(master) ✗ ls
README.md main.go
git:(master) ✗ go mod init app
go: creating new go.mod: module app
go: to add module requirements and sums:
go mod tidy
git:(master) ✗ ls
README.md go.mod main.go
  1. 解决项目依赖
✗ go mod tidy
go: finding module for package k8s.io/client-go/tools/clientcmd
go: finding module for package k8s.io/client-go/kubernetes
go: finding module for package k8s.io/apimachinery/pkg/apis/meta/v1
go: finding module for package k8s.io/client-go/rest
go: found k8s.io/apimachinery/pkg/apis/meta/v1 in k8s.io/apimachinery v0.23.5
go: found k8s.io/client-go/kubernetes in k8s.io/client-go v0.23.5
go: found k8s.io/client-go/rest in k8s.io/client-go v0.23.5
go: found k8s.io/client-go/tools/clientcmd in k8s.io/client-go v0.23.5

git:(master) ✗ ls
README.md go.mod go.sum main.go
  1. 运行代码,获取指定命名空间下的pod、deployment、daemonset等信息:
git:(master) ✗ go run main.go 
获取default namespace下的pod
nginx-deployment-9456bbbf9-78z87
nginx-deployment-9456bbbf9-7tgnm
nginx-deployment-9456bbbf9-n4mch
test-incluster-client-go
获取default namespace下的deployment的名字
nginx-deployment
获取kube-system namespace下的daemonset的名字
kube-proxy
获取get node的方法
minikube
获取kube-system svc
kube-dns
  1. 代码解读:​​项目代码​
package main

import (
"context"
"flag"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)

func main() {
// 一个简单的client-go使用外部kubeconfig文件交互k8s API,这里指定minikube的config配置文件路径
kubeconfig := flag.String("kubeconfig", "/Users/XXXX/.kube/config", "location to your kubeconfig file")
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
// handle error
fmt.Printf("erorr %s building config from flags\n", err.Error())
config, err = rest.InClusterConfig()
if err != nil {
fmt.Printf("error %s, getting inclusterconfig", err.Error())
}
}
//实例化clientset对象
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
// handle error
fmt.Printf("error %s, creating clientset\n", err.Error())
}
ctx := context.Background()
fmt.Println("获取default namespace下的pod")

//1、获取default下pod的名字
pods, err := clientset.CoreV1().Pods("default").List(ctx, metav1.ListOptions{})
if err != nil {
// handle error
fmt.Printf("error %s, while listing all the pods from default namespace\n", err.Error())
}

//在k8s源码当中https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/api/core/v1/types.go
//type PodList struct 定义了podlist ,Items []Pod定义了包含切片Pod的项目
//metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +optional
//metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// List of pods.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md
//Items []Pod `json:"items" protobuf:"bytes,2,rep,name=items"`

//所以我们就可以之间使用for循环取出此切片的长度了
for _, pod := range pods.Items {
fmt.Printf("%s\n", pod.Name)
}


fmt.Println("获取default namespace下的deployment的名字 ")
//2、获取default下deployment的资源名字
deployments, err := clientset.AppsV1().Deployments("default").List(ctx, metav1.ListOptions{})
if err != nil {
fmt.Printf("listing deployments %s\n", err.Error())
}
for _, d := range deployments.Items {
fmt.Printf("%s\n", d.Name)
}

fmt.Println("获取kube-system namespace下的daemonset的名字 ")
//3、获取kube-system下daemonset的资源名字
daemonsets, err := clientset.AppsV1().DaemonSets("kube-system").List(ctx, metav1.ListOptions{})
if err != nil {
fmt.Printf("listing daemonsets %s\n", err.Error())
}
for _, ds := range daemonsets.Items {
fmt.Printf("%s\n", ds.Name)
}

fmt.Println("获取get node的方法 ")
//4、获取get node的的名字
node, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
if err != nil {
fmt.Printf("listing Node %s\n", err.Error())
}
for _, no := range node.Items {
fmt.Printf("%s\n", no.Name)
}

fmt.Println("获取kube-system svc")
//5、获取kube-system下的service
svc, err := clientset.CoreV1().Services("kube-system").List(ctx, metav1.ListOptions{})
if err != nil {
fmt.Printf("listing service %s\n", err.Error())
}
for _, service := range svc.Items {
fmt.Printf("%s\n", service.Name)
}

}


开发技巧:

  1. pkg/registry/core 先找到对应的Group和Kind/resource(GR/GK),例如:pod 核心数据结构: pkg/registry/core/pod/storage/storage.go 参考:​​https://blog.51cto.com/daixuan/4976182​
// PodStorage includes storage for pods and all sub resources
type PodStorage struct {
Pod *REST
Binding *BindingREST
LegacyBinding *LegacyBindingREST
Eviction *EvictionREST
Status *StatusREST
EphemeralContainers *EphemeralContainersREST
Log *podrest.LogREST
Proxy *podrest.ProxyREST
Exec *podrest.ExecREST
Attach *podrest.AttachREST
PortForward *podrest.PortForwardREST
}

// REST implements a RESTStorage for pods
type REST struct {
*genericregistry.Store
proxyTransport http.RoundTripper
}
  1. staging/src/k8s.io/api/apps/v1/register.go 如果要开发apps资源下的Deployment,先找到registor.go,找到对应的list接口
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Deployment{},
&DeploymentList{},
&StatefulSet{},
&StatefulSetList{},
&DaemonSet{},
&DaemonSetList{},
&ReplicaSet{},
&ReplicaSetList{},
&ControllerRevision{},
&ControllerRevisionList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}


  1. 再去staging/src/k8s.io/api/apps/v1/types.go找到DeploymentList结构体(&DeploymentList{},Goland可以直接跳转过去)
// DeploymentList is a list of Deployments.
type DeploymentList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Items is the list of Deployments.
Items []Deployment `json:"items" protobuf:"bytes,2,rep,name=items"`
}

如果是pod/node等注册信息,使用的是staging/src/k8s.io/api/core/v1/register.go核心代码,不是staging/src/k8s.io/api/apps/v1了

// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Pod{},
&PodList{},
&PodStatusResult{},
&PodTemplate{},
&PodTemplateList{},
&ReplicationController{},
&ReplicationControllerList{},
&Service{},
&ServiceProxyOptions{},
&ServiceList{},
&Endpoints{},
&EndpointsList{},
&Node{},
&NodeList{},
&NodeProxyOptions{},
&Binding{},
&Event{},
&EventList{},
&List{},
&LimitRange{},
&LimitRangeList{},
&ResourceQuota{},
&ResourceQuotaList{},
&Namespace{},
&NamespaceList{},
&Secret{},
&SecretList{},
&ServiceAccount{},
&ServiceAccountList{},
&PersistentVolume{},
&PersistentVolumeList{},
&PersistentVolumeClaim{},
&PersistentVolumeClaimList{},
&PodAttachOptions{},
&PodLogOptions{},
&PodExecOptions{},
&PodPortForwardOptions{},
&PodProxyOptions{},
&ComponentStatus{},
&ComponentStatusList{},
&SerializedReference{},
&RangeAllocation{},
&ConfigMap{},
&ConfigMapList{},
)

pod/node等结构体也在core/v1下面,Goland可以直接跳转过去:staging/src/k8s.io/api/core/v1/types.go

// NodeList is the whole list of all Nodes which have been registered with master.
type NodeList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// List of nodes
Items []Node `json:"items" protobuf:"bytes,2,rep,name=items"`
}

// FinalizerName is the name identifying a finalizer during namespace lifecycle.
type FinalizerName string

// These are internal finalizer values to Kubernetes, must be qualified name unless defined here or
// in metav1.
const (
FinalizerKubernetes FinalizerName = "kubernetes"
)

4.调用方法

deployments, err := clientset.AppsV1().Deployments("default").List(ctx, metav1.ListOptions{})

vendor/k8s.io/client-go/kubernetes/clientset.go  Clientset结构体包含了多个结构体,例如:clientset.AppsV1().Deployments 和  clientset.CoreV1().Nodes等等

// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
appsV1 *appsv1.AppsV1Client
coreV1 *corev1.CoreV1Client
.......
}

clientset.AppsV1().Deployments输出的是v1.DeploymentList,v1.DeploymentList包含多个[]Deployment的Items

// DeploymentsGetter has a method to return a DeploymentInterface.
// A group's client should implement this interface.
type DeploymentsGetter interface {
Deployments(namespace string) DeploymentInterface
}

// DeploymentInterface has methods to work with Deployment resources.
type DeploymentInterface interface {
.....
List(ctx context.Context, opts metav1.ListOptions) (*v1.DeploymentList, error)
.....
}

// DeploymentList is a list of Deployments.
type DeploymentList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

// Items is the list of Deployments.
Items []Deployment `json:"items" protobuf:"bytes,2,rep,name=items"`
}

5.循环输出打印

for _, d := range deployments.Items {
fmt.Printf("%s\n", d.Name)
}