kubernetesソースコード解析----apiserverルーティング解析(1)

7569 ワード

kubernetesソースコード解析----apiserverルーティング解析(1)
apiserverはk 8 sクラスタの唯一のエントリとして、内部には主に2つの機能が実現されている.1つは要求のルーティングと処理であり、簡単に言えば1つのポートを傍受し、受信した要求を適切に対応する処理ロジックに転送し、もう1つの機能は認証と権限制御である.本文は主にapiserverのルーティング構築過程を解析する.apiserverはgo-restfulを使用してREST-style Webサービスを構築しているので、まずapiserverのソースコードをよりよく理解するために、このパッケージに関する内容を理解してみましょう.
(kubernetesコードバージョン:1.3.6 Commit id:ed 3 a 29 bd 6 aeb)
go-restful
Package restful, a lean package for creating REST-style WebServices without magic.
go-restfulはREST-style Webサービスを構築するためのgolangパッケージで、その由来はgo-restful-api-designを参照して、大体javaerがgolangの中でついでのREST-basedサービス構築パッケージを見つけていないことを意味しているので、Javaでよく使われるJAX-RSの設計に従ってgolangの中で車輪を作った.
go-restfulの中のいくつかのコンポーネントと特性
  • Routeルーティングは、標準JSR 311インタフェース仕様の実装RouterJSR 311と、高速ルーティングCurlyRouterの2つを含む.CurlyRouterは正規表現と動的パラメータをサポートし、RouterJSR 311よりも軽量級であり、apiserverではこのルーティングが使用されている.1つのRouteの設定には、要求メソッド(Http Method)、要求パス(URL Path)、処理メソッド、およびオプションの受信コンテンツタイプ(Content-Type)、応答コンテンツタイプ(Accept)などが含まれる.
  • WebService WebServiceは論理的にRouteの集合であり、機能的には主にRouteのセットにroot path、リクエスト応答のデータ型など、いくつかの共通の属性を統一的に設定する.WebServiceが有効になるにはContainerに加入する必要があります.
  •     func InstallVersionHandler(mux Mux, container *restful.Container) {
            // Set up a service to return the git code version.
            versionWS := new(restful.WebService)
        
            versionWS.Path("/version")
            versionWS.Doc("git code version from which this is built")
            versionWS.Route(
                versionWS.GET("/").To(handleVersion).
                    Doc("get the code version").
                    Operation("getCodeVersion").
                    Produces(restful.MIME_JSON).
                    Consumes(restful.MIME_JSON).
                    Writes(version.Info{}))
            container.Add(versionWS)
        }
  • Container Containerは論理的にWebServiceの集合であり,機能的にマルチ端末の効果を実現できる.たとえば、次のコードでは2つのContainerが作成され、それぞれ異なるport上でサービスが提供されます.
  •     func main() {
            ws := new(restful.WebService)
            ws.Route(ws.GET("/hello").To(hello))
            // ws       container restful.DefaultContainer 
            restful.Add(ws)
            go func() {
              // restful.DefaultContainer      8080 
                http.ListenAndServe(":8080", nil)
            }()
        
            container2 := restful.NewContainer()
            ws2 := new(restful.WebService)
            ws2.Route(ws2.GET("/hello").To(hello2))
            // ws2    container container2 
            container2.Add(ws2)
            // container2      8081 
            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")
        }
  • Filter Filterは、動的なブロッキング要求および応答のために使用され、対応するコンポーネントの前に配置されたフックと同様に、対応するコンポーネント機能の実行前に要求または応答をキャプチャし、主にlogの記録、検証、リダイレクトなどの機能に使用される.go-restfulには3種類のFilterがあります.
  • Container Filterは、Container内のすべてのWebServiceが実行される前に実行されます.
  • // install a (global) filter for the default container (processed before any webservice)
    restful.Filter(globalLogging)
  • WebService Filterは、WebService内のすべてのRouteが実行される前に実行されます.
  • // install a webservice filter (processed before any route)
    ws.Filter(webserviceLogging).Filter(measureTime)
  • Route Filterは、Routeバインディングのメソッドを呼び出す前に実行されます.
  • // install 2 chained route filters (processed before calling findUser)
    ws.Route(ws.GET("/{user-id}").Filter(routeLogging).Filter(NewCountFilter().routeCounter).To(findUser))

    使用例
    次のコードは、公式に提供された例です.
    package main
    
    import (
        "github.com/emicklei/go-restful"
        "log"
        "net/http"
    )
    
    type User struct {
        Id, Name string
    }
    
    type UserResource struct {
        // normally one would use DAO (data access object)
        users map[string]User
    }
    
    func (u UserResource) Register(container *restful.Container) {
        //     WebService
        ws := new(restful.WebService)
      
        //   WebService     ("/users")    MIME  (restful.MIME_XML/ restful.MIME_JSON)
        ws.
            Path("/users").
            Consumes(restful.MIME_XML, restful.MIME_JSON).
            Produces(restful.MIME_JSON, restful.MIME_XML) // you can specify this per route as well
    
        //     : GET /{user-id} --> u.findUser
        ws.Route(ws.GET("/{user-id}").To(u.findUser))
      
        //     : POST / --> u.updateUser
        ws.Route(ws.POST("").To(u.updateUser))
      
        //     : PUT /{user-id} --> u.createUser
        ws.Route(ws.PUT("/{user-id}").To(u.createUser))
      
        //     : DELETE /{user-id} --> u.removeUser
        ws.Route(ws.DELETE("/{user-id}").To(u.removeUser))
    
        //       WebService   Container 
        container.Add(ws)
    }
    
    // GET http://localhost:8080/users/1
    //
    func (u UserResource) findUser(request *restful.Request, response *restful.Response) {
        id := request.PathParameter("user-id")
        usr := u.users[id]
        if len(usr.Id) == 0 {
            response.AddHeader("Content-Type", "text/plain")
            response.WriteErrorString(http.StatusNotFound, "User could not be found.")
        } else {
            response.WriteEntity(usr)
        }
    }
    
    // POST http://localhost:8080/users
    // 1Melissa Raspberry
    //
    func (u *UserResource) updateUser(request *restful.Request, response *restful.Response) {
        usr := new(User)
        err := request.ReadEntity(&usr)
        if err == nil {
            u.users[usr.Id] = *usr
            response.WriteEntity(usr)
        } else {
            response.AddHeader("Content-Type", "text/plain")
            response.WriteErrorString(http.StatusInternalServerError, err.Error())
        }
    }
    
    // PUT http://localhost:8080/users/1
    // 1Melissa
    //
    func (u *UserResource) createUser(request *restful.Request, response *restful.Response) {
        usr := User{Id: request.PathParameter("user-id")}
        err := request.ReadEntity(&usr)
        if err == nil {
            u.users[usr.Id] = usr
            response.WriteHeader(http.StatusCreated)
            response.WriteEntity(usr)
        } else {
            response.AddHeader("Content-Type", "text/plain")
            response.WriteErrorString(http.StatusInternalServerError, err.Error())
        }
    }
    
    // DELETE http://localhost:8080/users/1
    //
    func (u *UserResource) removeUser(request *restful.Request, response *restful.Response) {
        id := request.PathParameter("user-id")
        delete(u.users, id)
    }
    
    func main() {
        //       Container
        wsContainer := restful.NewContainer()
      
        //      CurlyRouter
        wsContainer.Router(restful.CurlyRouter{})
      
        //       Resource Handle(   UserResource)
        u := UserResource{map[string]User{}}
      
        //   WebService,  WebService   Container 
        u.Register(wsContainer)
    
        log.Printf("start listening on localhost:8080")
        server := &http.Server{Addr: ":8080", Handler: wsContainer}
        
        //     
        log.Fatal(server.ListenAndServe())
    }

    上記の例ではRestfulサービスを構築し、いくつかのステップに分けてapiserverでも同様です.
  • Containerを作成します.
  • カスタムResource Handleを作成し、Resource関連の処理方法を実装します.
  • Resourceに対応するWebServiceを作成し、WebServiceに対応するRouteを追加し、ContainerにWebServiceを追加します.
  • リスニングサービスを開始します.

  • 転載先:https://www.cnblogs.com/ldaniel/p/5868384.html