k8s APIServer源码: go-restful框架

基于版本 1.6.7

k8s的APIServer, 使用了go-restful作为其处理框架, 注册资源并接收处理 HTTP 请求.

在阅读APIServer源码之前, 需先理解go-restful主要概念.

intro

package for building REST-style Web Services using Google Go

go-restful github

go-restfu

concepts

  • Container: 一组WebService的集合, 目的: Containers for WebServices on different HTTP endpoints.
  • WebService: Route的集合; 为一组Route定义统一的 root path / 请求类型 / 响应类型
  • Route: 定义method/ULR path/调用函数/文档/参数/ curly route; 支持正则及动态谭树
  • Filter: Filters for intercepting the request → response flow on Service or Route level, 可以加global / Webservice / Route 各自的filter

init steps:

  • create container
  • create resource WebService
  • define route, path, filter and bind to route handler
    
  • add router to WebService
    
  • add WebService to container
  • new server with Handler=container
  • start server

examples

  • 示例1: use default containers
ws := new(restful.WebService)
ws.
	Path("/users").
	Consumes(restful.MIME_XML, restful.MIME_JSON).
	Produces(restful.MIME_JSON, restful.MIME_XML)

ws.Route(ws.GET("/{user-id}").To(u.findUser).
	Doc("get a user").
	Param(ws.PathParameter("user-id", "identifier of the user").DataType("string")).
	Writes(User{}))
...

func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
	id := request.PathParameter("user-id")
	...
}
  • 示例2: 含多个container
// https://github.com/emicklei/go-restful/blob/master/examples/restful-multi-containers.go
// GET http://localhost:8080/hello
// GET http://localhost:8081/hello
package main

import (
	"github.com/emicklei/go-restful"
	"io"
	"log"
	"net/http"
)

func main() {
  // add to default container
	ws := new(restful.WebService)
	ws.Route(ws.GET("/hello").To(hello))
	restful.Add(ws)
	go func() {
		log.Fatal(http.ListenAndServe(":8080", nil))
	}()

  // container 2
	container2 := restful.NewContainer()
	ws2 := new(restful.WebService)
	ws2.Route(ws2.GET("/hello").To(hello2))
	container2.Add(ws2)
	server := &http.Server{Addr: ":8081", Handler: container2}
	log.Fatal(server.ListenAndServe())
}

func hello(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "default world")
}

func hello2(req *restful.Request, resp *restful.Response) {
	io.WriteString(resp, "second world")
}
  • 示例3: 包含 filter
// filter https://github.com/emicklei/go-restful/blob/master/examples/restful-filters.go
// Global Filter
func globalLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	log.Printf("[global-filter (logger)] %s,%s\n", req.Request.Method, req.Request.URL)
	chain.ProcessFilter(req, resp)
}

func main() {
	// install a global (=DefaultContainer) filter (processed before any webservice in the DefaultContainer)
	restful.Filter(globalLogging)

	restful.Add(NewUserService())
	log.Print("start listening on localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}


func NewUserService() *restful.WebService {
	ws := new(restful.WebService)
	ws.
		Path("/users").
		Consumes(restful.MIME_XML, restful.MIME_JSON).
		Produces(restful.MIME_JSON, restful.MIME_XML)

	// install a webservice filter (processed before any route)
	ws.Filter(webserviceLogging).Filter(measureTime)

	// install a counter filter
	ws.Route(ws.GET("").Filter(NewCountFilter().routeCounter).To(getAllUsers))

	// install 2 chained route filters (processed before calling findUser)
	ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser))
	return ws
}

reference


paas

506 Words

2017-09-23 12:00 +0800