概述
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.Storage 和 ws *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
}