diff --git a/cmd/kubelet/app/options/options.go b/cmd/kubelet/app/options/options.go index 66b054100a..69139621fd 100644 --- a/cmd/kubelet/app/options/options.go +++ b/cmd/kubelet/app/options/options.go @@ -194,6 +194,8 @@ type KubeletFlags struct { // This flag, if set, instructs the kubelet to keep volumes from terminated pods mounted to the node. // This can be useful for debugging volume related issues. KeepTerminatedPodVolumes bool + // EnableCAdvisorJSONEndpoints enables some cAdvisor endpoints that will be removed in future versions + EnableCAdvisorJSONEndpoints bool } // NewKubeletFlags will create a new KubeletFlags with default values @@ -223,7 +225,8 @@ func NewKubeletFlags() *KubeletFlags { RegisterNode: true, SeccompProfileRoot: filepath.Join(defaultRootDir, "seccomp"), // prior to the introduction of this flag, there was a hardcoded cap of 50 images - NodeStatusMaxImages: 50, + NodeStatusMaxImages: 50, + EnableCAdvisorJSONEndpoints: true, } } @@ -424,6 +427,8 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) { fs.MarkDeprecated("non-masquerade-cidr", "will be removed in a future version") fs.BoolVar(&f.KeepTerminatedPodVolumes, "keep-terminated-pod-volumes", f.KeepTerminatedPodVolumes, "Keep terminated pod volumes mounted to the node after the pod terminates. Can be useful for debugging volume related issues.") fs.MarkDeprecated("keep-terminated-pod-volumes", "will be removed in a future version") + fs.BoolVar(&f.EnableCAdvisorJSONEndpoints, "enable-cadvisor-json-endpoints", f.EnableCAdvisorJSONEndpoints, "Enable cAdvisor json /spec and /stats/* endpoints.") + fs.MarkDeprecated("enable-cadvisor-json-apis", "will be removed in a future version") } diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 29e2560bac..139a8eacbb 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -1079,13 +1079,13 @@ func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencie } klog.Info("Started kubelet as runonce") } else { - startKubelet(k, podCfg, &kubeServer.KubeletConfiguration, kubeDeps, kubeServer.EnableServer) + startKubelet(k, podCfg, &kubeServer.KubeletConfiguration, kubeDeps, kubeServer.EnableCAdvisorJSONEndpoints, kubeServer.EnableServer) klog.Info("Started kubelet") } return nil } -func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableServer bool) { +func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubeletconfiginternal.KubeletConfiguration, kubeDeps *kubelet.Dependencies, enableCAdvisorJSONEndpoints, enableServer bool) { // start the kubelet go wait.Until(func() { k.Run(podCfg.Updates()) @@ -1093,11 +1093,11 @@ func startKubelet(k kubelet.Bootstrap, podCfg *config.PodConfig, kubeCfg *kubele // start the kubelet server if enableServer { - go k.ListenAndServe(net.ParseIP(kubeCfg.Address), uint(kubeCfg.Port), kubeDeps.TLSOptions, kubeDeps.Auth, kubeCfg.EnableDebuggingHandlers, kubeCfg.EnableContentionProfiling) + go k.ListenAndServe(net.ParseIP(kubeCfg.Address), uint(kubeCfg.Port), kubeDeps.TLSOptions, kubeDeps.Auth, enableCAdvisorJSONEndpoints, kubeCfg.EnableDebuggingHandlers, kubeCfg.EnableContentionProfiling) } if kubeCfg.ReadOnlyPort > 0 { - go k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort)) + go k.ListenAndServeReadOnly(net.ParseIP(kubeCfg.Address), uint(kubeCfg.ReadOnlyPort), enableCAdvisorJSONEndpoints) } if utilfeature.DefaultFeatureGate.Enabled(features.KubeletPodResources) { go k.ListenAndServePodResources() diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index ce0fc0446c..9d009ac35e 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -193,8 +193,8 @@ type Bootstrap interface { GetConfiguration() kubeletconfiginternal.KubeletConfiguration BirthCry() StartGarbageCollection() - ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableDebuggingHandlers, enableContentionProfiling bool) - ListenAndServeReadOnly(address net.IP, port uint) + ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling bool) + ListenAndServeReadOnly(address net.IP, port uint, enableCAdvisorJSONEndpoints bool) ListenAndServePodResources() Run(<-chan kubetypes.PodUpdate) RunOnce(<-chan kubetypes.PodUpdate) ([]RunPodResult, error) @@ -2202,13 +2202,13 @@ func (kl *Kubelet) ResyncInterval() time.Duration { } // ListenAndServe runs the kubelet HTTP server. -func (kl *Kubelet) ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableDebuggingHandlers, enableContentionProfiling bool) { - server.ListenAndServeKubeletServer(kl, kl.resourceAnalyzer, address, port, tlsOptions, auth, enableDebuggingHandlers, enableContentionProfiling, kl.redirectContainerStreaming, kl.criHandler) +func (kl *Kubelet) ListenAndServe(address net.IP, port uint, tlsOptions *server.TLSOptions, auth server.AuthInterface, enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling bool) { + server.ListenAndServeKubeletServer(kl, kl.resourceAnalyzer, address, port, tlsOptions, auth, enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling, kl.redirectContainerStreaming, kl.criHandler) } // ListenAndServeReadOnly runs the kubelet HTTP server in read-only mode. -func (kl *Kubelet) ListenAndServeReadOnly(address net.IP, port uint) { - server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer, address, port) +func (kl *Kubelet) ListenAndServeReadOnly(address net.IP, port uint, enableCAdvisorJSONEndpoints bool) { + server.ListenAndServeKubeletReadOnlyServer(kl, kl.resourceAnalyzer, address, port, enableCAdvisorJSONEndpoints) } // ListenAndServePodResources runs the kubelet podresources grpc service diff --git a/pkg/kubelet/server/server.go b/pkg/kubelet/server/server.go index 576f6712b4..c1f1975fe4 100644 --- a/pkg/kubelet/server/server.go +++ b/pkg/kubelet/server/server.go @@ -136,12 +136,13 @@ func ListenAndServeKubeletServer( port uint, tlsOptions *TLSOptions, auth AuthInterface, + enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling, redirectContainerStreaming bool, criHandler http.Handler) { klog.Infof("Starting to listen on %s:%d", address, port) - handler := NewServer(host, resourceAnalyzer, auth, enableDebuggingHandlers, enableContentionProfiling, redirectContainerStreaming, criHandler) + handler := NewServer(host, resourceAnalyzer, auth, enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling, redirectContainerStreaming, criHandler) s := &http.Server{ Addr: net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)), Handler: &handler, @@ -159,9 +160,9 @@ func ListenAndServeKubeletServer( } // ListenAndServeKubeletReadOnlyServer initializes a server to respond to HTTP network requests on the Kubelet. -func ListenAndServeKubeletReadOnlyServer(host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, address net.IP, port uint) { +func ListenAndServeKubeletReadOnlyServer(host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, address net.IP, port uint, enableCAdvisorJSONEndpoints bool) { klog.V(1).Infof("Starting to listen read-only on %s:%d", address, port) - s := NewServer(host, resourceAnalyzer, nil, false, false, false, nil) + s := NewServer(host, resourceAnalyzer, nil, enableCAdvisorJSONEndpoints, false, false, false, nil) server := &http.Server{ Addr: net.JoinHostPort(address.String(), strconv.FormatUint(uint64(port), 10)), @@ -212,6 +213,7 @@ func NewServer( host HostInterface, resourceAnalyzer stats.ResourceAnalyzer, auth AuthInterface, + enableCAdvisorJSONEndpoints, enableDebuggingHandlers, enableContentionProfiling, redirectContainerStreaming bool, @@ -226,7 +228,7 @@ func NewServer( if auth != nil { server.InstallAuthFilter() } - server.InstallDefaultHandlers() + server.InstallDefaultHandlers(enableCAdvisorJSONEndpoints) if enableDebuggingHandlers { server.InstallDebuggingHandlers(criHandler) if enableContentionProfiling { @@ -278,7 +280,7 @@ func (s *Server) InstallAuthFilter() { // InstallDefaultHandlers registers the default set of supported HTTP request // patterns with the restful Container. -func (s *Server) InstallDefaultHandlers() { +func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) { healthz.InstallHandler(s.restfulCont, healthz.PingHealthz, healthz.LogHealthz, @@ -293,7 +295,7 @@ func (s *Server) InstallDefaultHandlers() { Operation("getPods")) s.restfulCont.Add(ws) - s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer)) + s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer, enableCAdvisorJSONEndpoints)) s.restfulCont.Handle(metricsPath, prometheus.Handler()) // cAdvisor metrics are exposed under the secured handler as well @@ -328,15 +330,17 @@ func (s *Server) InstallDefaultHandlers() { promhttp.HandlerFor(p, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}), ) - ws = new(restful.WebService) - ws. - Path(specPath). - Produces(restful.MIME_JSON) - ws.Route(ws.GET(""). - To(s.getSpec). - Operation("getSpec"). - Writes(cadvisorapi.MachineInfo{})) - s.restfulCont.Add(ws) + if enableCAdvisorJSONEndpoints { + ws := new(restful.WebService) + ws. + Path(specPath). + Produces(restful.MIME_JSON) + ws.Route(ws.GET(""). + To(s.getSpec). + Operation("getSpec"). + Writes(cadvisorapi.MachineInfo{})) + s.restfulCont.Add(ws) + } } const pprofBasePath = "/debug/pprof/" diff --git a/pkg/kubelet/server/server_test.go b/pkg/kubelet/server/server_test.go index 7627b0bcc1..4761d21afb 100644 --- a/pkg/kubelet/server/server_test.go +++ b/pkg/kubelet/server/server_test.go @@ -338,6 +338,7 @@ func newServerTestWithDebug(enableDebugging, redirectContainerStreaming bool, st fw.fakeKubelet, stats.NewResourceAnalyzer(fw.fakeKubelet, time.Minute), fw.fakeAuth, + true, enableDebugging, false, redirectContainerStreaming, diff --git a/pkg/kubelet/server/stats/handler.go b/pkg/kubelet/server/stats/handler.go index a5b9b4e5d8..c6dd5a0c56 100644 --- a/pkg/kubelet/server/stats/handler.go +++ b/pkg/kubelet/server/stats/handler.go @@ -108,22 +108,29 @@ type handler struct { } // CreateHandlers creates the REST handlers for the stats. -func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider) *restful.WebService { +func CreateHandlers(rootPath string, provider Provider, summaryProvider SummaryProvider, enableCAdvisorJSONEndpoints bool) *restful.WebService { h := &handler{provider, summaryProvider} ws := &restful.WebService{} ws.Path(rootPath). Produces(restful.MIME_JSON) - endpoints := []struct { + type endpoint struct { path string handler restful.RouteFunction - }{ - {"", h.handleStats}, + } + + endpoints := []endpoint{ {"/summary", h.handleSummary}, - {"/container", h.handleSystemContainer}, - {"/{podName}/{containerName}", h.handlePodContainer}, - {"/{namespace}/{podName}/{uid}/{containerName}", h.handlePodContainer}, + } + + if enableCAdvisorJSONEndpoints { + endpoints = append(endpoints, + endpoint{"", h.handleStats}, + endpoint{"/container", h.handleSystemContainer}, + endpoint{"/{podName}/{containerName}", h.handlePodContainer}, + endpoint{"/{namespace}/{podName}/{uid}/{containerName}", h.handlePodContainer}, + ) } for _, e := range endpoints {