Kube APIServer と go-restful のエントリ ポイントの基本を理解したので、APIExtensionServer がどのようにインスタンス化されるかを理解し始めることができます。 API拡張サーバーAPIExtensionServer の作成プロセスには、通常、次の手順が含まれます。 - GeneriAPIServerを作成する
- CustomResourceDefinitions のインスタンス化
- APIGroupInfo をインスタンス化する
- インストールAPIグループ
これら 3 種類のサーバーすべての最下層は、GeneriAPIServer に依存する必要があります。 2 番目の手順で作成された CustomResourceDefinitions は、現在のタイプの Server オブジェクトであり、後続のルーティング登録に使用されます。 APIGroupInfo は、各バージョンおよび各リソース タイプに対応するストレージ オブジェクトです。最後に、 InstallAPIGroup を呼び出してルートを登録し、各リソースのバージョンとタイプを URI アドレスにマッピングします。コードは次のようになります。 // cmd/kube-apiserver/app/apiextensions.go func createAPIExtensionsServer ( apiextensionsConfig * apiextensionsapiserver.Config , delegateAPIServer genericapiserver.DelegationTarget ) ( * apiextensionsapiserver.CustomResourceDefinitions , error ) { apiextensionsConfigを返します。完了() 。新規( delegateAPIServer ) }
// 実際のコードは次の場所にあります: /vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/apiserver.go // New は指定された構成から CustomResourceDefinitions の新しいインスタンスを返します func ( c CompletedConfig ) New ( delegationTarget genericapiserver.DelegationTarget ) ( * CustomResourceDefinitions , error ) { // APIExtensionsServer は GenericAPIServer に依存します
// GenericConfig を通じて apiextensions-apiserver という名前の genericServer を作成します genericServer 、エラー: = c 。汎用構成。新規( "apiextensions-apiserver" 、 delegationTarget )
// CustomResourceDefinitions オブジェクトをインスタンス化します s : = &カスタムリソース定義{ GenericAPIServer : genericServer 、 }
apiResourceConfig : = cです。汎用構成。マージされたリソース構成
// APIGroupInfo オブジェクトをインスタンス化します。 APIGroup は、サーバーが公開する必要がある API を参照します。 apiGroupInfo : = genericapiserver 。 NewDefaultAPIGroupInfo ( apiextensions . GroupName , Scheme , metav1 . ParameterCodec , Codecs )
// v1 が有効な場合は、リソース バージョン、リソース、およびリソース ストレージを APIGroupInfo マップに保存します。 apiResourceConfigの場合。バージョンが有効( v1 . SchemeGroupVersion ) { ストレージ: = map [文字列] rest .ストレージ{} customResourceDefinitionStorage 、エラー: = customresourcedefinition 。 NewREST ( Scheme 、 c . GenericConfig . RESTOptionsGetter )
ストレージ[ "customresourcedefinitions" ] = customResourceDefinitionStorage ストレージ[ "customresourcedefinitions/status" ] = customresourcedefinition 。 NewStatusREST (スキーム、カスタムリソース定義ストレージ)
apiGroupInfo 。バージョン付きリソースストレージマップ[ v1 .スキームグループバージョン。バージョン] =ストレージ }
//登録API err : = sの場合。汎用APIサーバー。 APIGroup をインストールします( & apiGroupInfo );エラー!=ゼロ{ nilまたはerrを返す }
// コントローラを初期化するために、CRD クライアントセットとインフォーマーを初期化します crdClient 、エラー: = clientset 。 NewForConfig ( s . GenericAPIServer . LoopbackClientConfig ) s 。情報提供者=外部情報提供者。 NewSharedInformerFactory ( crdClient 、 5 *時間.分)
delegateHandler : = delegationTarget 。保護されていないハンドラ() delegateHandler == nilの場合{ delegateHandler = http 。見つからないハンドラ() }
バージョン検出ハンドラ: = &バージョン検出ハンドラ{ 検出:マップ[スキーマ. GroupVersion ] *検出。 APIバージョンハンドラー{}, デリゲート: delegateHandler 、 } グループディスカバリハンドラ: = &グループディスカバリハンドラ{ 検出:マップ[文字列] *検出。 APIグループハンドラ{}, デリゲート: delegateHandler 、 } // コントローラーを初期化する コントローラを確立します: =確立します。 NewEstablishingController ( s . Informers . Apiextensions () . V1 () . CustomResourceDefinitions (), crdClient . ApiextensionsV1 ()) // ハンドラーを申請する crdHandler 、エラー: = NewCustomResourceDefinitionHandler ( バージョン検出ハンドラ、 グループ検出ハンドラ、 s 。情報提供者。 API拡張機能()。 V1 ()。カスタムリソース定義()、 // ...... ) s 。汎用APIサーバー。ハンドラー。非GoRestfulMux 。ハンドル( "/apis" 、 crdHandler ) s 。汎用APIサーバー。ハンドラー。非GoRestfulMux 。ハンドルプレフィックス( "/apis/" 、 crdHandler ) // 他のコントローラーを初期化する discoveryController : = NewDiscoveryController ( s . Informers . Apiextensions () . V1 () . CustomResourceDefinitions ()、 versionDiscoveryHandler 、 groupDiscoveryHandler ) namingController : =ステータス。 NewNamingConditionController ( s . Informers . Apiextensions () . V1 () . CustomResourceDefinitions (), crdClient . ApiextensionsV1 ()) nonStructuralSchemaController : =非構造スキーマ。 NewConditionController ( s . Informers . Apiextensions () . V1 () . CustomResourceDefinitions (), crdClient . ApiextensionsV1 ()) apiApprovalController : = apiapproval 。新しいKubernetesAPIApprovalPolicyConformantConditionController ( s . Informers . Apiextensions () . V1 () . CustomResourceDefinitions (), crdClient . ApiextensionsV1 ()) ファイナライズコントローラ: =ファイナライザー。新しいCRDFinalizer ( s 。情報提供者。 API拡張機能()。 V1 ()。カスタムリソース定義()、 crdClient.ApiextensionsV1 () 、 crdHandler 、 ) // openapi コントローラーを初期化する openapiController : = openapicontroller 。 NewController ( s.Informers.Apiextensions (). V1 (). CustomResourceDefinitions ( ) ) var openapiv3Controller * openapiv3controller 。コントローラ utilfeature の場合。デフォルトのフィーチャゲート。有効(機能. OpenAPIV3 ) { .openapiv3Controllerをオーバーライドします。 NewController ( s.Informers.Apiextensions (). V1 (). CustomResourceDefinitions ( ) ) } // PostStartHook にインフォーマーとコントローラーを追加する s 。汎用APIサーバー。 AddPostStartHookOrDie ( "start-apiextensions-informers" 、 func ( context genericapiserver . PostStartHookContext )エラー{ s 。情報提供者。開始(コンテキスト. StopCh ) ゼロを返す }) // フック関数を登録し、先ほどインスタンス化したさまざまなコントローラを起動します s 。汎用APIサーバー。 AddPostStartHookOrDie ( "start-apiextensions-controllers" 、 func ( context genericapiserver . PostStartHookContext )エラー{
sの場合。汎用APIサーバー。 OpenAPIVersionedService != nil && s 。汎用APIサーバー。 StaticOpenAPISpec != nil { openapiController に移動します。実行( s.GenericAPIServer.StaticOpenAPISpec 、 s.GenericAPIServer.OpenAPIVersionedService 、 context.StopCh ) utilfeature の場合。デフォルトのフィーチャゲート。有効(機能. OpenAPIV3 ) { openapiv3Controller に移動します。実行( s.GenericAPIServer.OpenAPIV3VersionedService 、 context.StopCh ) } } // 各種コントローラーを起動する コントローラに名前を付けます。実行(コンテキスト.StopCh ) コントローラを確立します。実行(コンテキスト.StopCh ) nonStructuralSchemaControllerに移動します。実行( 5 、コンテキスト. StopCh ) apiApprovalControllerに移動します。実行( 5 、コンテキスト. StopCh ) コントローラを終了させます。実行( 5 、コンテキスト. StopCh )
discoverySyncedCh : = make ( chan構造体{}) 探索コントローラに移動します。実行(コンテキスト.StopCh , discoverySyncedCh ) 選択{ ケース<-コンテキスト。ストップCh : ケース<- discoverySyncedCh : }
ゼロを返す }) // ....
s 、 nilを返す } まず、GenericConfig を使用して apiextensions-apiserver という名前の genericServer を作成します。 GenericServer は汎用 HTTP サーバーを提供し、アドレス、ポート、認証、承認、ヘルス チェック、その他の一般的な機能などの共通テンプレートを定義します。 APIServer と APIExtensionsServer はどちらも genericServer に依存しており、実装は次のようになります。 // ベンダー/k8s.io/apiserver/pkg/server/config.go // New は、渡されたサーバーと処理チェーンを論理的に結合する新しいサーバーを作成します。 // 名前はログレコードを区別するために使用されます func ( c CompletedConfig ) New ( name文字列、 delegationTarget DelegationTarget ) ( * GenericAPIServer 、 error ) { // ...
handlerChainBuilder : = func ( handler http.Handler ) http .ハンドラ{ // BuildHandlerChainFunc を使用すると、apiHandler を装飾してカスタム ハンドラー チェーンを構築できます。 // 現在のデフォルトの処理チェーン関数は DefaultBuildHandlerChain です。これには多くのデフォルトの処理メソッドが含まれています cを返します。 BuildHandlerChainFunc (ハンドラ、 c.Config ) }
apiServerHandler : = NewAPIServerHandler ( name , c.Serializer , handlerChainBuilder , delegationTarget.UnprotectedHandler ( ) )
s : = & GenericAPIServer {
ハンドラー: apiServerHandler 、
リストされたパスプロバイダー: apiServerHandler 、
// ...... }
// ...... // すべてのインターフェース、メトリック インターフェースなどのインデックス作成など、いくつかの追加ルートをインストールします。 installAPI ( s 、 c 。 Config )
s 、 nilを返す }
// ベンダー/k8s.io/apiserver/pkg/server/handler.go // HandlerChainBuilderFn は、提供されたハンドラー チェーンを使用している GoRestfulContainer ハンドラーをラップするために使用されます。 // 通常は認証や承認などのアプリケーションフィルタリングに使用されます タイプHandlerChainBuilderFn func ( apiHandler http . Handler ) http .ハンドラ
// この関数は、go-restfulモードに従ってコンテナを初期化するために使用されます func NewAPIServerHandler ( name string 、 sランタイム.NegotiatedSerializer 、 handlerChainBuilder HandlerChainBuilderFn 、 notFoundHandler http .Handler ) * APIServerHandler { nonGoRestfulMux : = muxです。 NewPathRecorderMux (名前) notFoundHandler != nil の場合{ 非GoRestfulMux 。 NotFoundHandler ( notFoundHandler ) }
gorestfulContainer : =安らかに。新しいコンテナ() gorestfulコンテナ。サーブMux = http 。新しいサーブマルチプレックス() gorestfulコンテナ。 Router ( restful . CurlyRouter {}) // 例: proxy/{kind}/{name}/{*} gorestfulコンテナ。 RecoverHandler ( func ( panicReasonインターフェース{}, httpWriter http . ResponseWriter ) { logStackOnRecover ( s 、 panicReason 、 httpWriter ) のログ }) gorestfulコンテナ。 ServiceErrorHandler ( func ( serviceErr restful.ServiceError , request * restful.Request , response * restful.Response ) { serviceErrorHandler ( s 、 serviceErr 、 request 、 response ) })
ディレクター: =ディレクター{ 名前:名前、 goRestfulContainer : gorestfulContainer 、 非GoRestfulMux :非GoRestfulMux 、 }
戻り値& APIServerHandler { FullHandlerChain : handlerChainBuilder (ディレクター)、 GoRestfulContainer : gorestfulContainer 、 非GoRestfulMux :非GoRestfulMux 、 監督:監督、 } } 次に、CRD と APIGroupInfo をインスタンス化します。 APIGroupInfo オブジェクトは、リソース グループ情報を記述するために使用されます。 1 つのリソースは 1 つの APIGroupInfo オブジェクトに対応し、各リソースは 1 つのリソース ストレージ オブジェクトに対応します。 // /vendor/k8s.io/apiextensions-apiserver/pkg/server/genericapiserver.go func NewDefaultAPIGroupInfo (グループ文字列、スキーム*ランタイム.Scheme、パラメーターコードランタイム.ParameterCodec、コーデックシリアライザー.CodecFactory ) APIGroupInfo { APIGroupInfoを返す{ PrioritizedVersions :スキーム。 PrioritizedVersionsForGroup (グループ)、 // このマップは、リソースとリソース ストレージ オブジェクト間のマッピング関係を格納するために使用されます // 形式: リソース バージョン/リソース/リソース ストレージ オブジェクト // リソース CRUD を担当するリソース ストレージ オブジェクト RESTStorage //その後、RESTStorageをhttpハンドラ関数に変換します VersionedResourcesStorageMap : map [文字列] map [文字列] rest .ストレージ{}、
オプション外部バージョン: &スキーマ。グループバージョン{バージョン: "v1" }, スキーム:スキーム、 パラメータコーデック:パラメータコーデック、 NegotiatedSerializer :コーデック、 } } 次に、APIGroupInfo を登録する必要があります。これは、s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo) を通じて実行され、APIGroupInfo 内のリソース オブジェクトが APIExtensionServerHandler 関数に登録されます。プロセスは次のとおりです。 - APIGroupInfo をトラバースします。
- リソース グループ、リソース バージョン、およびリソース名を http パス要求パスにマップします。
- InstallREST 関数を使用して、リソース オブジェクトをリソース ハンドラー メソッドとして保存します。
- 最後に、go-restful の ws.Route を使用して、定義されたリクエスト パスとハンドラー メソッドを go-restful に追加します。
詳細なコードは次のとおりです。 // /vendor/k8s.io/apiextensions-apiserver/pkg/server/genericapiserver.go
// 指定された APIGroup を API で公開します func ( s * GenericAPIServer ) InstallAPIGroup ( apiGroupInfo * APIGroupInfo )エラー{ s.InstallAPIGroups ( apiGroupInfo )を返します。 }
func ( s * GenericAPIServer ) InstallAPIGroups ( apiGroupInfos ... * APIGroupInfo )エラー{
// ... // OpenAPI モデルを取得する openAPIModels 、エラー: = s 。 getOpenAPIModels ( APIGroupPrefix 、 apiGroupInfos ...) を取得します。 // すべてのリソース情報を走査し、リソースバージョンプロセッサを一度インストールします _の場合、 apiGroupInfo : =範囲apiGroupInfos { err : = sの場合。 APIリソースをインストールします( APIGroupPrefix 、 apiGroupInfo 、 openAPIModels )。エラー!=ゼロ{ fmtを返します。 Errorf ( "API リソースをインストールできません: %v" 、 err ) }
apiVersionsForDiscovery : = [] metav1 。検出用グループバージョン{} // ... apiGroup : = metav1です。 APIグループ{ 名前: apiGroupInfo 。優先バージョン[ 0 ]。グループ、 バージョン: apiVersionsForDiscovery 、 優先バージョン:優先バージョン検出、 }
s 。ディスカバリーグループマネージャー。グループの追加( apiGroup ) s 。ハンドラー。 GoRestfulContainer 。追加( discovery . NewAPIGroupHandler ( s . Serializer , apiGroup ). WebService ()) } ゼロを返す }
// installAPIResources は各 API グループバージョンリソースをサポートするために RESTStorage をインストールするために使用されます func ( s * GenericAPIServer ) installAPIResources ( apiPrefix string 、 apiGroupInfo * APIGroupInfo 、 openAPIModels openapiproto . Models )エラー{ var resourceInfos [] * storageversion 。リソース情報 _の場合、 groupVersion : = range apiGroupInfo 。優先バージョン{
apiGroupVersion : = s 。 APIグループバージョンを取得します( apiGroupInfo 、 groupVersion 、 apiPrefix ) // ... apiグループバージョン。 MaxRequestBodyBytes = s 。最大リクエストボディバイト数
// コアは InstallREST を呼び出すことです。パラメータは go-restful のコンテナ オブジェクトです。 r 、エラー: = apiGroupVersion 。 InstallREST ( s . Handler . GoRestfulContainer ) // ... resourceInfos = append ( resourceInfos , r ...) }
// ...
ゼロを返す }
// InstallREST は、REST ハンドラー (ストレージ、ウォッチ、プロキシ、リダイレクト) を RESTful コンテナーに登録します。 // 指定されたパスのルートプレフィックスはすべての操作に対応することが期待されており、ルートはスラッシュで終わることはできません。 func ( g * APIGroupVersion ) InstallREST ( container * restful.Container ) ([] * storageversion.ResourceInfo , error ) { // たとえば、InstallAPI 呼び出しチェーンから、ここでの g.Root は /apis なので、ハンドラーのプレフィックスは /apis/{goup}/{version} であると判断できます。 プレフィックス: =パス。結合( g.Root 、 g.GroupVersion.Group 、 g.GroupVersion.Version ) //APIInstallerオブジェクトをインスタンス化する インストーラー: = & APIInstaller { グループ: g 、 接頭辞:接頭辞、 minRequestTimeout : g 。最小リクエストタイムアウト、 } // Install関数を呼び出します。APIを登録し、go-restful WebServiceオブジェクトを返します。 apiResources 、 resourceInfos 、 ws 、 registrationErrors : =インストーラー。インストール() バージョンDiscoveryHandler : =検出。新しいAPIVersionHandler ( g.Serializer 、 g.GroupVersion 、 staticLister { apiResources }) バージョンDiscoveryHandler.AddToWebService (ws ) // コンテナに WebService を追加します。これには go-restful フレームワークの知識が必要です。 容器。追加( ws ) removeNonPersistedResources ( resourceInfos )、 utilerrors を返します。新しい集計(登録エラー) } 上記のプロセス全体は、API を登録するための準備です。コアは installer.Install() 関数にあり、API リソースをプロセッサに追加するために使用されます。 // /vendor/k8s.io/apiserver/pkg/endpoints/installer.go
// APIインストーラのプレフィックスとバージョンを使用して、新しいRESTful Webサービスオブジェクトを作成します // この部分は go-restful フレームワークの使用法に属します func ( a * APIInstaller ) newWebService () * restful 。 Webサービス{ ws : = new ( restful.WebService )を追加します。 ws 。パス( .プレフィックス) // a.prefix には「prefix/group/version」が含まれます ws 。 Doc ( 「API at」 + .プレフィックス) ws 。消費する( "*/*" ) mediaTypes 、 streamMediaTypes : =ネゴシエーション。 MediaTypesForSerializer ( .グループ. Serializer ) ws 。 ( append ( mediaTypes 、 streamMediaTypes ...)...)を生成します。 ws 。 ApiVersion ( a.group.GroupVersion.String ( ) ) WSを返す }
func ( a * APIInstaller ) Install () ([] metav1 . APIResource , [] * storageversion . ResourceInfo , * restful . WebService , [] error ) { var apiResources [] metav1 。 APIリソース var resourceInfos [] * storageversion 。リソース情報 var errors []エラー
// 新しい WebService オブジェクトを作成します (go-restful フレームワーク内) ws : = aです。新しいWebサービス()
// パスをソートする パス: = make ([]文字列, len ( a .グループ.ストレージ)) var i int = 0 パスの場合: =範囲a 。グループ。ストレージ{ パス[ i ] =パス 私は++ } 選別。文字列(パス) // Swagger仕様を取得する _の場合、パス: =範囲パス{ // ストレージをルーターに変換し、ルートを Web サービスに登録します apiResource 、 resourceInfo 、 err : = a 。 registerResourceHandlers (パス、 a .グループ.ストレージ[パス]、 ws )
apiResource != nil の場合{ apiResources =追加( apiResources 、 * apiResource ) } リソース情報!= nilの場合{ resourceInfos =追加( resourceInfos 、 resourceInfo ) } } apiResources 、 resourceInfos 、 ws 、 errorsを返します。 } ここで最も重要なのは、registerResourceHandlers 関数です。この方法は非常に長いです。そのコア機能は、ストレージに基づいてハンドラーを構築し、ハンドラーとパスを go-restful フレームワークの Route オブジェクトに構築し、最後に Route を Web サービスに追加することです。 // /vendor/k8s.io/apiserver/pkg/endpoints/installer.go func ( a * APIInstaller ) registerResourceHandlers ( path string , storage rest.Storage , ws * restful.WebService ) ( * metav1 . APIResource , * storageversion . ResourceInfo , error ) { // ......
// 名前空間レベルですか? var名前空間スコープ付きブール // ......
// ストレージはどの動詞操作をサポートしていますか?これは、各パスでサポートされている操作を理解するために使用されます。 creater 、 isCreater : = storage .( rest . Creater ) namedCreater 、 isNamedCreater : = storage .( rest . NamedCreater ) リストア、 isLister : =ストレージ. (rest.Lister ) getter 、 isGetter : = storage .( rest . Getter )
// ......
// 指定された範囲の操作リストを取得します スイッチ{ 場合!名前空間スコープ: // ノードなどの名前空間スコープ外のリソースを処理する // ......
// リソースパスにアクションを追加します: /api/apiVersion/resource アクション= appendIf (アクション、アクション{ "LIST" 、リソースパス、リソースパラメータ、ネームサーバー、 false }、 isLister ) アクション= appendIf (アクション、アクション{ "POST" 、リソースパス、リソースパラメータ、ネームサーバー、 false }、 isCreater ) アクション= appendIf (アクション、アクション{ "DELETECOLLECTION" 、リソースパス、リソースパラメータ、ネームサーバー、 false }、 isCollectionDeleter ) // ...... デフォルト: // 名前空間レベルのリソース オブジェクト namespaceParamName : = "名前空間" 名前空間Param : = ws 。 PathParameter ( "namespace" 、 "チームやプロジェクトなどのオブジェクト名と認証スコープ" )。データ型( "文字列" ) namespacedPath : = namespaceParamName + "/{namespace}/" +リソース namespaceParams : = [] * restful です。パラメータ{ namespaceParam } // ...... // アクションリストを構築 アクション= appendIf (アクション、アクション{ "LIST" 、リソースパス、リソースパラメータ、ネームサーバー、 false }、 isLister ) アクション= appendIf (アクション、アクション{ "POST" 、リソースパス、リソースパラメータ、ネームサーバー、 false }、 isCreater ) // ......
}
// アクションのルートを作成する
// go-restfulによって生成されたMIMEタイプを設定します mediaTypes 、 streamMediaTypes : =ネゴシエーション。 MediaTypesForSerializer ( .グループ. Serializer ) allMediaTypes : = append ( mediaTypes 、 streamMediaTypes ...) を追加します。 ws.Produces (allMediaTypes ... )
// ... _の場合、アクション: =範囲アクション{ // ......
// Go-Restful RouteBuilder オブジェクトを構築します ルート: = [] *安らかに。ルートビルダー{}
// サブリソースの場合、種類は現在の種類と同じである必要があります サブリソースの場合{ parentStorage 、 OK : = a 。グループ。ストレージ[リソース]
fqParentKind 、 err : = GetResourceKind ( a.group.GroupVersion 、 parentStorage 、 a.group.Typer )
種類= fqParentKind 。親切 }
//異なる動詞に応じて異なるハンドラに登録する スイッチアクション。動詞{ ケース「GET」 : varハンドラーRESTful 。 RouteFunction // go-restful ハンドラー // ハンドラを初期化する isGetterWithOptionsの場合{ ハンドラー= restfulGetResourceWithOptions ( getterWithOptions 、 reqScope 、 isSubresource ) }それ以外{ ハンドラー= restfulGetResource (ゲッター、 reqScope ) }
//...
// ルートを構築します(これは go-restful フレームワークを使用する方法です) ルート: = ws 。 GET (アクション.パス)。 (ハンドラー)宛。 ドキュメント( doc )。 Param ( ws . QueryParameter ( "pretty" , "「true」の場合、出力はきれいに印刷されます。" ))。 操作( 「読み取り」 +名前空間+種類+文字列。タイトル(サブリソース) +操作サフィックス)。 ( append ( storageMeta . ProducesMIMETypes ( action . Verb ), mediaTypes ...)...)を生成します。 ( http . StatusOK 、 "OK" 、 producedObject )を返します。 書き込み( producedObject )
// ルートにルートを追加する addParams (ルート、アクション、 Params ) ルート=追加(ルート、ルート) // ...他の動詞処理方法は基本的に同じです case "POST" : // リソースを作成します。 varハンドラーrestful .RouteFunction isNamedCreaterの場合{ ハンドラー= restfulCreateNamedResource ( namedCreater 、 reqScope 、 admission ) }それ以外{ ハンドラー= restfulCreateResource ( creater 、 reqScope 、 admission ) } // ...... }
// ルートをトラバースしてWebServiceに追加します _の場合、ルート: =範囲ルート{ ルート。メタデータ( ROUTE_META_GVK 、 metav1 。 GroupVersionKind { グループ: reqScope 。親切。グループ、 バージョン: reqScope 。親切。バージョン、 種類: reqScope 。親切。親切、 }) ルート。メタデータ( ROUTE_META_ACTION 、文字列. ToLower (アクション. Verb )) // WebService にルートを追加 ws 。ルート(ルート) } }
// ......
戻り値& apiResource , resourceInfo , nil } registerResourceHandlers 関数は非常に長いですが、詳細は脇に置いて全体として理解することができます。まず、Storage を使用してサポートされている Verbs 操作を判別し、次にアクション リストを生成し、最後に各アクションのルート リストを構築することがわかります。最後に、これらのルートが go-restful WebService に追加されます。ここで構築されるプロセッサにバインドされるルートには、さまざまな実装方法があります。たとえば、GET ハンドラーは restfulGetResource を通じてインスタンス化され、POST ハンドラーは restfulCreateResource を通じてインスタンス化されます。実装方法は基本的に同じです。 GET メソッド ハンドラー関数 restfulGetResource の実装は次のとおりです。 // /vendor/k8s.io/apiserver/pkg/endpoints/installer.go func restfulGetResource ( r rest.Getter ,スコープハンドラー.RequestScope ) restful .ルート関数{ 戻り値func ( req * restful.Request , res * restful.Response ) { ハンドラー。 GetResource ( r 、 & scope )( res . ResponseWriter 、 req . Request ) } } restfulGetResource 関数は、go-restful の方法で restful.RouteFunction を取得します。実際に処理されるのは、getResourceHandler を呼び出すhandlers.GetResource 関数です。この関数は、対応するルート要求を処理するための http 標準ライブラリ ハンドラー関数を返します。 GET リクエストの処理は比較的簡単です。要求されたクエリを通じて metav1.GetOptions が構築され、処理のために Getter インターフェイスに渡されます。最後に、クエリ結果が変換され、要求者に返されます。 //vendor/k8s.io/apiserver/pkg/endpoints/handlers/get.go
// GetResource は、rest.Storage オブジェクトから単一のリソースを取得する関数を返します。 func GetResource ( r rest . Getter 、 scope * RequestScope ) http .ハンドラ関数{ getResourceHandler (スコープ、 func ( ctx context.Context , name string , req * http.Request , trace * utiltrace.Trace ) ( runtime.Object , error ) { // 必要なGetOptionsを初期化する オプション: = metav1 。オプションを取得{} // クエリパラメータを取得する 値の場合: = req 。 .URL .クエリ(); len (値) > 0 { // ... // クエリパラメータをデコードし、GetOptions オブジェクトをプログラムします errの場合: = metainternalversionscheme 。パラメータコーデック。 DecodeParameters (値、スコープ、 MetaGroupVersion 、およびオプション);エラー!=ゼロ{ err =エラー。 NewBadRequest ( err . Error ()) nilまたはerrを返す } } //次に、Getterインターフェースを使用して処理します rを返します。取得( ctx 、 name 、 & options ) }) }
// getResourceHandlerはリクエストを取得するために使用されるHTTPハンドラ関数です // 渡されたgetterFuncに実際の取得の実行を委任します function getResourceHandler ( scope * RequestScope 、 getter getterFunc ) http 。ハンドラ関数{ 戻り値func ( w http.ResponseWriter 、 req * http.Request ) { // ...
名前空間、名前、エラー: =スコープ。ネーマー。名前(必須)
/// ... ctx : =要求。コンテクスト() ctx =リクエスト. WithNamespace ( ctx 、名前空間)
outputMediaType 、 _ 、エラー: =ネゴシエーション。 NegotiateOutputMediaType ( req 、 scope 、 Serializer 、 scope )
// ... // getterFuncを使用して実際の取得操作を実行します。 結果、エラー: = getter ( ctx 、 name 、 req 、 trace ) // ...
//結果をユーザーが要求する形式に変換し、ユーザーに返します transformResponseObject ( ctx 、 scope 、 trace 、 req 、 w 、 http 、 StatusOK 、 outputMediaType 、 result )
} } POST ハンドラーも同様で、対応するロジックは restfulCreateResource にあります。 // /vendor/k8s.io/apiserver/pkg/endpoints/installer.go func restfulCreateResource ( r rest.Creater ,スコープhandlers.RequestScope , admission.Interface ) restful .ルート関数{ 戻り値func ( req * restful.Request , res * restful.Response ) { ハンドラー。 CreateResource ( r 、 & scope 、 admission )( res . ResponseWriter 、 req . Request ) } } 実際にリクエストを処理する関数は、createHandler を呼び出す handlers.CreateResource です。この関数は、対応するルーティング要求を処理するための http 標準ライブラリ ハンドラー関数を返します。 //vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go
// CreateNamedResource は、名前付きのリソース作成を処理する関数を返します。 func CreateNamedResource ( r rest.NamedCreater 、スコープ* RequestScope 、 admission admission.Interface ) http .ハンドラ関数{ createHandler ( r 、スコープ、入場、 true )を返します。 }
// CreateResource はリソース作成を処理する関数を返します func CreateResource ( r rest.Creater , scope * RequestScope , admission admission.Interface ) http .ハンドラ関数{ createHandler ( & namedCreaterAdapter { r },スコープ、アドミッション、 false )を返します。 } createHandler の実装コードは比較的長く、主に次のことを行います。 - クエリ文字列をデコードして metav1.CreateOptions を生成します。
- リクエスト本文のデータをデコードし、リソース オブジェクトを生成します。デコードされたオブジェクト バージョンは内部バージョンであり、リソース オブジェクトのすべてのバージョン フィールドの完全なセットです。同じコードを使用して、異なるバージョンのオブジェクトを処理できます。
- オブジェクトを変更する必要があるかどうかを判断するためのオブジェクトを変更するためのアクセス制御。
- 作成者インターフェイスに送信してリソース オブジェクトを作成します。
- データを期待される形式に変換し、応答に書き込みます。作成者インターフェイスを呼び出すことによって返される結果は、依然として内部バージョンです。エンコード時には、ユーザーが要求したバージョンにエンコードされ、ユーザーに返されます。
//vendor/k8s.io/apiserver/pkg/endpoints/handlers/create.go
// 対応するルーティング要求を処理するための http ハンドラ関数を返します func createHandler ( r rest . NamedCreater 、スコープ* RequestScope 、 admission . Interface 、 includeName bool ) http .ハンドラ関数{ //標準のhttpハンドラ関数 戻り値func ( w http.ResponseWriter 、 req * http.Request ) { // ...
outputMediaType 、 _ 、エラー: =ネゴシエーション。 NegotiateOutputMediaType ( req 、 scope 、 Serializer 、 scope )
// 適切なシリアライザーを見つける gv : =スコープ。親切。グループバージョン() s 、 err : =交渉。 NegotiateInputSerializer ( req 、 false 、 scope 。 Serializer )
// リクエストをCreateOptionsにデコードする オプション: = & metav1 。オプションの作成{} 値: =必須。 .URL .クエリ() errの場合: = metainternalversionscheme 。パラメータコーデック。 DecodeParameters (値、スコープ、 MetaGroupVersion 、オプション);エラー!=ゼロ{ // ... } // ... オプション。タイプメタ。 SetGroupVersionKind ( metav1 . SchemeGroupVersion . WithKind ( "CreateOptions" ))
defaultGVK : =スコープ。親切 オリジナル: = r 。新しい()
// ...
// 適切なデコーダーを見つける デコーダー: =スコープ。シリアライザー。 DecoderToVersion ( decodeSerializer 、スコープ. HubGroupVersion )
// デコードするボディをリクエストしてください obj 、 gvk 、 err : =デコーダー。デコード( body 、 defaultGVK 、 original )
ctx =リクエスト. WithNamespace ( ctx 、名前空間) // 監査、承認、リクエストのログ記録 ae : =監査。監査イベント元( ctx ) 認める=入場。監査付き(認める、 ae ) 監査。 LogRequestObject ( req . Context ()、 obj 、 objGV 、 scope . Resource 、 scope . Subresource 、 scope . Serializer )
userInfo 、 _ : =リクエスト。ユーザーFrom ( ctx )
入場属性: =入場。 NewAttributesRecord ( obj 、 nil 、 scope . Kind 、 namespace 、 name 、 scope . Resource 、 scope . Subresource 、 admission . Create 、 options 、 dryrun . IsDryRun ( options . DryRun )、 userInfo ) requestFunc : = func () ( runtime.Object , error ) { rを返します。作成する( ctx 、 名前、 オブジェクト、 休む。 AdmissionToValidateObjectFunc (認める、入場属性、スコープ)、 オプション、 ) }
// リクエストを処理する 結果、エラー: =フィニッシャー。 FinishRequest ( ctx , func () (ランタイム. Object , error ) { // ... // アドミッションコントロールの変更操作を実行します。つまり、オブジェクトの作成時に変更します。 mutatingAdmissionの場合、 ok : = admission .( admission . MutationInterface ); ok && mutatingAdmission 。ハンドル(入場.作成){ err の場合: = mutatingAdmission 。認める( ctx 、 admissionAttributes 、 scope );エラー!=ゼロ{ nilまたはerrを返す } } // ...... //createメソッドを呼び出す 結果、エラー: = requestFunc () 結果を返す、エラー })
コード: = http .ステータス作成済み ステータス、 OK : =結果。( * metav1 .ステータス) ok &&ステータスの場合。コード== 0 { 状態。コード= int32 (コード) } //結果をユーザーが要求する形式に変換し、ユーザーに返します transformResponseObject ( ctx 、 scope 、 trace 、 req 、 w 、 code 、 outputMediaType 、 result ) は、 } } KubeAPIサーバーKubeAPIServer は、組み込みリソース オブジェクトに対するリクエストを処理するために使用されるコア サーバーです。サーバーは次のように作成されます。 kubeAPIServer 、エラー: = CreateKubeAPIServer ( kubeAPIServerConfig 、 apiExtensionsServer。GenericAPIServer ) kubeAPIServerConfig は、汎用構成の生成を紹介する際に上記で紹介しました。次のパラメータ apiExtensionsServer.GenericAPIServer は、以前の APIExtensionServer によって生成された汎用 APIServer です。 KubeAPIServer もこのサーバーに依存するため、直接使用されます。 // cmd/kube-apiserver/app/server.go
func CreateKubeAPIServer ( kubeAPIServerConfig * controlplane.Config , delegateAPIServer genericapiserver.DelegationTarget ) ( * controlplane.Instance , error ) { kubeAPIServer 、エラー: = kubeAPIServerConfig 。完了()。新規( delegateAPIServer )
kubeAPIServerを返す、 nil } 同様に、CreateKubeAPIServer 関数は、kubeAPIServerConfig オブジェクトにデフォルト オブジェクトを直接入力し、インスタンス化します。 // pkg/コントロールプレーン/インスタンス.go // New は指定された構成から新しい Master インスタンスを返します。 // 設定されていない場合、一部の構成フィールドはデフォルト値に設定されます。 // KubeltClientConfig など、特定の構成フィールドを指定する必要があります。 func ( c CompletedConfig ) New ( delegationTarget genericapiserver.DelegationTarget ) ( *インスタンス、エラー) {
// ここでは、crd サーバーと同様に、GenericConfig が呼び出され、kube-apiserver という名前のサーバーがインスタンス化されます。 s 、エラー: = c 。汎用構成。新規( "kube-apiserver" 、 delegationTarget ) //ログルーティングのサポートを構成する cの場合。追加構成。ログサポートを有効にする{ ルート。 {}をログに記録します。インストール( s . Handler . GoRestfulContainer ) }
// ......
m : = &インスタンス{ GenericAPIServer : s 、 クラスター認証情報: c 。追加構成。クラスター認証情報、 }
// レガシーAPIをインストール cの場合。追加構成。 APIリソース構成ソース。バージョンが有効( apiv1 . SchemeGroupVersion ) { legacyRESTStorageProvider : = corerest 。レガシーRESTStorageProvider { ストレージファクトリー: c .追加構成。ストレージファクトリー、 // ...... } // restStorageProvider が有効になっている場合、InstallLegacyAPI はそれ用のレガシー API をインストールします err : = m の場合。 InstallLegacyAPI ( & c , c . GenericConfig . RESTOptionsGetter , LegacyRESTStorageProvider );エラー!=ゼロ{ nilまたはerrを返す } }
// 同じ名前のリソースが複数のグループに存在する場合(例:"deployments.apps""と"deployments.extensions")、 //このリストの順序は、どちらが優先されるかを決定します(例:「展開」)。 //この優先順位はローカルディスカバリーに使用されますが、最終的には `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go`に特定の優先順位があります。
RestStorageProviders : = [] RestStorageProvider { Apiserverinternalrest 。 StorageProvider {}、 AuthenticationRest 。 RestStorageProvider { Authenticator : c 。 genericconfig 。認証。 Authenticator 、 Apiaudiences : c 。 genericconfig 。認証。 apiaudiences }、 AuthorizationRest 。 RestStorageProvider { authorizer : c 。 genericconfig 。許可。 Authorizer 、 Ruleresolver : c 。 genericconfig 。 Ruleresolver }、 autoscalingrest .RestStorageProvider {}、 BatchRest .RestStorageProvider {}、 certificatesRest .RestStorageProvider {}、 ColdinationRest .RestStorageProvider {}、 DiscoveryRest 。 StorageProvider {}、 Networkingrest 。 RestStorageProvider {}、 Noderest 。 RestStorageProvider {}、 policyrest 。 RestStorageProvider {}、 rbacrest 。 RestStorageProvider { authorizer : c 。 genericconfig 。許可。承認者}、 SchedulringRest 。 RestStorageProvider {}、 Storagerest 。 RestStorageProvider {}、 FlowControlrest 。 RestStorageProvider {}、 AppSrest 。 StorageProvider {}、 AdminisionRegistrationRest 。 RestStorageProvider {}、 eventsrest 。 RestStorageProvider { TTL : c 。 extraconfig 。 eventttl }、 } //インターフェイスの新しいバージョンをインストールする:/apis/ err : = mの場合。 InstallApis ( c。Extraconfig。apiresourceconfigsource 、 c。genericconfig。restooptionsgetter 、 restStorageProviders ... ) ;エラー!=ゼロ{ nil 、 errを返します }
// ...
m 、 nilを返します } CRDサーバーと同様に、最初にGenericConfigを呼び出してKube-Apserverという名前のサーバーをインスタンス化し、M.Installlegacyapiを呼び出してLegayapiをインストールします。この方法の主な機能は、コアAPIをルートに登録することです。これは、Apiserverの初期化プロセスで最もコアメソッドの1つです。 // pkg/controlplane/instance.go
// InstallLegacyapiは、APIの古いバージョンをインストールします。これは実際にはCore API:/API/ func ( m * instance ) installlegacyapi ( c * completedconfig 、 reptoptionsettergeneric。restooptionsgetter 、 legacyrestStorageProviderCorerest。LegacyRestStorageProvider )エラー{ //レガシアピの各リソースのRESTSTORAGEを作成する LegacyRestStorage 、 apigroupinfo 、 err : = legacyrestStorageProvider 。 NewLegacyRestStorage ( RESTOPTIONSGETTER )
//ブートストラップコントローラーを初期化します コントロール名: = "bootstrap-controller" coreclient : = corev1client 。 NewForConfigordie ( c。GenericConfig。LoopbackClientConfig ) bootstrapcontroller : = c 。 NewBootStrapController ( LegacyRestStorage 、 CoreClient 、 CoreClient 、 CoreClient。RestClient () ) m 。 GenericApiserver 。 addpoststarthookordie ( Controlnname 、 BootstrapController。PostStarthook ) m 。 GenericApiserver 。 addpreshutdownhookordie ( controllname 、 bootstrapcontroller。preshutdownhook ) //ルーティング情報を登録します err : = mの場合。 GenericApiserver 。 InstallLegacyApigroup ( genericApiserver。defaultlegacyapiprefix 、 & apigroupinfo );エラー!=ゼロ{ FMTを返します。 errorf ( "グループバージョンの登録のエラー:%v" 、 err ) } ゼロを返す } APIをルーティングに登録するという究極の目標は、RESTFUL APIを提供して対応するリソースを操作することです。 APIの登録は、主に2つのステップに分割されます。最初のステップは、APIの各リソースのRESTSTORAGEを初期化して、バックエンドに保存されているデータの変更を操作することです。 2番目のステップは、動詞に従って各リソースに対応するルートを構築することです。 m.installlegacyapiの主な論理は次のとおりです。 - LegacyRestStorageProvider.NewLegacyRestStorageに電話して、レガシアピの各リソースのレストストラージを作成します。 RestStorageの目的は、各リソースのアクセスパスとそのバックエンドストレージ操作に対応することです。
- Bootstrap-Controllerを初期化し、PostStarthookに追加します。 Bootstrap-Controllerは、Apiserverのコントローラーです。その主な機能は、システムに必要ないくつかの名前空間を作成し、Kubernetesサービスを作成し、対応する同期操作を定期的にトリガーすることです。 Apiserverが開始すると、PostStarthookを呼び出すことにより、Bootstrap-Controllerを開始します。
- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づでしょしろうと::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.. :::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::づでしょしろうと::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.. :::::: ::::::::::::最後に、アクションアレイに従って、各操作にハンドラーメソッドを追加し、ルートに登録してから、ウェブサービスへのルートを登録します。 WebServiceは、最終的に、Restful Designパターンに従ってコンテナに登録します。このプロセスは、以前のCRDサーバーとまったく同じです。
次に、m.installapisメソッドは似ており、(/apis)リソースインターフェイスの新しいバージョンの登録とインストールに使用されます。 次に、AggregatorServerサービスを作成します。基本的な方法は、前の2つのサーバーに似ています。 CreateServerchainプロセスのコールチェーンは次のとおりです。 | - > createkubeapiserverconfig | CreateServerchain - | - > CreateapiextensionsConfig | | | - > c 。 genericconfig 。新しい | - > createapiextensionsserver - > apiextensionsconfig 。完了()。新しい- | | | - > s 。 GenericApiserver 。 installapigroup | | | - > c 。 genericconfig 。 new- > regacyrestStorageProvider 。 NewLegacyRestStorage | | | - > CreateKubeapiserver- > KubeapiserverConfig 。完了()。新規- | - > m 。 InstallLegacyapi | | | | - > m 。 InstallApis | | | - > createaggregatorConfig | | | - > c 。 genericconfig 。新しい | | | - > createaggregatorserver- > gregatorconfig 。完了()。 NewWithDelegate- | - > apiservicerest 。 NewRestStorage | | - > s 。 GenericApiserver 。 installapigroup 起動するcreateServerchainを呼び出して各サーバーの初期化を完了した後、Server.preparerunが呼び出され、サービスが開始される前に準備を完了し、最後にforted.runメソッドが呼び出され、安全なHTTPサーバーを起動します。 server.preparerunは、主に健康チェック、サバイバルチェック、Openapiルーティングの登録を完了します。以下は、preat.runプロセスを分析し続けており、prepare.runでは、主にS.NonBlockingRunを呼び出してスタートアップ作業を完了します。 // Vendor/K8s.io/Kube-Aggregator/PKG/APISERVER/APISERVER.GO func ( s predapiaggregator ) run ( spotch < -chan struct {}) error { s 。実行可能。ラン(停止) } ここで実行可能は以前の準備で初期化されており、取得されたものは準備されたGenericApiserverオブジェクトです。 タイプpredapiaggregator struct { * Apiaggregator Runnable Runnable }
func ( s * apiaggregator ) preaderun ()( predapiaggregator 、 error ){ // ... //あなたが得るのは、準備されたGenericApiserverオブジェクトです 準備: = s 。 GenericApiserver 。 preaverun ()
// ...
Returnpiaggregator { apiaggregator : s 、 runnable : preperion }、 nil } したがって、実際のスタートアップメソッドの実行は、reportgenericApiserverの実行方法です。 // vendor/k8s.io/apiserver/pkg/server/generic/apiserver.go
// run Secure HTTPサーバーを起動します。 //ストップが閉じられているか、安全なポートが最初に聴くことができない場合にのみ返されます func ( s preatedgenericapiserver ) run ( spotch < -chan struct {}) error { DelayedStopch : = s 。ライフサイクルセイニル。 aftershutdowndelayduration ShutdownInitided : = s 。ライフサイクルセイニル。シャットダウンが発生しました
// ...
go func (){ 遅延した延期。 signal () Klogを延期します。 V ( 1 )。 infos ( "[Graceful-Termination]シャットダウンイベント" 、 "name" 、 delayedStopch。name ())
< -停止 //開始したら、 /Readyzはすぐに失敗メッセージの返品を開始する必要があります。 //これにより、ロードバランサーは、ShutdownDelayDurationによって定義されたタイムウィンドウを提供し、 /Readyzが利用できない場合、サーバーへのトラフィックの送信を停止します。 ShutdownInitiatedCh 。 signal () クログ。 V ( 1 )。 infos ( "[Graceful-Termination]シャットダウンイベント" 、 "name" 、 shutdowninitidech。name ( ) ))
時間。睡眠( s。ShutdownDelayDuration ) }()
//ソケットを閉じます drainedch : = s 。ライフサイクルセイニル。 Inflightrequestsdrained Stophttpserverch : = delayedStopch 。 signaled () ShutdownTimeOut : = s 。 ShutdownTimeOut s 。 shutdownsendretryafter { stophttpserverch = drainedch 。 signaled () shutdowntimeout = 2 *時間。 2番 クログ。 V ( 1 )。 infos ( "[[Graceful-Termination] HTTPサーバーシャットダウンタイムアウトを使用した" 、 "ShutdownTimeout" 、 ShutdownTimeout ) } // nonblockingRunを呼び出して、スタートアッププロセスを完了します StoppedCh 、 ristenStoppedch 、 err : = s 。 nonblockingrun ( stophttpserverch 、 shutdowntimeout )
//次のことは、出口信号を受信した後に行われた最終作業です httpserStoppedListeningch : = s 。ライフサイクルセイニル。 httpserStoppedListening go func (){ < -sienSorstoppedch httpserverstoppedlisteningch 。 signal () クログ。 V ( 1 )。 infos ( "[Graceful-Termination]シャットダウンイベント" 、 "name" 、 httpserverstoppedlistening。name ())) }()
// ... } サービスを開始する本当のコアはS.NonBlockingRunメソッドであり、その主な実装コードは次のとおりです。 // /vendor/k8s.io/apiextensions-apiserver/pkg/server/genericapiserver.go
func ( s reprentgenericapiserver ) nonblockingrun ( spotch < -chan struct {}、 shutdowntimeout time 。持続時間)( <- chan struct {}、 <- chan struct {}、 error ){
auditStopch : = make ( chan struct {})
//監査ログを開始するかどうか s 。 auditbackend != nil { err : = s 。監査バックエンド。 run ( auditStopch );エラー!=ゼロ{ nil 、 nil 、 fmtを返します。 errorf ( "監査バックエンドの実行に失敗した:%v" 、 err ) } }
//実際のHTTPSサーバーを起動します internalStopch : = make ( chan struct {}) var stoppedch < -chan struct {} var sienderstoppedch < -chan struct {} s 。 SecureServingInfo != nil && s 。ハンドラー!= nil { var errエラー StoppedCh 、 ristenStoppedch 、 err = s 。 SecureServinginfo 。 servewithlistenerstopped ( s。handler 、 shutdowntimeout 、 internalStopch ) /// }
//その後、一部の処理も受信されます。 go func (){ < -停止 Close ( internalStopch ) stoppedch != nil { < -停止した } s 。 HandlerChainWaitGroup 。待って() 閉じる( auditStopch ) }() // PostStarthooksを実行します s 。 runpoststarthooks (停止) // systemdにready信号を送信します _ 、 err := systemd 。 sdnotify ( true 、 "Ready = 1 \ n" );エラー!=ゼロ{ クログ。 errorf ( "SystemDデーモンを送信できませんStart Startメッセージ:%V \ n" 、 err ) }
Return Stoppedch 、リスニングストップ、 nil } s.nonblockingRunの主なロジックは次のとおりです。 - 監査ログサービスを開始するかどうかを決定します。
- s.secureservinginfo.serveを呼び出して、HTTPSサーバーを構成して起動します。
- PostStarthooksを実行します。
- systemdに準備ができた信号を送信します。
上記は、Apiserverの初期化と起動プロセスの分析です。これは単なる全体的なプロセスであり、上記のAPIリソースRestStorageなど、分析する必要があるなど、詳細な詳細がたくさんあります。 |