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 }