0%

本文是一个示例程序,展示一下如何基于Kubernetes的CRD(Custom Resource Defination)& Go-client构建一个查询Pod详细信息的服务。

该服务运行起来后,可以通过标准的kubernetes api接口,基于CRD来查询某个Pod的详细信息。

代码的地址在:

1
https://github.com/weiyuanke/PodInfoLookup

首先我们基于配置文件创建一个我们自定义的资源——Testcr

1
2
3
4
5
6
7
#PodInfoLookup/yaml/testcrd.yaml

#创建了一个名为Testcr的自定义资源类型
#group:stable.example.com
#version:v1
#resource:testcrs
$kubectl apply -f yaml/testcrd.yaml

本文假定本地已经有一个kubernetes集群在运行了,如果没有的话,可以基于minikube安装一个。

1
2
3
4
5
#拉取最新代码:
go get github.com/weiyuanke/PodInfoLookup

#启动服务
go run main.go --kubeconfig=/Users/yuankewei/.kube/config

在另外一个终端创建一个pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kubectl apply -f yaml/pod.yaml 

#服务会监听到pod的创建,同时将该pod的相关信息写入Testcr资源中,
add: default/nginx

current list:
&{map[kind:Testcr metadata:map[generation:1 name:29b36e2c6835dded8a115aee874d1ddc resourceVersion:113140 selfLink:/apis/stable.example.com/v1/testcrs/29b36e2c6835dded8a115aee874d1ddc uid:a2440f67-9ca4-11e9-9f23-080027f1737d creationTimestamp:2019-07-02T08:37:32Z] spec:map[podip:nginx podkey:a242bc2d-9ca4-11e9-9f23-080027f1737d podname:29b36e2c6835dded8a115aee874d1ddc poduid:] apiVersion:stable.example.com/v1]}

#同理,删除pod,会导致Testrc中对应的资源被删除
kubectl delete -f yaml/pod.yaml

delete: default/nginx

current list:

1、什么是自定义资源(Custom Resource)?

1
2
3
4
5
自定义资源是对kubernetes api的扩展,用户通过配置文件(Custom Resource Definition)
定义 资源 后,就可以通过kubernetes的API来操作此类资源。

仅仅通过API对资源进行操作其实意义不大,一般会再配合一个自定义的控制器,来实现一个声明式的
API,在自定义的控制器中监听该资源相关的事件,并执行对应的业务逻辑。

2、自定义资源 -> 自定义控制器的整个流程

1
2
API server(包含有自定义资源) -> Lister&Watcher -> Reflector -> Delta Queue ->
Informer -> 存入Indexer并同时触发相关的Handler -> work queue -> 自定义控制器

Kubernetes的Api Server中用到了golang的http包,故而做下简单的了解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"io"
"net/http"
)

func main() {
http.HandleFunc("/", helloworld)
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println("ListenAndServe: ", err)
}
}

func helloworld(w http.ResponseWriter, request *http.Request) {
result := "HelloWorld\n"
result = result + "RequestURI: " + request.RequestURI

io.WriteString(w, result)
}

以上代码开启了一个简单的web服务,应用启动后访问如下地址:

1
http://127.0.0.1:9090/?we=12

会给出如下的输出

1
2
HelloWorld
RequestURI: /?we=12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//第一个参数是监听的地址和端口
//第二个参数是一个Handler,实现了ServeHTTP(ResponseWriter, *Request)方法,
//客户端的请求会交由这个方法进行处理。
//如果传nil的话,会采用http包默认的handler,DefaultServeMux来进行处理。
//DefaultServeMux可以认为是一个路由管理器,
//它的ServeHTTP方法实现 会根据客户端请求的路径来将请求路由到不同的HandlerFunc上去。
http.ListenAndServe(":9090", nil)

//为DefaultServeMux注册一个HandleFunc
http.HandleFunc("/", helloworld)

具体的代码:
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}

除了采用默认的路由分发器DefaultServeMux,也可以构建自己的Mux,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"io"
"net/http"
)

func main() {
//新建一个路由管理器,
mux := http.NewServeMux()
//绑定路径和处理函数
mux.HandleFunc("/", helloworld)

server := &http.Server{
Addr:":9090",
Handler:mux,
}

server.ListenAndServe()
}

func helloworld(w http.ResponseWriter, request *http.Request) {
result := "HelloWorld\n"
result = result + "RequestURI: " + request.RequestURI

io.WriteString(w, result)
}