Kubernetes API Server初探: API Server究竟简不简单

78 阅读2分钟

概述

k8s中的中心组件api-server应该是每个k8s初学者第一个交互的组件。也许每个应用层项目都有一个HTTP Server,但k8s的特点在于APIServer的地位被提高到了不可能再高了,比如想访问k8s中唯一的存储etcd就只能通过APIServer这一设计思想。

details

store

type Store struct {
    // curl GET /apis/group/version/namespaces/my-ns/myresource/name-of-object
    NewFunc func() runtime.Object
	// curl GET /apis/group/version/namespaces/my-ns/myresource
    NewListFunc func() runtime.Object

    // ...
}

register

registerResourceHandlers

registerResourceHandlers 暴露出了http handler注册到http框架的代码,需要重点关注入参中的 storage rest.Storagews *restful.WebService

func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, *storageversion.ResourceInfo, error) {
    // what verbs are supported by the storage, used to know what verbs we support per path
	creater, isCreater := storage.(rest.Creater)

    switch action.Verb {
    case "POST": // Create a resource.
        var handler restful.RouteFunction
        if isNamedCreater {
            handler = restfulCreateNamedResource(namedCreater, reqScope, admit)
        } else {
            handler = restfulCreateResource(creater, reqScope, admit)
        }
        route := ws.POST(action.Path).To(handler).
            Doc(doc).
            Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
            Operation("create"+namespaced+kind+strings.Title(subresource)+operationSuffix).
            Produces(append(storageMeta.ProducesMIMETypes(action.Verb), mediaTypes...)...).
            Returns(http.StatusOK, "OK", producedObject).
            // TODO: in some cases, the API may return a v1.Status instead of the versioned object
            // but currently go-restful can't handle multiple different objects being returned.
            Returns(http.StatusCreated, "Created", producedObject).
            Returns(http.StatusAccepted, "Accepted", producedObject).
            Reads(defaultVersionedObject).
            Writes(producedObject)
        addParams(route, action.Params)
        routes = append(routes, route)
    }
}

http框架 go-restful

点到ws的实现,才发现转到了第三方代码,github.com/emicklei/go-restful 不是最主流的Go HTTP框架,但是从RESTful的角度可能才被k8s选为依赖的框架吧。

Install

registerResourceHandlers 向上一层,是函数 Install,它的代码非常简洁,看到了返回值是熟悉的 APIResources。函数的核心在于根据 len(a.group.Storage) 找到所有path,然后对path注册handler,在此印证了 rest.Storage 接口的重要性。

func (a *APIInstaller) Install() ([]metav1.APIResource, []*storageversion.ResourceInfo, *restful.WebService, []error) {
	var apiResources []metav1.APIResource
	var resourceInfos []*storageversion.ResourceInfo
	var errors []error
	ws := a.newWebService()

	// Register the paths in a deterministic (sorted) order to get a deterministic swagger spec.
	paths := make([]string, len(a.group.Storage))
	var i int = 0
	for path := range a.group.Storage {
		paths[i] = path
		i++
	}
	sort.Strings(paths)
	for _, path := range paths {
		apiResource, resourceInfo, err := a.registerResourceHandlers(path, a.group.Storage[path], ws)
		if err != nil {
			errors = append(errors, fmt.Errorf("error in registering resource: %s, %v", path, err))
		}
		if apiResource != nil {
			apiResources = append(apiResources, *apiResource)
		}
		if resourceInfo != nil {
			resourceInfos = append(resourceInfos, resourceInfo)
		}
	}
	return apiResources, resourceInfos, ws, errors
}

ref

k8s源码分析——kube-apiserver源码阅读