client-go 全系列之三 —— 《go k8s 访问》

1 前言

  上节介绍了 GO 项目开发的配置,本小节会利用 client-go 库实际编写一个访问 K8S 的样例。


2 运行环境

  本系列文章使用的环境配置如下(不要求读者完全匹配,可根据自己实际情况酌情处理):

  • K8s 版本 : 1.19.0
  • Docker 版本:20.10.8
  • CentOS 版本:7.7.1908
  • Go SDK 版本:go1.16.6 linux/amd64

3 项目代码

  进入 GO 项目的根目录:

# cd $GOPATH/src

  新建 k8s-visitor 项目目录,并在该目录下创建 main.go 文件:

# mkdir k8s-visitor
# cd k8s-visitor
# touch main.go

编辑 main.go 文件,添加如下代码:

package main

import (
    "context"
    "fmt"
    "io/ioutil"

    core_v1 "k8s.io/api/core/v1"
    meta_v1 "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() {
    var (
        err          error
        kubeconfig   []byte
        clientconfig *rest.Config
        clientset    *kubernetes.Clientset
        pods      	 *core_v1.PodList
    )   

    if kubeconfig, err = ioutil.ReadFile("/root/.kube/config"); err != nil {
        panic(err)
    }   

    if clientconfig, err = clientcmd.RESTConfigFromKubeConfig(kubeconfig); err != nil {
        panic(err)
    }   

    if clientset, err = kubernetes.NewForConfig(clientconfig); err != nil {
        panic(err)
    }   

    if pods, err = clientset.CoreV1().Pods("default").List(context.TODO(), meta_v1.ListOptions{}); err != nil {
        panic(err)
    }

    fmt.Println(pods)
}

4 运行项目

  如果想运行成功上面的代码样例,需执行如下两个步骤:

  • 创建 go.mod
  • 运行 main.go

4.1 创建 go.mod

  go mod 在 GO v1.11 版本引入,在 v1.12 版本基本稳定,到 v1.13 版本的时候默认是打开的,可以使用如下命令查看:

[root@k8s-master-1 k8s-visitor]# go env | grep -i GO111MODULE
GO111MODULE="on"

  执行下列命令创建 go.mod 文件:

[root@k8s-master-1 k8s-visitor]# go mod init
go: creating new go.mod: module k8s-visitor
go: to add module requirements and sums:
	go mod tidy

  如果执行结果如上所示,继续执行下面指令(备注,如果指令执行失败,很大概率是依赖包下不到,可参考本系列第一篇文章配置好下载包代理):

[root@k8s-master-1 k8s-visitor]# 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/client-go/rest
go: finding module for package k8s.io/api/core/v1
go: finding module for package k8s.io/apimachinery/pkg/apis/meta/v1
go: found k8s.io/api/core/v1 in k8s.io/api v0.22.1
go: found k8s.io/apimachinery/pkg/apis/meta/v1 in k8s.io/apimachinery v0.22.1
go: found k8s.io/client-go/kubernetes in k8s.io/client-go v0.22.1
go: found k8s.io/client-go/rest in k8s.io/client-go v0.22.1
go: found k8s.io/client-go/tools/clientcmd in k8s.io/client-go v0.22.1

  执行完毕后, $GOPATH/src/k8s-visitor 目录结构如下:

[root@k8s-master-1 k8s-visitor]# tree
.
├── go.mod
├── go.sum
└── main.go

0 directories, 3 files

4.2 运行 main.go

  运行 main.go:

[root@k8s-master-1 k8s-visitor]# go run main.go

  如果读者输出的结果是 k8s default 命名空间下的 pod 列表信息则表示程序执行成功。下图是笔者的运行结果,仅供参考:

  自此,第一个 client-go 程序编写完毕并运行成功。

4.3 源码解释

  下面简单介绍程序代码逻辑。

4.3.1 读取 K8S 配置

  client-go 需要连接配置才可以访问到 K8S,比如 IP、Port、CA 或 token 等。K8S 默认将连接配置存放在 master 节点的 ~/.kube/config 文件中,比如笔者配置如下所示:

apiVersion: v1
clusters:
- cluster:
  certificate-authority: /etc/kubernetes/pki/ca.crt
  server: https://10.110.101.109:6443
name: default
- cluster:
  certificate-authority: /etc/kubernetes/pki/ca.crt
  server: https://10.110.101.109:6443
name: k8s-cluster
contexts:
- context:
  cluster: default
  user: admin
name: default
- context:
  cluster: k8s-cluster
  namespace: jiuxi
  user: admin
name: k8s-context
current-context: default
kind: Config
preferences: {}
users:
- name: admin
user:
  client-certificate: /etc/kubernetes/pki/client.crt
  client-key: /etc/kubernetes/pki/client.key

  下列代码读取上面 config 配置文件,保存在 kubeconfig 切片中,如果读者 K8S 默认配置文件地址(/root/.kube/config)与笔者不同,请根据实际情况进行修改。

if kubeconfig, err = ioutil.ReadFile("/root/.kube/config"); err != nil {
  panic(err)
}  

4.3.2 创建客户端配置对象

  下列代码将上面创建的 kubeconfig 切片转化为客户端配置对象,读者如果觉得费解,可以简单理解为单纯的数据类型转换,即:从切片转化为对象。

if clientconfig, err = clientcmd.RESTConfigFromKubeConfig(kubeconfig); err != nil {
  panic(err)
} 

4.3.3 创建客户端访问对象

  下列代码根据上面创建的配置对象(clientconfig)生成客户端访问对象(clientset),clientset 是 client-go 针对 K8S 每种内置资源(比如:Pod,Deployment)封装的客户端访问对象,该对象内部封装资源操作的 API(比如 delete、create、apply),读者可直接拿来使用,不用自己创造轮子。

if clientset, err = kubernetes.NewForConfig(clientconfig); err != nil {
  panic(err)
}   

4.3.4 访问 K8S 获取 Pod 列表

  下列代码利用 clientset API 获取 K8S default 命名空间下的 Pod 列表。

if pods, err = clientset.CoreV1().Pods("default").List(context.TODO(), meta_v1.ListOptions{}); err != nil {
  panic(err)
} 

5.总结

  本节给出了一个实际样例介绍如何使用 client-go 连接 K8S,这是项目开发的基础,后续所有项目将基于此开发,请大家认真体会。