使用 Go 程序调用 Kubernetes API

在前面的章节中,我们介绍了快速部署 Kubernetes 和应用程序的方法,接下来在本章节中我们将对 Kubernetes 的 API 进行了解,并且进行调用,这是开发人员最关注的一环之一。

因为不论是 DevOps、基础架构,又或是自愈,都需要与 Kubernetes API 直接/间接接触,因此即使在你不懂 Kubernetes 的情况下,Kubernetes API 的知识点仍然属于必知必会,API 总得会调。

查看 Kubernetes API

kube-apiserver 架构图

image

(图来自 kubernetes.io)

在 Kubernetes 的架构中,由 kube-apiserver 组件在主节点上提供 Kubernetes API 服务,kube-apiserver 是 Kubernetes 所有控制的前端,对外提供大量的 RESTful API。

最常见的就是 kubelet 命令,实际上也是在调用 kube-apiserver 所提供的的 API。

访问 API 和查看列表

在了解 Kubernetes 的基本架构和提供 API 的方式后,接下来我们需要知道 Kubernetes 到底提供了哪些 API。为了方便调试,首先我们需要在本地运行 kubectl proxy 命令,kube-apiserver 就会在本地的 8001 端口上进行监听,也就是提供了一个 Kubernetes API 服务的 HTTP 代理。

这个时候我们可以访问:

$ curl http://localhost:8001/api/v1/

查看所提供的对应 API‘s:

{
  "kind": "APIResourceList",
  "groupVersion": "v1",
  "resources": [
    {
      "name": "bindings",
      "singularName": "",
      "namespaced": true,
      "kind": "Binding",
      "verbs": [
        "create"
      ]
    },
    {
      "name": "componentstatuses",
      "singularName": "",
      "namespaced": false,
      "kind": "ComponentStatus",
      "verbs": [
        "get",
        "list"
      ],
      "shortNames": [
        "cs"
      ]
    },
    ...
  ]
}

访问 api/v1/pods 路径,获取所有 Pods

$ curl http://127.0.0.1:8001/api/v1/pods

访问结果:

{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/pods",
    "resourceVersion": "614376"
  },
  "items": [
    {
      "metadata": {
        "name": "awesome-project-76788db95b-7ztwr",
        "generateName": "awesome-project-76788db95b-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/awesome-project-76788db95b-7ztwr",
        "uid": "4fdb6661-edbd-4fc6-bf71-1d2dadb3ffc1",
        "resourceVersion": "608545",
        "creationTimestamp": "2020-05-03T02:29:32Z",
        "labels": {
          "app": "awesome-project",
          "pod-template-hash": "76788db95b"
        },
        ...
        ]
      },
    ]

更多的 API 列表和介绍可查看官方文档

Go 程序调用 Kubernetes API

接下来进入在本章的重点,也就是在程序中调用 Kubernetes API,Kubernetes 官方提供了 Go 语言的 Client SDK,也就是kubernetes/client-go,我们借助上一章节的 Go 程序,对其进行改造。

Demo

首先写入如下方法:

func NewK8sInCluster() error {
  config, err := rest.InClusterConfig()
  if err != nil {
    return err
  }

  k8sClient, err = kubernetes.NewForConfig(config)
  if err != nil {
    return err
  }

  return nil
}

编写获取 K8S Pod 列表的方法:

func GetPodList(pod Pod) ([]v1.Pod, error) {
  podList, err := k8sClient.CoreV1().Pods(pod.Namespace).List(metav1.ListOptions{})
  if err != nil {
    return nil, err
  }
  pods := podList.Items

  if pod.Name != "" {
    filterPods := make([]v1.Pod, 0, len(pods))
    for _, p := range pods {
      if strings.HasPrefix(p.Name, pod.Name) {
        filterPods = append(filterPods, p)
      }
    }
    pods = filterPods
  }

  return pods, nil
}

修改 main 方法中的路由:

func main() {
  r := gin.Default()
  r.GET("/ping", func(c *gin.Context) {
    c.String(http.StatusOK, "pong")
  })
  r.GET("/k8s/pods", func(c *gin.Context) {
    err := NewK8sInCluster()
    if err != nil {
      c.String(http.StatusInternalServerError, "NewK8sInCluster err: %v", err)
    }
    pods, err := GetPodList(Pod{Namespace: "default"})
    if err != nil {
      c.String(http.StatusInternalServerError, "GetPodList err: %v", err)
    }

    c.JSON(http.StatusOK, pods)
  })
  err := r.Run(":9001")
  if err != nil {
    log.Fatalf("r.Run err: %v", err)
  }
}

在确定程序正常后,我们重新编译并打标签:

$ docker build -t eddycjy/awesome-project:v0.0.2 .
$ docker login  
$ docker push eddycjy/awesome-project:v0.0.2

部署并验证

修改 go-deployment.yaml 文件:

      containers:
      - name: awesome-project
        image: eddycjy/awesome-project:v0.0.2

将其应用到 Kubernetes:

$ kubectl apply -f go-deployment.yaml 
deployment.extensions/awesome-project configured

访问刚刚所编写的接口,如下:

$ curl http://website-ingress.local/k8s/pods
[{"metadata":{"name":"awesome-project-64979bcbd9-rm957","generateName":"awesome-project-64979bcbd9-","namespace":"default","selfLink":"/api/v1/namespaces/default/pods/awesome-project-64979bcbd9-rm957","uid":"b0a83787-c547-4d74-9bc4-c930b2188e84","resourceVersion":"...