马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
想学习K8S源码,可以加 :mkjnnm
1、先容
client-go 是用来和 k8s 集群交互的go语言客户端库,地点为:https://github.com/kubernetes/client-go client-go 的版本有两种标识方式:
- v0.x.y (For each v1.x.y Kubernetes release, the major version (first digit) would remain 0)
- kubernetes-1.x.y
ps: k8s 发布v1.30.0 版本时,client-go 会同步发布两个版本 v0.30.0 (保举利用)和 kubernetes-1.30.0
如果你想利用最新版本的客户端库,你可以运行如下下令:
go get k8s.io/client-go@latest
如果你想利用特定版本,保举利用如下下令:
go get k8s.io/client-go@v0.20.4
2、目录布局
client-go 包罗以下几部门:
- The kubernetes package contains the clientset to access Kubernetes API.
- The discovery package is used to discover APIs supported by a Kubernetes API server.
- The dynamic package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects.
- The plugin/pkg/client/auth packages contain optional authentication plugins for obtaining credentials from external sources.
- The transport package is used to set up auth and start a connection.
- The tools/cache package is useful for writing controllers.
3、利用
1.初始化
如果你的应用跑在集群中的pod上,保举利用集群内初始化,否则利用集群外初始化。
- // 集群外初始化 client
- // 需要集群的 kubeconfig 配置文件
- func main() {
- var kubeconfig *string
- if home := homedir.HomeDir(); home != "" {
- kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
- } else {
- kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
- }
- flag.Parse()
- // use the current context in kubeconfig
- config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
- if err != nil {
- panic(err.Error())
- }
- // create the clientset
- clientset, err := kubernetes.NewForConfig(config)
- if err != nil {
- panic(err.Error())
- }
- }
复制代码 2. 列出集群内pod资源
- pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
- if err != nil {
- panic(err.Error())
- }
- fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
复制代码 上述代码在client-
go仓库下examples目录
你可以运行该代码:
- cd out-of-cluster-client-configuration
- go build -o app .
- ./app -kubeconfig=/path/to/xxx
复制代码 3. deployment资源CRUD - typed (clientset)方式
以下代码创建一个有2个副本数的deployment,然后更新副本数为1,升级nginx镜像版本,最后删除
- deploymentsClient := clientset.AppsV1().Deployments(apiv1.NamespaceDefault)
- deployment := &appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: "demo-deployment",
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: int32Ptr(2),
- Selector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- "app": "demo",
- },
- },
- Template: apiv1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "app": "demo",
- },
- },
- Spec: apiv1.PodSpec{
- Containers: []apiv1.Container{
- {
- Name: "web",
- Image: "nginx:1.12",
- Ports: []apiv1.ContainerPort{
- {
- Name: "http",
- Protocol: apiv1.ProtocolTCP,
- ContainerPort: 80,
- },
- },
- },
- },
- },
- },
- },
- }
- // Create Deployment
- fmt.Println("Creating deployment...")
- result, err := deploymentsClient.Create(context.TODO(), deployment, metav1.CreateOptions{})
- if err != nil {
- panic(err)
- }
- fmt.Printf("Created deployment %q.\n", result.GetObjectMeta().GetName())
- // Update Deployment
- prompt()
- fmt.Println("Updating deployment...")
- // You have two options to Update() this Deployment:
- //
- // 1. Modify the "deployment" variable and call: Update(deployment).
- // This works like the "kubectl replace" command and it overwrites/loses changes
- // made by other clients between you Create() and Update() the object.
- // 2. Modify the "result" returned by Get() and retry Update(result) until
- // you no longer get a conflict error. This way, you can preserve changes made
- // by other clients between Create() and Update(). This is implemented below
- // using the retry utility package included with client-go. (RECOMMENDED)
- //
- // More Info:
- // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
- retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
- // Retrieve the latest version of Deployment before attempting update
- // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
- result, getErr := deploymentsClient.Get(context.TODO(), "demo-deployment", metav1.GetOptions{})
- if getErr != nil {
- panic(fmt.Errorf("Failed to get latest version of Deployment: %v", getErr))
- }
- result.Spec.Replicas = int32Ptr(1) // reduce replica count
- result.Spec.Template.Spec.Containers[0].Image = "nginx:1.13" // change nginx version
- _, updateErr := deploymentsClient.Update(context.TODO(), result, metav1.UpdateOptions{})
- return updateErr
- })
- if retryErr != nil {
- panic(fmt.Errorf("Update failed: %v", retryErr))
- }
- fmt.Println("Updated deployment...")
- // List Deployments
- prompt()
- fmt.Printf("Listing deployments in namespace %q:\n", apiv1.NamespaceDefault)
- list, err := deploymentsClient.List(context.TODO(), metav1.ListOptions{})
- if err != nil {
- panic(err)
- }
- for _, d := range list.Items {
- fmt.Printf(" * %s (%d replicas)\n", d.Name, *d.Spec.Replicas)
- }
- // Delete Deployment
- prompt()
- fmt.Println("Deleting deployment...")
- deletePolicy := metav1.DeletePropagationForeground
- if err := deploymentsClient.Delete(context.TODO(), "demo-deployment", metav1.DeleteOptions{
- PropagationPolicy: &deletePolicy,
- }); err != nil {
- panic(err)
- }
- fmt.Println("Deleted deployment.")
- }
- func prompt() {
- fmt.Printf("-> Press Return key to continue.")
- scanner := bufio.NewScanner(os.Stdin)
- for scanner.Scan() {
- break
- }
- if err := scanner.Err(); err != nil {
- panic(err)
- }
- fmt.Println()
- }
- func int32Ptr(i int32) *int32 { return &i }
复制代码 4.deployment资源CRUD - dynamic方式
利用typed方式创建资源固然方便,但是必要事先利用client-gen天生且会与某个特定版本耦合,不敷通用,所以我们可以利用 unstructured.Unstructured 来表现集群中恣意对象。
- client, err := dynamic.NewForConfig(config)
- if err != nil {
- panic(err)
- }
-
- deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
- deployment := &unstructured.Unstructured{
- Object: map[string]interface{}{
- "apiVersion": "apps/v1",
- "kind": "Deployment",
- "metadata": map[string]interface{}{
- "name": "demo-deployment",
- },
- "spec": map[string]interface{}{
- "replicas": 2,
- "selector": map[string]interface{}{
- "matchLabels": map[string]interface{}{
- "app": "demo",
- },
- },
- "template": map[string]interface{}{
- "metadata": map[string]interface{}{
- "labels": map[string]interface{}{
- "app": "demo",
- },
- },
- "spec": map[string]interface{}{
- "containers": []map[string]interface{}{
- {
- "name": "web",
- "image": "nginx:1.12",
- "ports": []map[string]interface{}{
- {
- "name": "http",
- "protocol": "TCP",
- "containerPort": 80,
- },
- },
- },
- },
- },
- },
- },
- },
- }
- // Create Deployment
- fmt.Println("Creating deployment...")
- result, err := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Create(context.TODO(), deployment, metav1.CreateOptions{})
- if err != nil {
- panic(err)
- }
- fmt.Printf("Created deployment %q.\n", result.GetName())
复制代码 5. discoveryClient
3-4末节我们学习了 typed client 和 dynamic client ,这两个client利用来操作集群中资源,比如创建 deployment,删除pod。discovery client 差别,他是用来发现服务端支持的组、版本、资源类型:
- // Package discovery provides ways to discover server-supported
- // API groups, versions and resources.
复制代码 我们可以查询服务端支持的组与版本、某个组的资源列表
- func main() {
- var kubeconfig *string
- if home := homedir.HomeDir(); home != "" {
- kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
- } else {
- kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
- }
- flag.Parse()
- // use the current context in kubeconfig
- config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
- if err != nil {
- panic(err.Error())
- }
- // *查询服务端支持的组列表
- discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(config)
- gs, err := discoveryClient.ServerGroups()
- if err != nil {
- panic(err.Error())
- }
- spew.Dump(gs.Groups)
-
- // *查询core/v1 组下的资源列表
- rs, err := discoveryClient.ServerResourcesForGroupVersion("v1")
- if err != nil {
- panic(err.Error())
- }
- for _, r := range rs.APIResources {
- fmt.Println(r.Name)
- }
- }
- // 输出支持的组列表
- /*
- (v1.APIGroup) &APIGroup{Name:apps,Versions:[]GroupVersionForDiscovery{GroupVersionForDiscovery{GroupVersion:apps/v1,Version:v1,},},PreferredVersion:GroupVersionForDiscovery{GroupVersion:apps/v1,Version:v1,},ServerAddressByClientCIDRs:[]ServerAddressByClientCIDR{},},
- (v1.APIGroup) &APIGroup{Name:events.k8s.io,Versions:[]GroupVersionForDiscovery{GroupVersionForDiscovery{GroupVersion:events.k8s.io/v1,Version:v1,},},PreferredVersion:GroupVersionForDiscovery{GroupVersion:events.k8s.io/v1,Version:v1,},ServerAddressByClientCIDRs:[]ServerAddressByClientCIDR{},},
- ...
- */
- // 输出core/v1组下的资源列表
- /*
- pods/status
- podtemplates
- replicationcontrollers
- replicationcontrollers/scale
- replicationcontrollers/status
- resourcequotas
- resourcequotas/status
- secrets
- serviceaccounts
- ...
- */
复制代码 6. restClient
上面三种客户端都是基于 restClient 封装的,restClient 是 client-go 最底子的客户端,对http request 举行了封装,更加灵活,一般我们用不到。
- // 根据配置信息构建restClient实例
- restClient, err := rest.RESTClientFor(config)
- if err!=nil {
- panic(err.Error())
- }
- // 保存pod结果的数据结构实例
- result := &corev1.PodList{}
- // 指定namespace
- namespace := "kube-system"
- // 设置请求参数,然后发起请求
- // GET请求
- err = restClient.Get().
- // 指定namespace,参考path : /api/v1/namespaces/{namespace}/pods
- Namespace(namespace).
- // 查找多个pod,参考path : /api/v1/namespaces/{namespace}/pods
- Resource("pods").
- // 指定大小限制和序列化工具
- VersionedParams(&metav1.ListOptions{Limit:100}, scheme.ParameterCodec).
- // 请求
- Do(context.TODO()).
- // 结果存入result
- Into(result)
复制代码 4、范围
利用 client 操作集群中资源会导致频繁的轮询,k8s client-go 包提供了更加高效的方式:informer 。
informer 提供了一种机制来监视 Kubernetes 集群内资源的变化并做出反应。它使开辟职员能够接收有关各种 Kubernetes 对象(比方 Pod、服务、部署等)状态的实时更新。
Informer 将集群中的资源缓存在当地来减少频繁的API调用,提高性能并优化资源利用率。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |