k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-apiserver/app/server.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package app does all of the work necessary to create a Kubernetes
    18  // APIServer by binding together the API, master and APIServer infrastructure.
    19  // It can be configured and called directly or via the hyperkube framework.
    20  package app
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  	"net/url"
    26  	"os"
    27  
    28  	"github.com/spf13/cobra"
    29  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    30  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    31  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    32  	"k8s.io/apiserver/pkg/admission"
    33  	genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
    34  	genericapiserver "k8s.io/apiserver/pkg/server"
    35  	"k8s.io/apiserver/pkg/server/egressselector"
    36  	serverstorage "k8s.io/apiserver/pkg/server/storage"
    37  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    38  	"k8s.io/apiserver/pkg/util/notfoundhandler"
    39  	"k8s.io/apiserver/pkg/util/webhook"
    40  	clientgoinformers "k8s.io/client-go/informers"
    41  	"k8s.io/client-go/rest"
    42  	cliflag "k8s.io/component-base/cli/flag"
    43  	"k8s.io/component-base/cli/globalflag"
    44  	"k8s.io/component-base/logs"
    45  	logsapi "k8s.io/component-base/logs/api/v1"
    46  	_ "k8s.io/component-base/metrics/prometheus/workqueue"
    47  	"k8s.io/component-base/term"
    48  	"k8s.io/component-base/version"
    49  	"k8s.io/component-base/version/verflag"
    50  	"k8s.io/klog/v2"
    51  	aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
    52  	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
    53  	"k8s.io/kubernetes/pkg/capabilities"
    54  	"k8s.io/kubernetes/pkg/controlplane"
    55  	controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver"
    56  	"k8s.io/kubernetes/pkg/controlplane/reconcilers"
    57  	kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
    58  )
    59  
    60  func init() {
    61  	utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
    62  }
    63  
    64  // NewAPIServerCommand creates a *cobra.Command object with default parameters
    65  func NewAPIServerCommand() *cobra.Command {
    66  	s := options.NewServerRunOptions()
    67  	cmd := &cobra.Command{
    68  		Use: "kube-apiserver",
    69  		Long: `The Kubernetes API server validates and configures data
    70  for the api objects which include pods, services, replicationcontrollers, and
    71  others. The API Server services REST operations and provides the frontend to the
    72  cluster's shared state through which all other components interact.`,
    73  
    74  		// stop printing usage when the command errors
    75  		SilenceUsage: true,
    76  		PersistentPreRunE: func(*cobra.Command, []string) error {
    77  			// silence client-go warnings.
    78  			// kube-apiserver loopback clients should not log self-issued warnings.
    79  			rest.SetDefaultWarningHandler(rest.NoWarnings{})
    80  			return nil
    81  		},
    82  		RunE: func(cmd *cobra.Command, args []string) error {
    83  			verflag.PrintAndExitIfRequested()
    84  			fs := cmd.Flags()
    85  
    86  			// Activate logging as soon as possible, after that
    87  			// show flags with the final logging configuration.
    88  			if err := logsapi.ValidateAndApply(s.Logs, utilfeature.DefaultFeatureGate); err != nil {
    89  				return err
    90  			}
    91  			cliflag.PrintFlags(fs)
    92  
    93  			// set default options
    94  			completedOptions, err := s.Complete()
    95  			if err != nil {
    96  				return err
    97  			}
    98  
    99  			// validate options
   100  			if errs := completedOptions.Validate(); len(errs) != 0 {
   101  				return utilerrors.NewAggregate(errs)
   102  			}
   103  			// add feature enablement metrics
   104  			utilfeature.DefaultMutableFeatureGate.AddMetrics()
   105  			return Run(cmd.Context(), completedOptions)
   106  		},
   107  		Args: func(cmd *cobra.Command, args []string) error {
   108  			for _, arg := range args {
   109  				if len(arg) > 0 {
   110  					return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
   111  				}
   112  			}
   113  			return nil
   114  		},
   115  	}
   116  	cmd.SetContext(genericapiserver.SetupSignalContext())
   117  
   118  	fs := cmd.Flags()
   119  	namedFlagSets := s.Flags()
   120  	verflag.AddFlags(namedFlagSets.FlagSet("global"))
   121  	globalflag.AddGlobalFlags(namedFlagSets.FlagSet("global"), cmd.Name(), logs.SkipLoggingConfigurationFlags())
   122  	options.AddCustomGlobalFlags(namedFlagSets.FlagSet("generic"))
   123  	for _, f := range namedFlagSets.FlagSets {
   124  		fs.AddFlagSet(f)
   125  	}
   126  
   127  	cols, _, _ := term.TerminalSize(cmd.OutOrStdout())
   128  	cliflag.SetUsageAndHelpFunc(cmd, namedFlagSets, cols)
   129  
   130  	return cmd
   131  }
   132  
   133  // Run runs the specified APIServer.  This should never exit.
   134  func Run(ctx context.Context, opts options.CompletedOptions) error {
   135  	// To help debugging, immediately log version
   136  	klog.Infof("Version: %+v", version.Get())
   137  
   138  	klog.InfoS("Golang settings", "GOGC", os.Getenv("GOGC"), "GOMAXPROCS", os.Getenv("GOMAXPROCS"), "GOTRACEBACK", os.Getenv("GOTRACEBACK"))
   139  
   140  	config, err := NewConfig(opts)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	completed, err := config.Complete()
   145  	if err != nil {
   146  		return err
   147  	}
   148  	server, err := CreateServerChain(completed)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	prepared, err := server.PrepareRun()
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	return prepared.Run(ctx)
   159  }
   160  
   161  // CreateServerChain creates the apiservers connected via delegation.
   162  func CreateServerChain(config CompletedConfig) (*aggregatorapiserver.APIAggregator, error) {
   163  	notFoundHandler := notfoundhandler.New(config.KubeAPIs.ControlPlane.Generic.Serializer, genericapifilters.NoMuxAndDiscoveryIncompleteKey)
   164  	apiExtensionsServer, err := config.ApiExtensions.New(genericapiserver.NewEmptyDelegateWithCustomHandler(notFoundHandler))
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  	crdAPIEnabled := config.ApiExtensions.GenericConfig.MergedResourceConfig.ResourceEnabled(apiextensionsv1.SchemeGroupVersion.WithResource("customresourcedefinitions"))
   169  
   170  	kubeAPIServer, err := config.KubeAPIs.New(apiExtensionsServer.GenericAPIServer)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	// aggregator comes last in the chain
   176  	aggregatorServer, err := controlplaneapiserver.CreateAggregatorServer(config.Aggregator, kubeAPIServer.ControlPlane.GenericAPIServer, apiExtensionsServer.Informers.Apiextensions().V1().CustomResourceDefinitions(), crdAPIEnabled, apiVersionPriorities)
   177  	if err != nil {
   178  		// we don't need special handling for innerStopCh because the aggregator server doesn't create any go routines
   179  		return nil, err
   180  	}
   181  
   182  	return aggregatorServer, nil
   183  }
   184  
   185  // CreateKubeAPIServerConfig creates all the resources for running the API server, but runs none of them
   186  func CreateKubeAPIServerConfig(
   187  	opts options.CompletedOptions,
   188  	genericConfig *genericapiserver.Config,
   189  	versionedInformers clientgoinformers.SharedInformerFactory,
   190  	storageFactory *serverstorage.DefaultStorageFactory,
   191  ) (
   192  	*controlplane.Config,
   193  	aggregatorapiserver.ServiceResolver,
   194  	[]admission.PluginInitializer,
   195  	error,
   196  ) {
   197  	// global stuff
   198  	capabilities.Setup(opts.AllowPrivileged, opts.MaxConnectionBytesPerSec)
   199  
   200  	// additional admission initializers
   201  	kubeAdmissionConfig := &kubeapiserveradmission.Config{
   202  		CloudConfigFile: opts.CloudProvider.CloudConfigFile,
   203  	}
   204  	kubeInitializers, err := kubeAdmissionConfig.New()
   205  	if err != nil {
   206  		return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %w", err)
   207  	}
   208  
   209  	serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
   210  	controlplaneConfig, admissionInitializers, err := controlplaneapiserver.CreateConfig(opts.CompletedOptions, genericConfig, versionedInformers, storageFactory, serviceResolver, kubeInitializers)
   211  	if err != nil {
   212  		return nil, nil, nil, err
   213  	}
   214  
   215  	config := &controlplane.Config{
   216  		ControlPlane: *controlplaneConfig,
   217  		Extra: controlplane.Extra{
   218  			KubeletClientConfig: opts.KubeletConfig,
   219  
   220  			ServiceIPRange:          opts.PrimaryServiceClusterIPRange,
   221  			APIServerServiceIP:      opts.APIServerServiceIP,
   222  			SecondaryServiceIPRange: opts.SecondaryServiceClusterIPRange,
   223  
   224  			APIServerServicePort: 443,
   225  
   226  			ServiceNodePortRange:      opts.ServiceNodePortRange,
   227  			KubernetesServiceNodePort: opts.KubernetesServiceNodePort,
   228  
   229  			EndpointReconcilerType: reconcilers.Type(opts.EndpointReconcilerType),
   230  			MasterCount:            opts.MasterCount,
   231  		},
   232  	}
   233  
   234  	if config.ControlPlane.Generic.EgressSelector != nil {
   235  		// Use the config.ControlPlane.Generic.EgressSelector lookup to find the dialer to connect to the kubelet
   236  		config.Extra.KubeletClientConfig.Lookup = config.ControlPlane.Generic.EgressSelector.Lookup
   237  
   238  		// Use the config.ControlPlane.Generic.EgressSelector lookup as the transport used by the "proxy" subresources.
   239  		networkContext := egressselector.Cluster.AsNetworkContext()
   240  		dialer, err := config.ControlPlane.Generic.EgressSelector.Lookup(networkContext)
   241  		if err != nil {
   242  			return nil, nil, nil, err
   243  		}
   244  		c := config.ControlPlane.Extra.ProxyTransport.Clone()
   245  		c.DialContext = dialer
   246  		config.ControlPlane.ProxyTransport = c
   247  	}
   248  
   249  	return config, serviceResolver, admissionInitializers, nil
   250  }
   251  
   252  var testServiceResolver webhook.ServiceResolver
   253  
   254  // SetServiceResolverForTests allows the service resolver to be overridden during tests.
   255  // Tests using this function must run serially as this function is not safe to call concurrently with server start.
   256  func SetServiceResolverForTests(resolver webhook.ServiceResolver) func() {
   257  	if testServiceResolver != nil {
   258  		panic("test service resolver is set: tests are either running concurrently or clean up was skipped")
   259  	}
   260  
   261  	testServiceResolver = resolver
   262  
   263  	return func() {
   264  		testServiceResolver = nil
   265  	}
   266  }
   267  
   268  func buildServiceResolver(enabledAggregatorRouting bool, hostname string, informer clientgoinformers.SharedInformerFactory) webhook.ServiceResolver {
   269  	if testServiceResolver != nil {
   270  		return testServiceResolver
   271  	}
   272  
   273  	var serviceResolver webhook.ServiceResolver
   274  	if enabledAggregatorRouting {
   275  		serviceResolver = aggregatorapiserver.NewEndpointServiceResolver(
   276  			informer.Core().V1().Services().Lister(),
   277  			informer.Core().V1().Endpoints().Lister(),
   278  		)
   279  	} else {
   280  		serviceResolver = aggregatorapiserver.NewClusterIPServiceResolver(
   281  			informer.Core().V1().Services().Lister(),
   282  		)
   283  	}
   284  
   285  	// resolve kubernetes.default.svc locally
   286  	if localHost, err := url.Parse(hostname); err == nil {
   287  		serviceResolver = aggregatorapiserver.NewLoopbackServiceResolver(serviceResolver, localHost)
   288  	}
   289  	return serviceResolver
   290  }