github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/metrics/heapster.go (about) 1 // Copyright 2014 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:generate ./hooks/run_extpoints.sh 16 17 package main 18 19 import ( 20 "crypto/tls" 21 "flag" 22 "fmt" 23 "net/http" 24 "net/url" 25 "os" 26 "runtime" 27 "strings" 28 "time" 29 30 "github.com/golang/glog" 31 "github.com/prometheus/client_golang/prometheus" 32 "k8s.io/heapster/common/flags" 33 kube_config "k8s.io/heapster/common/kubernetes" 34 "k8s.io/heapster/metrics/core" 35 "k8s.io/heapster/metrics/manager" 36 "k8s.io/heapster/metrics/processors" 37 "k8s.io/heapster/metrics/sinks" 38 "k8s.io/heapster/metrics/sources" 39 "k8s.io/heapster/version" 40 kube_api "k8s.io/kubernetes/pkg/api" 41 "k8s.io/kubernetes/pkg/client/cache" 42 kube_client "k8s.io/kubernetes/pkg/client/unversioned" 43 "k8s.io/kubernetes/pkg/fields" 44 ) 45 46 var ( 47 argMetricResolution = flag.Duration("metric_resolution", 60*time.Second, "The resolution at which heapster will retain metrics.") 48 argPort = flag.Int("port", 8082, "port to listen to") 49 argIp = flag.String("listen_ip", "", "IP to listen on, defaults to all IPs") 50 argMaxProcs = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores)") 51 argTLSCertFile = flag.String("tls_cert", "", "file containing TLS certificate") 52 argTLSKeyFile = flag.String("tls_key", "", "file containing TLS key") 53 argTLSClientCAFile = flag.String("tls_client_ca", "", "file containing TLS client CA for client cert validation") 54 argAllowedUsers = flag.String("allowed_users", "", "comma-separated list of allowed users") 55 argSources flags.Uris 56 argSinks flags.Uris 57 ) 58 59 func main() { 60 defer glog.Flush() 61 flag.Var(&argSources, "source", "source(s) to watch") 62 flag.Var(&argSinks, "sink", "external sink(s) that receive data") 63 flag.Parse() 64 setMaxProcs() 65 glog.Infof(strings.Join(os.Args, " ")) 66 glog.Infof("Heapster version %v", version.HeapsterVersion) 67 if err := validateFlags(); err != nil { 68 glog.Fatal(err) 69 } 70 71 // sources 72 if len(argSources) != 1 { 73 glog.Fatal("Wrong number of sources specified") 74 } 75 sourceFactory := sources.NewSourceFactory() 76 sourceProvider, err := sourceFactory.BuildAll(argSources) 77 if err != nil { 78 glog.Fatalf("Failed to create source provide: %v", err) 79 } 80 sourceManager, err := sources.NewSourceManager(sourceProvider, sources.DefaultMetricsScrapeTimeout) 81 if err != nil { 82 glog.Fatalf("Failed to create source manager: %v", err) 83 } 84 85 // sinks 86 sinksFactory := sinks.NewSinkFactory() 87 metricSink, sinkList := sinksFactory.BuildAll(argSinks) 88 if metricSink == nil { 89 glog.Fatal("Failed to create metric sink") 90 } 91 for _, sink := range sinkList { 92 glog.Infof("Starting with %s", sink.Name()) 93 } 94 sinkManager, err := sinks.NewDataSinkManager(sinkList, sinks.DefaultSinkExportDataTimeout, sinks.DefaultSinkStopTimeout) 95 if err != nil { 96 glog.Fatalf("Failed to created sink manager: %v", err) 97 } 98 99 // data processors 100 metricsToAggregate := []string{ 101 core.MetricCpuUsageRate.Name, 102 core.MetricMemoryUsage.Name, 103 core.MetricCpuRequest.Name, 104 core.MetricCpuLimit.Name, 105 core.MetricMemoryRequest.Name, 106 core.MetricMemoryLimit.Name, 107 } 108 109 metricsToAggregateForNode := []string{ 110 core.MetricCpuRequest.Name, 111 core.MetricCpuLimit.Name, 112 core.MetricMemoryRequest.Name, 113 core.MetricMemoryLimit.Name, 114 } 115 116 dataProcessors := []core.DataProcessor{ 117 // Convert cumulaties to rate 118 processors.NewRateCalculator(core.RateMetricsMapping), 119 } 120 121 kubernetesUrl, err := getKubernetesAddress(argSources) 122 if err != nil { 123 glog.Fatalf("Failed to get kubernetes address: %v", err) 124 } 125 podLister, err := getPodLister(kubernetesUrl) 126 if err != nil { 127 glog.Fatalf("Failed to create podLister: %v", err) 128 } 129 130 podBasedEnricher, err := processors.NewPodBasedEnricher(podLister) 131 if err != nil { 132 glog.Fatalf("Failed to create PodBasedEnricher: %v", err) 133 } 134 dataProcessors = append(dataProcessors, podBasedEnricher) 135 136 namespaceBasedEnricher, err := processors.NewNamespaceBasedEnricher(kubernetesUrl) 137 if err != nil { 138 glog.Fatalf("Failed to create NamespaceBasedEnricher: %v", err) 139 } 140 dataProcessors = append(dataProcessors, namespaceBasedEnricher) 141 142 // then aggregators 143 dataProcessors = append(dataProcessors, 144 processors.NewPodAggregator(), 145 &processors.NamespaceAggregator{ 146 MetricsToAggregate: metricsToAggregate, 147 }, 148 &processors.NodeAggregator{ 149 MetricsToAggregate: metricsToAggregateForNode, 150 }, 151 &processors.ClusterAggregator{ 152 MetricsToAggregate: metricsToAggregate, 153 }) 154 155 nodeAutoscalingEnricher, err := processors.NewNodeAutoscalingEnricher(kubernetesUrl) 156 if err != nil { 157 glog.Fatalf("Failed to create NodeAutoscalingEnricher: %v", err) 158 } 159 dataProcessors = append(dataProcessors, nodeAutoscalingEnricher) 160 161 // main manager 162 manager, err := manager.NewManager(sourceManager, dataProcessors, sinkManager, *argMetricResolution, 163 manager.DefaultScrapeOffset, manager.DefaultMaxParallelism) 164 if err != nil { 165 glog.Fatalf("Failed to create main manager: %v", err) 166 } 167 manager.Start() 168 169 handler := setupHandlers(metricSink, podLister) 170 addr := fmt.Sprintf("%s:%d", *argIp, *argPort) 171 glog.Infof("Starting heapster on port %d", *argPort) 172 173 mux := http.NewServeMux() 174 promHandler := prometheus.Handler() 175 if len(*argTLSCertFile) > 0 && len(*argTLSKeyFile) > 0 { 176 if len(*argTLSClientCAFile) > 0 { 177 authPprofHandler, err := newAuthHandler(handler) 178 if err != nil { 179 glog.Fatalf("Failed to create authorized pprof handler: %v", err) 180 } 181 handler = authPprofHandler 182 183 authPromHandler, err := newAuthHandler(promHandler) 184 if err != nil { 185 glog.Fatalf("Failed to create authorized prometheus handler: %v", err) 186 } 187 promHandler = authPromHandler 188 } 189 mux.Handle("/", handler) 190 mux.Handle("/metrics", promHandler) 191 192 // If allowed users is set, then we need to enable Client Authentication 193 if len(*argAllowedUsers) > 0 { 194 server := &http.Server{ 195 Addr: addr, 196 Handler: mux, 197 TLSConfig: &tls.Config{ClientAuth: tls.RequestClientCert}, 198 } 199 glog.Fatal(server.ListenAndServeTLS(*argTLSCertFile, *argTLSKeyFile)) 200 } else { 201 glog.Fatal(http.ListenAndServeTLS(addr, *argTLSCertFile, *argTLSKeyFile, mux)) 202 } 203 204 } else { 205 mux.Handle("/", handler) 206 mux.Handle("/metrics", promHandler) 207 glog.Fatal(http.ListenAndServe(addr, mux)) 208 } 209 } 210 211 // Gets the address of the kubernetes source from the list of source URIs. 212 // Possible kubernetes sources are: 'kubernetes' and 'kubernetes.summary_api' 213 func getKubernetesAddress(args flags.Uris) (*url.URL, error) { 214 for _, uri := range args { 215 if strings.SplitN(uri.Key, ".", 2)[0] == "kubernetes" { 216 return &uri.Val, nil 217 } 218 } 219 return nil, fmt.Errorf("No kubernetes source found.") 220 } 221 222 func getPodLister(url *url.URL) (*cache.StoreToPodLister, error) { 223 kubeConfig, err := kube_config.GetKubeClientConfig(url) 224 if err != nil { 225 return nil, err 226 } 227 kubeClient := kube_client.NewOrDie(kubeConfig) 228 229 lw := cache.NewListWatchFromClient(kubeClient, "pods", kube_api.NamespaceAll, fields.Everything()) 230 store := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) 231 podLister := &cache.StoreToPodLister{Indexer: store} 232 reflector := cache.NewReflector(lw, &kube_api.Pod{}, store, time.Hour) 233 reflector.Run() 234 235 return podLister, nil 236 } 237 238 func validateFlags() error { 239 if *argMetricResolution < 5*time.Second { 240 return fmt.Errorf("metric resolution needs to be greater than 5 seconds - %d", *argMetricResolution) 241 } 242 if (len(*argTLSCertFile) > 0 && len(*argTLSKeyFile) == 0) || (len(*argTLSCertFile) == 0 && len(*argTLSKeyFile) > 0) { 243 return fmt.Errorf("both TLS certificate & key are required to enable TLS serving") 244 } 245 if len(*argTLSClientCAFile) > 0 && len(*argTLSCertFile) == 0 { 246 return fmt.Errorf("client cert authentication requires TLS certificate & key") 247 } 248 return nil 249 } 250 251 func setMaxProcs() { 252 // Allow as many threads as we have cores unless the user specified a value. 253 var numProcs int 254 if *argMaxProcs < 1 { 255 numProcs = runtime.NumCPU() 256 } else { 257 numProcs = *argMaxProcs 258 } 259 runtime.GOMAXPROCS(numProcs) 260 261 // Check if the setting was successful. 262 actualNumProcs := runtime.GOMAXPROCS(0) 263 if actualNumProcs != numProcs { 264 glog.Warningf("Specified max procs of %d but using %d", numProcs, actualNumProcs) 265 } 266 }