天天看點

帶你讀《雲原生應用開發 Operator原理與實踐》第二章 Operator 原理2.2Client-go 原理(十四)

2.2.7         Transport 說明

本節簡要介紹 Client-go源碼中 Transport包的實作和底層原理。

1. Transport功能說明

Transport提 供 認 證 授 權 安 全 的 傳 輸 控 制 協 議(TCP,TransmissionControlProtocol)連接配接,基于 SPDY協定支援 HTTP流(Stream)傳輸機制。Transport包是通過自定義 Transport對 http.Client的定制化封裝實作的,在 Client-go源碼中作為工具包為 RESTClient封裝 HTTP 用戶端請求。在實際開發過程中,一般隻需要調用 Client-go中提供的 RESTClient、DiscoveryClient、ClientSet、DynamicClient即可。

2. Transport的内部實作

Transport包主要是對 http.RoundTripper 的封裝實作,為了更好地了解本節内容,首先介紹 http.RoundTripper的概念和實作,然後介紹 Transport是怎樣封裝http.RoundTripper的。最後簡要介紹Client-go包中底層的 RESTClient是如何使用 Transport的。

(1)      http.RoundTripper

http.RoundTripper能夠執行單個 HTTP事務,擷取給定請求的響應。實作http.RoundTripper接口的代碼通常需要在多個   Goroutine   中并發執行,是以,必須確定實作代碼的線程安全性。

http.RoundTripper是在 Go語言 HTTP包中定義的接口,接口定義見代碼清單 2-49。

typeRoundTripperinterface{RoundTrip(*Request)(*Response,error)

}

從上述代碼中可以看出,http.RoundTripper接口很簡單,隻定義了一個名為 RoundTrip的方法。RoundTrip() 方法用于執行一個獨立的 HTTP事務,接收傳入的 *Request 請求值作為參數并傳回對應的 *Response響應值,以及一個 error值。任何實作了 RoundTrip() 方法的類型都實作了http.RoundTripper接口。

代碼清單 2-50簡單展示了 http.RoundTripper接口的實作。

typetestTransportstruct{agentstring

originalTransporthttp.RoundTripper

func(c*testTransport)RoundTrip(r*http.Request)(*http.Response,error){iflen(r.Header.Get("User-Agent"))!=0{

returnc.originalTransport.RoundTrip(r)

r=utilnet.CloneRequest(r)r.Header.Set("User-Agent",c.agent)

resp,err:=c.originalTransport.RoundTrip(r)

iferr!=nil{

returnnil,err

returnresp,nil

上述代碼定義了一個 testTransport結構體類型,通過實作該類型的RoundTrip方法實作了該類型的 http.RoundTripper接口。該接口的功能是在 HTTP的請求頭中添加 User-Agent參數。通過以上 http.RoundTripper接口的簡單實作,我們了解了 http.RoundTripper接口是如何封裝 HTTP請求的。Transport包中以同樣的方式實作了多種封裝類型。下面具體介紹 Transport包中 http.RoundTripper的封裝。

(2)      Transport包中對 http.RoundTripper的封裝

Transport包中定義了 New函數,該函數通過傳入的 Config參數建立 http.Round-Tripper,具體見代碼清單 2-51。

funcNew(config*Config)(http.RoundTripper,error){

//設定Transport的安全級别

ifconfig.Transport!=nil&&(config.HasCA()||config.HasCertAuth()||config.HasCertCallback()||config.TLS.Insecure){

returnnil,fmt.Errorf("usingacustomtransportwithTLScertificateoptionsortheinsecureflagisnotallowed")

var(

rthttp.RoundTrippererrerror

)

ifconfig.Transport!=nil{rt=config.Transport

}else{

rt,err=tlsCache.get(config)

iferr!=nil{returnnil,err

returnHTTPWrappersForConfig(config,rt)

在 New函數中,首先通過 config 對象的方法擷取認證資訊,如果認證資訊是非安全設定的,則傳回 nil;如果配置中滿足安全設定,則 New函數會讀取配置中的 Transport資訊;如果 Transport為空,New 函數就從緩存中讀取緩存的 Transport,如果緩存中沒有Transport,那麼需要初始化一個預設的 Transport。最後調用 HTTPWrappersForConfig函數,該函數将Config作為參數對 Transport進行進一步的封裝。

HTTPWrappersForConfig函數見代碼清單 2-52。

funcHTTPWrappersForConfig(config*Config,rthttp.RoundTripper)(http.RoundTripper,

error){

ifconfig.WrapTransport!=nil{rt=config.WrapTransport(rt)

rt=DebugWrappers(rt)

//Setauthenticationwrappersswitch{

caseconfig.HasBasicAuth()&&config.HasTokenAuth():

returnnil,fmt.Errorf("username/passwordorbearertokenmaybeset,butnot

both")

caseconfig.HasTokenAuth():

varerrerror

rt,err=NewBearerAuthWithRefreshRoundTripper(config.BearerToken,config.

BearerTokenFile,rt)

caseconfig.HasBasicAuth():

rt=NewBasicAuthRoundTripper(config.Username,config.Password,rt)

iflen(config.UserAgent)>0{

rt=NewUserAgentRoundTripper(config.UserAgent,rt)

iflen(config.Impersonate.UserName)>0||len(config.Impersonate.Groups)>0||len(config.Impersonate.Extra)>0{

rt=NewImpersonatingRoundTripper(config.Impersonate,rt)

returnrt,nil

HTTPWrappersForConfig函數可以根據不同配置的認證資訊建立不同的 http.Round‐Tripper。由以上代碼可知該函數共建立了4種不同類型的 http.RoundTripper。

① NewBearerAuthWithRefreshRoundTripper建立了 BearerAuthWithRefres-hRoundTripper類型對象, 實作了 http.RoundTripper接口, 并将提供的Bearer令牌添加到請求中,如果 tokenFile是非空的,則定期讀取 tokenFile,最後一次成功讀取的内容作為 Bearer令牌;如果 tokenFile是非空的,而 Bearer是空的,tokenFile會被立即讀取,以填充初始的 Bearer 令牌。

② NewBasicAuthRoundTripper建立了 basicAuthRoundTripper類型對象,它将基本 auth 授權應用到請求中,通過使用者名和密碼授權實作 http.RoundTripper接口。

③ NewUserAgentRoundTripper建立了userAgentRoundTripper類型對象,它向請求添加 User-Agent請求頭,實作了 http.RoundTripper接口。

④ NewImpersonatingRoundTripper建立了 ImpersonatingRoundTripper類型對象,向請求添加一個 Act-As請求頭,實作了 http.RoundTripper接口。

以上4種不同類型的http.RoundTripper實作方式與2.2.6 節的案例實作是同一種方式,這裡不再贅述。除了以上4種不同類型的 http.RoundTripper對 http.RoundTripper接口的實作,Transport中還包括 authProxyRoundTripper、debuggingRoundTripper等其他類型,具體可在/client-go/transport/round_trippers.go檔案中檢視。

繼續閱讀