func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() verflag.PrintAndExitIfRequested() verifyMinionFlags() if len(etcdServerList) == 0 { glog.Fatalf("-etcd_servers flag is required.") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) cloud := initCloudProvider(*cloudProvider, *cloudConfigFile) podInfoGetter := &client.HTTPPodInfoGetter{ Client: http.DefaultClient, Port: *minionPort, } client, err := client.New(net.JoinHostPort(*address, strconv.Itoa(int(*port))), nil) if err != nil { glog.Fatalf("Invalid server address: %v", err) } m := master.New(&master.Config{ Client: client, Cloud: cloud, EtcdServers: etcdServerList, HealthCheckMinions: *healthCheckMinions, Minions: machineList, MinionCacheTTL: *minionCacheTTL, MinionRegexp: *minionRegexp, PodInfoGetter: podInfoGetter, }) storage, codec := m.API_v1beta1() handler := apiserver.Handle(storage, codec, *apiPrefix) if len(corsAllowedOriginList) > 0 { allowedOriginRegexps, err := util.CompileRegexps(corsAllowedOriginList) if err != nil { glog.Fatalf("Invalid CORS allowed origin, --cors_allowed_origins flag was set to %v - %v", strings.Join(corsAllowedOriginList, ","), err) } handler = apiserver.CORS(handler, allowedOriginRegexps, nil, nil, "true") } s := &http.Server{ Addr: net.JoinHostPort(*address, strconv.Itoa(int(*port))), Handler: apiserver.RecoverPanics(handler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Fatal(s.ListenAndServe()) }
func StartMaster(openshiftMasterConfig *configapi.MasterConfig) error { glog.Infof("Starting an OpenShift master, reachable at %s (etcd: %v)", openshiftMasterConfig.ServingInfo.BindAddress, openshiftMasterConfig.EtcdClientInfo.URLs) glog.Infof("OpenShift master public address is %s", openshiftMasterConfig.AssetConfig.MasterPublicURL) if openshiftMasterConfig.EtcdConfig != nil { etcd.RunEtcd(openshiftMasterConfig.EtcdConfig) } // Allow privileged containers // TODO: make this configurable and not the default https://github.com/openshift/origin/issues/662 capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: true, HostNetworkSources: []string{kubelet.ApiserverSource, kubelet.FileSource}, }) openshiftConfig, err := origin.BuildMasterConfig(*openshiftMasterConfig) if err != nil { return err } go func() { openshiftConfig.ControllerPlug.WaitForStop() glog.Fatalf("Master shutdown requested") }() // Must start policy caching immediately openshiftConfig.RunPolicyCache() openshiftConfig.RunProjectCache() unprotectedInstallers := []origin.APIInstaller{} if openshiftMasterConfig.OAuthConfig != nil { authConfig, err := origin.BuildAuthConfig(*openshiftMasterConfig) if err != nil { return err } unprotectedInstallers = append(unprotectedInstallers, authConfig) } var standaloneAssetConfig *origin.AssetConfig if openshiftMasterConfig.AssetConfig != nil { config, err := origin.BuildAssetConfig(*openshiftMasterConfig.AssetConfig) if err != nil { return err } if openshiftMasterConfig.AssetConfig.ServingInfo.BindAddress == openshiftMasterConfig.ServingInfo.BindAddress { unprotectedInstallers = append(unprotectedInstallers, config) } else { standaloneAssetConfig = config } } var kubeConfig *kubernetes.MasterConfig if openshiftMasterConfig.KubernetesMasterConfig != nil { kubeConfig, err = kubernetes.BuildKubernetesMasterConfig(*openshiftMasterConfig, openshiftConfig.RequestContextMapper, openshiftConfig.KubeClient()) if err != nil { return err } openshiftConfig.Run([]origin.APIInstaller{kubeConfig}, unprotectedInstallers) } else { _, kubeConfig, err := configapi.GetKubeClient(openshiftMasterConfig.MasterClients.ExternalKubernetesKubeConfig) if err != nil { return err } proxy := &kubernetes.ProxyConfig{ ClientConfig: kubeConfig, } openshiftConfig.Run([]origin.APIInstaller{proxy}, unprotectedInstallers) } glog.Infof("Using images from %q", openshiftConfig.ImageFor("<component>")) if standaloneAssetConfig != nil { standaloneAssetConfig.Run() } if openshiftMasterConfig.DNSConfig != nil { openshiftConfig.RunDNSServer() } openshiftConfig.RunProjectAuthorizationCache() if openshiftMasterConfig.Controllers != configapi.ControllersDisabled { go func() { openshiftConfig.ControllerPlug.WaitForStart() glog.Infof("Master controllers starting (%s)", openshiftMasterConfig.Controllers) // Start these first, because they provide credentials for other controllers' clients openshiftConfig.RunServiceAccountsController() openshiftConfig.RunServiceAccountTokensController() // used by admission controllers openshiftConfig.RunServiceAccountPullSecretsControllers() openshiftConfig.RunSecurityAllocationController() if kubeConfig != nil { _, rcClient, err := openshiftConfig.GetServiceAccountClients(openshiftConfig.ReplicationControllerServiceAccount) if err != nil { glog.Fatalf("Could not get client for replication controller: %v", err) } // called by admission control kubeConfig.RunResourceQuotaManager() // no special order kubeConfig.RunNodeController() kubeConfig.RunScheduler() kubeConfig.RunReplicationController(rcClient) kubeConfig.RunEndpointController() kubeConfig.RunNamespaceController() kubeConfig.RunPersistentVolumeClaimBinder() kubeConfig.RunPersistentVolumeClaimRecycler(openshiftConfig.ImageFor("deployer")) } // no special order openshiftConfig.RunBuildController() openshiftConfig.RunBuildPodController() openshiftConfig.RunBuildImageChangeTriggerController() openshiftConfig.RunDeploymentController() openshiftConfig.RunDeployerPodController() openshiftConfig.RunDeploymentConfigController() openshiftConfig.RunDeploymentConfigChangeController() openshiftConfig.RunDeploymentImageChangeTriggerController() openshiftConfig.RunImageImportController() openshiftConfig.RunOriginNamespaceController() openshiftConfig.RunSDNController() }() } return nil }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() verflag.PrintAndExitIfRequested() verifyPortalFlags() if (*etcdConfigFile != "" && len(etcdServerList) != 0) || (*etcdConfigFile == "" && len(etcdServerList) == 0) { glog.Fatalf("specify either -etcd_servers or -etcd_config") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) cloud := cloudprovider.InitCloudProvider(*cloudProvider, *cloudConfigFile) kubeletClient, err := client.NewKubeletClient(&kubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } _, v1beta3 := runtimeConfig["api/v1beta3"] // TODO: expose same flags as client.BindClientConfigFlags but for a server clientConfig := &client.Config{ Host: net.JoinHostPort(address.String(), strconv.Itoa(int(*port))), Version: *storageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } helper, err := newEtcd(*etcdConfigFile, etcdServerList) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } n := net.IPNet(portalNet) authenticator, err := apiserver.NewAuthenticatorFromTokenFile(*tokenAuthFile) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(*authorizationMode, *authorizationPolicyFile) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(*admissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, *admissionControlConfigFile) config := &master.Config{ Client: client, Cloud: cloud, EtcdHelper: helper, HealthCheckMinions: *healthCheckMinions, EventTTL: *eventTTL, KubeletClient: kubeletClient, PortalNet: &n, EnableLogsSupport: *enableLogsSupport, EnableUISupport: true, EnableSwaggerSupport: true, APIPrefix: *apiPrefix, CorsAllowedOriginList: corsAllowedOriginList, ReadOnlyPort: *readOnlyPort, ReadWritePort: *port, PublicAddress: *publicAddressOverride, Authenticator: authenticator, Authorizer: authorizer, AdmissionControl: admissionController, EnableV1Beta3: v1beta3, MasterServiceNamespace: *masterServiceNamespace, } m := master.New(config) // We serve on 3 ports. See docs/reaching_the_api.md roLocation := "" if *readOnlyPort != 0 { roLocation = net.JoinHostPort(config.PublicAddress, strconv.Itoa(config.ReadOnlyPort)) } secureLocation := "" if *securePort != 0 { secureLocation = net.JoinHostPort(config.PublicAddress, strconv.Itoa(*securePort)) } rwLocation := net.JoinHostPort(address.String(), strconv.Itoa(int(*port))) // See the flag commentary to understand our assumptions when opening the read-only and read-write ports. if roLocation != "" { // Allow 1 read-only request per second, allow up to 20 in a burst before enforcing. rl := util.NewTokenBucketRateLimiter(1.0, 20) readOnlyServer := &http.Server{ Addr: roLocation, Handler: apiserver.RecoverPanics(apiserver.ReadOnly(apiserver.RateLimit(rl, m.InsecureHandler))), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving read-only insecurely on %s", roLocation) go func() { defer util.HandleCrash() for { if err := readOnlyServer.ListenAndServe(); err != nil { glog.Errorf("Unable to listen for read only traffic (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } if secureLocation != "" { secureServer := &http.Server{ Addr: secureLocation, Handler: apiserver.RecoverPanics(m.Handler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) MinVersion: tls.VersionTLS10, // Populate PeerCertificates in requests, but don't reject connections without certificates // This allows certificates to be validated by authenticators, while still allowing other auth types ClientAuth: tls.RequestClientCert, }, } glog.Infof("Serving securely on %s", secureLocation) go func() { defer util.HandleCrash() for { if *tlsCertFile == "" && *tlsPrivateKeyFile == "" { *tlsCertFile = "/var/run/kubernetes/apiserver.crt" *tlsPrivateKeyFile = "/var/run/kubernetes/apiserver.key" if err := util.GenerateSelfSignedCert(config.PublicAddress, *tlsCertFile, *tlsPrivateKeyFile); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", *tlsCertFile, *tlsPrivateKeyFile) } } if err := secureServer.ListenAndServeTLS(*tlsCertFile, *tlsPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } s := &http.Server{ Addr: rwLocation, Handler: apiserver.RecoverPanics(m.InsecureHandler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving insecurely on %s", rwLocation) glog.Fatal(s.ListenAndServe()) }
// Run runs the specified APIServer. This should never exit. func (s *APIServer) Run(_ []string) error { s.verifyClusterIPFlags() // If advertise-address is not specified, use bind-address. If bind-address // is also unset (or 0.0.0.0), setDefaults() in pkg/master/master.go will // do the right thing and use the host's default interface. if s.AdvertiseAddress == nil || net.IP(s.AdvertiseAddress).IsUnspecified() { s.AdvertiseAddress = s.BindAddress } if (s.EtcdConfigFile != "" && len(s.EtcdServerList) != 0) || (s.EtcdConfigFile == "" && len(s.EtcdServerList) == 0) { glog.Fatalf("specify either --etcd-servers or --etcd-config") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. HostNetworkSources: []string{}, }) cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } kubeletClient, err := client.NewKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } // "api/all=false" allows users to selectively enable specific api versions. disableAllAPIs := false allAPIFlagValue, ok := s.RuntimeConfig["api/all"] if ok && allAPIFlagValue == "false" { disableAllAPIs = true } // "api/legacy=false" allows users to disable legacy api versions. disableLegacyAPIs := false legacyAPIFlagValue, ok := s.RuntimeConfig["api/legacy"] if ok && legacyAPIFlagValue == "false" { disableLegacyAPIs = true } _ = disableLegacyAPIs // hush the compiler while we don't have legacy APIs to disable. // v1beta3 is disabled by default. Users can enable it using "api/v1beta3=true" enableV1beta3 := s.getRuntimeConfigValue("api/v1beta3", false) // "api/v1={true|false} allows users to enable/disable v1 API. // This takes preference over api/all and api/legacy, if specified. disableV1 := disableAllAPIs disableV1 = !s.getRuntimeConfigValue("api/v1", !disableV1) // TODO: expose same flags as client.BindClientConfigFlags but for a server clientConfig := &client.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), Version: s.StorageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } helper, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, s.StorageVersion, s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } // TODO Is this the right place for migration to happen? Must *both* old and // new etcd prefix params be supplied for this to be valid? if s.OldEtcdPathPrefix != "" { if err = helper.MigrateKeys(s.OldEtcdPathPrefix); err != nil { glog.Fatalf("Migration of old etcd keys failed: %v", err) } } n := net.IPNet(s.ServiceClusterIPRange) // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { if apiserver.IsValidServiceAccountKeyFile(s.TLSPrivateKeyFile) { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } else { glog.Warning("no RSA key provided, service account token authentication disabled") } } authenticator, err := apiserver.NewAuthenticator(s.BasicAuthFile, s.ClientCAFile, s.TokenAuthFile, s.ServiceAccountKeyFile, s.ServiceAccountLookup, helper) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(s.AuthorizationMode, s.AuthorizationPolicyFile) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) if len(s.ExternalHost) == 0 { // TODO: extend for other providers if s.CloudProvider == "gce" { instances, supported := cloud.Instances() if !supported { glog.Fatalf("gce cloud provider has no instances. this shouldn't happen. exiting.") } name, err := os.Hostname() if err != nil { glog.Fatalf("failed to get hostname: %v", err) } addrs, err := instances.NodeAddresses(name) if err != nil { glog.Warningf("unable to obtain external host address from cloud provider: %v", err) } else { for _, addr := range addrs { if addr.Type == api.NodeExternalIP { s.ExternalHost = addr.Address } } } } } var installSSH master.InstallSSHKey if cloud != nil { if instances, supported := cloud.Instances(); supported { installSSH = instances.AddSSHKeyToAllInstances } } config := &master.Config{ EtcdHelper: helper, EventTTL: s.EventTTL, KubeletClient: kubeletClient, ServiceClusterIPRange: &n, EnableCoreControllers: true, EnableLogsSupport: s.EnableLogsSupport, EnableUISupport: true, EnableSwaggerSupport: true, EnableProfiling: s.EnableProfiling, EnableIndex: true, APIPrefix: s.APIPrefix, CorsAllowedOriginList: s.CorsAllowedOriginList, ReadWritePort: s.SecurePort, PublicAddress: net.IP(s.AdvertiseAddress), Authenticator: authenticator, SupportsBasicAuth: len(s.BasicAuthFile) > 0, Authorizer: authorizer, AdmissionControl: admissionController, EnableV1Beta3: enableV1beta3, DisableV1: disableV1, MasterServiceNamespace: s.MasterServiceNamespace, ClusterName: s.ClusterName, ExternalHost: s.ExternalHost, MinRequestTimeout: s.MinRequestTimeout, SSHUser: s.SSHUser, SSHKeyfile: s.SSHKeyfile, InstallSSHKey: installSSH, ServiceNodePortRange: s.ServiceNodePortRange, } m := master.New(config) // We serve on 2 ports. See docs/accessing_the_api.md secureLocation := "" if s.SecurePort != 0 { secureLocation = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.SecurePort)) } insecureLocation := net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)) // See the flag commentary to understand our assumptions when opening the read-only and read-write ports. var sem chan bool if s.MaxRequestsInFlight > 0 { sem = make(chan bool, s.MaxRequestsInFlight) } longRunningRE := regexp.MustCompile(s.LongRunningRequestRE) if secureLocation != "" { secureServer := &http.Server{ Addr: secureLocation, Handler: apiserver.MaxInFlightLimit(sem, longRunningRE, apiserver.RecoverPanics(m.Handler)), ReadTimeout: ReadWriteTimeout, WriteTimeout: ReadWriteTimeout, MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) MinVersion: tls.VersionTLS10, }, } if len(s.ClientCAFile) > 0 { clientCAs, err := util.CertPoolFromFile(s.ClientCAFile) if err != nil { glog.Fatalf("unable to load client CA file: %v", err) } // Populate PeerCertificates in requests, but don't reject connections without certificates // This allows certificates to be validated by authenticators, while still allowing other auth types secureServer.TLSConfig.ClientAuth = tls.RequestClientCert // Specify allowed CAs for client certificates secureServer.TLSConfig.ClientCAs = clientCAs } glog.Infof("Serving securely on %s", secureLocation) go func() { defer util.HandleCrash() for { if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { s.TLSCertFile = path.Join(s.CertDirectory, "apiserver.crt") s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "apiserver.key") // TODO (cjcullen): Is PublicAddress the right address to sign a cert with? alternateIPs := []net.IP{config.ServiceReadWriteIP} alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"} // It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless // alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME") if err := util.GenerateSelfSignedCert(config.PublicAddress.String(), s.TLSCertFile, s.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile) } } // err == systemd.SdNotifyNoSocket when not running on a systemd system if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket { glog.Errorf("Unable to send systemd daemon sucessful start message: %v\n", err) } if err := secureServer.ListenAndServeTLS(s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } http := &http.Server{ Addr: insecureLocation, Handler: apiserver.RecoverPanics(m.InsecureHandler), ReadTimeout: ReadWriteTimeout, WriteTimeout: ReadWriteTimeout, MaxHeaderBytes: 1 << 20, } if secureLocation == "" { // err == systemd.SdNotifyNoSocket when not running on a systemd system if err := systemd.SdNotify("READY=1\n"); err != nil && err != systemd.SdNotifyNoSocket { glog.Errorf("Unable to send systemd daemon sucessful start message: %v\n", err) } } glog.Infof("Serving insecurely on %s", insecureLocation) glog.Fatal(http.ListenAndServe()) return nil }
// Run runs the specified APIServer. This should never exit. func (s *APIServer) Run(_ []string) error { s.verifyPortalFlags() if (s.EtcdConfigFile != "" && len(s.EtcdServerList) != 0) || (s.EtcdConfigFile == "" && len(s.EtcdServerList) == 0) { glog.Fatalf("specify either --etcd-servers or --etcd-config") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: s.AllowPrivileged, // TODO(vmarmol): Implement support for HostNetworkSources. HostNetworkSources: []string{}, }) cloud, err := cloudprovider.InitCloudProvider(s.CloudProvider, s.CloudConfigFile) if err != nil { glog.Fatalf("Cloud provider could not be initialized: %v", err) } kubeletClient, err := client.NewKubeletClient(&s.KubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } // "api/all=false" allows users to selectively enable specific api versions. disableAllAPIs := false allAPIFlagValue, ok := s.RuntimeConfig["api/all"] if ok && allAPIFlagValue == "false" { disableAllAPIs = true } // "api/legacy=false" allows users to disable legacy api versions. // Right now, v1beta1 and v1beta2 are considered legacy. disableLegacyAPIs := false legacyAPIFlagValue, ok := s.RuntimeConfig["api/legacy"] if ok && legacyAPIFlagValue == "false" { disableLegacyAPIs = true } // "api/v1beta1={true|false} allows users to enable/disable v1beta1 API. // This takes preference over api/all and api/legacy, if specified. disableV1beta1 := disableAllAPIs || disableLegacyAPIs disableV1beta1 = !s.getRuntimeConfigValue("api/v1beta1", !disableV1beta1) // "api/v1beta2={true|false} allows users to enable/disable v1beta2 API. // This takes preference over api/all and api/legacy, if specified. disableV1beta2 := disableAllAPIs || disableLegacyAPIs disableV1beta2 = !s.getRuntimeConfigValue("api/v1beta2", !disableV1beta2) // "api/v1beta3={true|false} allows users to enable/disable v1beta3 API. // This takes preference over api/all and api/legacy, if specified. disableV1beta3 := disableAllAPIs disableV1beta3 = !s.getRuntimeConfigValue("api/v1beta3", !disableV1beta3) // V1 is disabled by default. Users can enable it using "api/v1={true}". _, enableV1 := s.RuntimeConfig["api/v1"] // TODO: expose same flags as client.BindClientConfigFlags but for a server clientConfig := &client.Config{ Host: net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)), Version: s.StorageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } helper, err := newEtcd(s.EtcdConfigFile, s.EtcdServerList, s.StorageVersion, s.EtcdPathPrefix) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } // TODO Is this the right place for migration to happen? Must *both* old and // new etcd prefix params be supplied for this to be valid? if s.OldEtcdPathPrefix != "" { if err = helper.MigrateKeys(s.OldEtcdPathPrefix); err != nil { glog.Fatalf("Migration of old etcd keys failed: %v", err) } } n := net.IPNet(s.PortalNet) // Default to the private server key for service account token signing if s.ServiceAccountKeyFile == "" && s.TLSPrivateKeyFile != "" { s.ServiceAccountKeyFile = s.TLSPrivateKeyFile } authenticator, err := apiserver.NewAuthenticator(s.BasicAuthFile, s.ClientCAFile, s.TokenAuthFile, s.ServiceAccountKeyFile, s.ServiceAccountLookup, helper) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(s.AuthorizationMode, s.AuthorizationPolicyFile) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) if len(s.ExternalHost) == 0 { // TODO: extend for other providers if s.CloudProvider == "gce" { instances, supported := cloud.Instances() if !supported { glog.Fatalf("gce cloud provider has no instances. this shouldn't happen. exiting.") } name, err := os.Hostname() if err != nil { glog.Fatalf("failed to get hostname: %v", err) } addrs, err := instances.NodeAddresses(name) if err != nil { glog.Warningf("unable to obtain external host address from cloud provider: %v", err) } else { for _, addr := range addrs { if addr.Type == api.NodeExternalIP { s.ExternalHost = addr.Address } } } } } config := &master.Config{ EtcdHelper: helper, EventTTL: s.EventTTL, KubeletClient: kubeletClient, PortalNet: &n, EnableCoreControllers: true, EnableLogsSupport: s.EnableLogsSupport, EnableUISupport: true, EnableSwaggerSupport: true, EnableProfiling: s.EnableProfiling, EnableIndex: true, APIPrefix: s.APIPrefix, CorsAllowedOriginList: s.CorsAllowedOriginList, ReadOnlyPort: s.ReadOnlyPort, ReadWritePort: s.SecurePort, PublicAddress: net.IP(s.BindAddress), Authenticator: authenticator, SupportsBasicAuth: len(s.BasicAuthFile) > 0, Authorizer: authorizer, AdmissionControl: admissionController, DisableV1Beta1: disableV1beta1, DisableV1Beta2: disableV1beta2, DisableV1Beta3: disableV1beta3, EnableV1: enableV1, MasterServiceNamespace: s.MasterServiceNamespace, ClusterName: s.ClusterName, ExternalHost: s.ExternalHost, } m := master.New(config) // We serve on 3 ports. See docs/accessing_the_api.md roLocation := "" if s.ReadOnlyPort != 0 { roLocation = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.ReadOnlyPort)) } secureLocation := "" if s.SecurePort != 0 { secureLocation = net.JoinHostPort(s.BindAddress.String(), strconv.Itoa(s.SecurePort)) } insecureLocation := net.JoinHostPort(s.InsecureBindAddress.String(), strconv.Itoa(s.InsecurePort)) // See the flag commentary to understand our assumptions when opening the read-only and read-write ports. var sem chan bool if s.MaxRequestsInFlight > 0 { sem = make(chan bool, s.MaxRequestsInFlight) } longRunningRE := regexp.MustCompile(s.LongRunningRequestRE) if roLocation != "" { // Default settings allow 1 read-only request per second, allow up to 20 in a burst before enforcing. rl := util.NewTokenBucketRateLimiter(s.APIRate, s.APIBurst) readOnlyServer := &http.Server{ Addr: roLocation, Handler: apiserver.MaxInFlightLimit(sem, longRunningRE, apiserver.RecoverPanics(apiserver.ReadOnly(apiserver.RateLimit(rl, m.InsecureHandler)))), ReadTimeout: ReadWriteTimeout, WriteTimeout: ReadWriteTimeout, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving read-only insecurely on %s", roLocation) go func() { defer util.HandleCrash() for { if err := readOnlyServer.ListenAndServe(); err != nil { glog.Errorf("Unable to listen for read only traffic (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } if secureLocation != "" { secureServer := &http.Server{ Addr: secureLocation, Handler: apiserver.MaxInFlightLimit(sem, longRunningRE, apiserver.RecoverPanics(m.Handler)), ReadTimeout: ReadWriteTimeout, WriteTimeout: ReadWriteTimeout, MaxHeaderBytes: 1 << 20, TLSConfig: &tls.Config{ // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability) MinVersion: tls.VersionTLS10, }, } if len(s.ClientCAFile) > 0 { clientCAs, err := util.CertPoolFromFile(s.ClientCAFile) if err != nil { glog.Fatalf("unable to load client CA file: %v", err) } // Populate PeerCertificates in requests, but don't reject connections without certificates // This allows certificates to be validated by authenticators, while still allowing other auth types secureServer.TLSConfig.ClientAuth = tls.RequestClientCert // Specify allowed CAs for client certificates secureServer.TLSConfig.ClientCAs = clientCAs } glog.Infof("Serving securely on %s", secureLocation) go func() { defer util.HandleCrash() for { if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { s.TLSCertFile = path.Join(s.CertDirectory, "apiserver.crt") s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "apiserver.key") if err := util.GenerateSelfSignedCert(config.PublicAddress.String(), s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to generate self signed cert: %v", err) } else { glog.Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile) } } if err := secureServer.ListenAndServeTLS(s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } http := &http.Server{ Addr: insecureLocation, Handler: apiserver.RecoverPanics(m.InsecureHandler), ReadTimeout: ReadWriteTimeout, WriteTimeout: ReadWriteTimeout, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving insecurely on %s", insecureLocation) glog.Fatal(http.ListenAndServe()) return nil }
// TODO: move this into pkg/capabilities func SetupCapabilities(allowPrivileged bool) { capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: allowPrivileged, }) }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() rand.Seed(time.Now().UTC().UnixNano()) verflag.PrintAndExitIfRequested() if *runonce { exclusiveFlag := "invalid option: --runonce and %s are mutually exclusive" if len(etcdServerList) > 0 { glog.Fatalf(exclusiveFlag, "--etcd_servers") } if *enableServer { glog.Infof("--runonce is set, disabling server") *enableServer = false } } etcd.SetLogger(util.NewLogger("etcd ")) // Log the events locally too. record.StartLogging(glog.Infof) capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) dockerClient, err := docker.NewClient(getDockerEndpoint()) if err != nil { glog.Fatal("Couldn't connect to docker.") } hostname := getHostname() if *rootDirectory == "" { glog.Fatal("Invalid root directory path.") } *rootDirectory = path.Clean(*rootDirectory) if err := os.MkdirAll(*rootDirectory, 0750); err != nil { glog.Fatalf("Error creating root directory: %v", err) } // source of all configuration cfg := kconfig.NewPodConfig(kconfig.PodConfigNotificationSnapshotAndUpdates) // define file config source if *config != "" { kconfig.NewSourceFile(*config, *fileCheckFrequency, cfg.Channel("file")) } // define url config source if *manifestURL != "" { kconfig.NewSourceURL(*manifestURL, *httpCheckFrequency, cfg.Channel("http")) } // define etcd config source and initialize etcd client var etcdClient *etcd.Client if len(etcdServerList) > 0 { etcdClient = etcd.NewClient(etcdServerList) } else if *etcdConfigFile != "" { var err error etcdClient, err = etcd.NewClientFromFile(*etcdConfigFile) if err != nil { glog.Fatalf("Error with etcd config file: %v", err) } } if etcdClient != nil { glog.Infof("Watching for etcd configs at %v", etcdClient.GetCluster()) kconfig.NewSourceEtcd(kconfig.EtcdKeyForHost(hostname), etcdClient, cfg.Channel("etcd")) } // TODO: block until all sources have delivered at least one update to the channel, or break the sync loop // up into "per source" synchronizations k := kubelet.NewMainKubelet( getHostname(), dockerClient, etcdClient, *rootDirectory, *networkContainerImage, *syncFrequency, float32(*registryPullQPS), *registryBurst, *minimumGCAge, *maxContainerCount) k.BirthCry() go func() { util.Forever(func() { err := k.GarbageCollectContainers() if err != nil { glog.Errorf("Garbage collect failed: %v", err) } }, time.Minute*1) }() go func() { defer util.HandleCrash() // TODO: Monitor this connection, reconnect if needed? glog.V(1).Infof("Trying to create cadvisor client.") cadvisorClient, err := cadvisor.NewClient("http://127.0.0.1:4194") if err != nil { glog.Errorf("Error on creating cadvisor client: %v", err) return } glog.V(1).Infof("Successfully created cadvisor client.") k.SetCadvisorClient(cadvisorClient) }() // TODO: These should probably become more plugin-ish: register a factory func // in each checker's init(), iterate those here. health.AddHealthChecker(health.NewExecHealthChecker(k)) health.AddHealthChecker(health.NewHTTPHealthChecker(&http.Client{})) health.AddHealthChecker(&health.TCPHealthChecker{}) // process pods and exit. if *runonce { if _, err := k.RunOnce(cfg.Updates()); err != nil { glog.Fatalf("--runonce failed: %v", err) } return } // start the kubelet go util.Forever(func() { k.Run(cfg.Updates()) }, 0) // start the kubelet server if *enableServer { go util.Forever(func() { kubelet.ListenAndServeKubeletServer(k, cfg.Channel("http"), net.IP(address), *port, *enableDebuggingHandlers) }, 0) } // runs forever select {} }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() rand.Seed(time.Now().UTC().UnixNano()) verflag.PrintAndExitIfRequested() etcd.SetLogger(util.NewLogger("etcd ")) capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) dockerClient, err := docker.NewClient(getDockerEndpoint()) if err != nil { glog.Fatal("Couldn't connect to docker.") } cadvisorClient, err := cadvisor.NewClient("http://127.0.0.1:4194") if err != nil { glog.Errorf("Error on creating cadvisor client: %v", err) } hostname := getHostname() if *rootDirectory == "" { glog.Fatal("Invalid root directory path.") } *rootDirectory = path.Clean(*rootDirectory) os.MkdirAll(*rootDirectory, 0750) // source of all configuration cfg := kconfig.NewPodConfig(kconfig.PodConfigNotificationSnapshotAndUpdates) // define file config source if *config != "" { kconfig.NewSourceFile(*config, *fileCheckFrequency, cfg.Channel("file")) } // define url config source if *manifestURL != "" { kconfig.NewSourceURL(*manifestURL, *httpCheckFrequency, cfg.Channel("http")) } // define etcd config source and initialize etcd client var etcdClient tools.EtcdClient if len(etcdServerList) > 0 { glog.Infof("Watching for etcd configs at %v", etcdServerList) etcdClient = etcd.NewClient(etcdServerList) kconfig.NewSourceEtcd(kconfig.EtcdKeyForHost(hostname), etcdClient, cfg.Channel("etcd")) } // TODO: block until all sources have delivered at least one update to the channel, or break the sync loop // up into "per source" synchronizations k := kubelet.NewMainKubelet( getHostname(), dockerClient, cadvisorClient, etcdClient, *rootDirectory, *syncFrequency) health.AddHealthChecker("exec", health.NewExecHealthChecker(k)) health.AddHealthChecker("http", health.NewHTTPHealthChecker(&http.Client{})) health.AddHealthChecker("tcp", &health.TCPHealthChecker{}) // start the kubelet go util.Forever(func() { k.Run(cfg.Updates()) }, 0) // start the kubelet server if *enableServer { go util.Forever(func() { kubelet.ListenAndServeKubeletServer(k, cfg.Channel("http"), *address, *port) }, 0) } // runs forever select {} }
func main() { flag.Parse() util.InitLogs() defer util.FlushLogs() verflag.PrintAndExitIfRequested() verifyPortalFlags() if (*etcdConfigFile != "" && len(etcdServerList) != 0) || (*etcdConfigFile == "" && len(etcdServerList) == 0) { glog.Fatalf("specify either -etcd_servers or -etcd_config") } capabilities.Initialize(capabilities.Capabilities{ AllowPrivileged: *allowPrivileged, }) cloud := cloudprovider.InitCloudProvider(*cloudProvider, *cloudConfigFile) kubeletClient, err := client.NewKubeletClient(&kubeletConfig) if err != nil { glog.Fatalf("Failure to start kubelet client: %v", err) } // TODO: expose same flags as client.BindClientConfigFlags but for a server clientConfig := &client.Config{ Host: net.JoinHostPort(address.String(), strconv.Itoa(int(*port))), Version: *storageVersion, } client, err := client.New(clientConfig) if err != nil { glog.Fatalf("Invalid server address: %v", err) } helper, err := newEtcd(*etcdConfigFile, etcdServerList) if err != nil { glog.Fatalf("Invalid storage version or misconfigured etcd: %v", err) } n := net.IPNet(portalNet) authenticator, err := apiserver.NewAuthenticatorFromTokenFile(*tokenAuthFile) if err != nil { glog.Fatalf("Invalid Authentication Config: %v", err) } authorizer, err := apiserver.NewAuthorizerFromAuthorizationConfig(*authorizationMode, *authorizationPolicyFile) if err != nil { glog.Fatalf("Invalid Authorization Config: %v", err) } config := &master.Config{ Client: client, Cloud: cloud, EtcdHelper: helper, HealthCheckMinions: *healthCheckMinions, EventTTL: *eventTTL, KubeletClient: kubeletClient, PortalNet: &n, EnableLogsSupport: *enableLogsSupport, EnableUISupport: true, APIPrefix: *apiPrefix, CorsAllowedOriginList: corsAllowedOriginList, ReadOnlyPort: *readOnlyPort, ReadWritePort: *port, PublicAddress: *publicAddressOverride, Authenticator: authenticator, Authorizer: authorizer, } m := master.New(config) // We serve on 3 ports. See docs/reaching_the_api.md roLocation := "" if *readOnlyPort != 0 { roLocation = net.JoinHostPort(config.PublicAddress, strconv.Itoa(config.ReadOnlyPort)) } secureLocation := "" if *securePort != 0 { secureLocation = net.JoinHostPort(config.PublicAddress, strconv.Itoa(*securePort)) } rwLocation := net.JoinHostPort(address.String(), strconv.Itoa(int(*port))) // See the flag commentary to understand our assumptions when opening the read-only and read-write ports. if roLocation != "" { // Allow 1 read-only request per second, allow up to 20 in a burst before enforcing. rl := util.NewTokenBucketRateLimiter(1.0, 20) readOnlyServer := &http.Server{ Addr: roLocation, Handler: apiserver.RecoverPanics(apiserver.ReadOnly(apiserver.RateLimit(rl, m.InsecureHandler))), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving read-only insecurely on %s", roLocation) go func() { defer util.HandleCrash() for { if err := readOnlyServer.ListenAndServe(); err != nil { glog.Errorf("Unable to listen for read only traffic (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } if secureLocation != "" { secureServer := &http.Server{ Addr: secureLocation, Handler: apiserver.RecoverPanics(m.Handler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving securely on %s", secureLocation) go func() { defer util.HandleCrash() for { if err := secureServer.ListenAndServeTLS(*tlsCertFile, *tlsPrivateKeyFile); err != nil { glog.Errorf("Unable to listen for secure (%v); will try again.", err) } time.Sleep(15 * time.Second) } }() } s := &http.Server{ Addr: rwLocation, Handler: apiserver.RecoverPanics(m.InsecureHandler), ReadTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute, MaxHeaderBytes: 1 << 20, } glog.Infof("Serving insecurely on %s", rwLocation) glog.Fatal(s.ListenAndServe()) }