使用 Go 程序调用 Kubernetes API
在前面的章节中,我们介绍了快速部署 Kubernetes 和应用程序的方法,接下来在本章节中我们将对 Kubernetes 的 API 进行了解,并且进行调用,这是开发人员最关注的一环之一。
因为不论是 DevOps、基础架构,又或是自愈,都需要与 Kubernetes API 直接/间接接触,因此即使在你不懂 Kubernetes 的情况下,Kubernetes API 的知识点仍然属于必知必会,API 总得会调。
查看 Kubernetes API
kube-apiserver 架构图
(图来自 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":"...