2015-01-30 23:31:36 +00:00
/ *
2016-06-03 00:25:58 +00:00
Copyright 2014 The Kubernetes Authors .
2015-01-30 23:31:36 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2015-02-08 04:07:00 +00:00
// Package app implements a server that runs a set of active
2015-01-30 23:31:36 +00:00
// components. This includes replication controllers, service endpoints and
// nodes.
2015-06-11 13:13:19 +00:00
//
2015-02-08 04:07:00 +00:00
package app
2015-01-30 23:31:36 +00:00
import (
2015-06-23 22:43:59 +00:00
"fmt"
"io/ioutil"
2015-10-06 09:12:00 +00:00
"math/rand"
2015-01-30 23:31:36 +00:00
"net"
"net/http"
2015-03-13 15:44:11 +00:00
"net/http/pprof"
2015-11-04 23:22:11 +00:00
"os"
2015-01-30 23:31:36 +00:00
"strconv"
"time"
2015-12-24 23:59:05 +00:00
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
2015-11-04 23:22:11 +00:00
"k8s.io/kubernetes/pkg/api"
2015-10-13 00:31:25 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2016-09-13 03:28:49 +00:00
"k8s.io/kubernetes/pkg/apimachinery/registered"
2016-08-10 00:43:38 +00:00
"k8s.io/kubernetes/pkg/apis/batch"
2016-02-05 21:58:03 +00:00
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
2016-10-21 22:24:05 +00:00
unversionedcore "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
2015-11-04 23:22:11 +00:00
"k8s.io/kubernetes/pkg/client/leaderelection"
2016-09-15 19:17:18 +00:00
"k8s.io/kubernetes/pkg/client/leaderelection/resourcelock"
2015-11-04 23:22:11 +00:00
"k8s.io/kubernetes/pkg/client/record"
2016-02-12 18:58:43 +00:00
"k8s.io/kubernetes/pkg/client/restclient"
2016-03-03 04:34:18 +00:00
"k8s.io/kubernetes/pkg/client/typed/dynamic"
2015-08-13 19:01:50 +00:00
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/cloudprovider"
2015-11-11 21:19:39 +00:00
"k8s.io/kubernetes/pkg/controller"
2016-05-16 02:18:18 +00:00
certcontroller "k8s.io/kubernetes/pkg/controller/certificates"
2016-11-01 22:46:23 +00:00
"k8s.io/kubernetes/pkg/controller/cronjob"
2015-08-27 17:18:01 +00:00
"k8s.io/kubernetes/pkg/controller/daemon"
2015-09-03 00:02:22 +00:00
"k8s.io/kubernetes/pkg/controller/deployment"
2016-05-13 22:51:05 +00:00
"k8s.io/kubernetes/pkg/controller/disruption"
2015-10-10 03:58:57 +00:00
endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint"
2016-05-26 06:05:50 +00:00
"k8s.io/kubernetes/pkg/controller/garbagecollector"
2016-07-02 06:46:00 +00:00
"k8s.io/kubernetes/pkg/controller/garbagecollector/metaonly"
2016-09-14 18:35:38 +00:00
"k8s.io/kubernetes/pkg/controller/informers"
2015-08-27 12:19:35 +00:00
"k8s.io/kubernetes/pkg/controller/job"
2015-10-10 03:58:57 +00:00
namespacecontroller "k8s.io/kubernetes/pkg/controller/namespace"
nodecontroller "k8s.io/kubernetes/pkg/controller/node"
2016-04-25 19:24:40 +00:00
petset "k8s.io/kubernetes/pkg/controller/petset"
2015-09-10 13:10:07 +00:00
"k8s.io/kubernetes/pkg/controller/podautoscaler"
"k8s.io/kubernetes/pkg/controller/podautoscaler/metrics"
2016-06-06 22:43:57 +00:00
"k8s.io/kubernetes/pkg/controller/podgc"
2016-01-19 00:06:57 +00:00
replicaset "k8s.io/kubernetes/pkg/controller/replicaset"
2015-10-10 03:58:57 +00:00
replicationcontroller "k8s.io/kubernetes/pkg/controller/replication"
resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota"
routecontroller "k8s.io/kubernetes/pkg/controller/route"
servicecontroller "k8s.io/kubernetes/pkg/controller/service"
2015-12-24 21:54:40 +00:00
serviceaccountcontroller "k8s.io/kubernetes/pkg/controller/serviceaccount"
2016-07-02 01:50:25 +00:00
"k8s.io/kubernetes/pkg/controller/volume/attachdetach"
persistentvolumecontroller "k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/healthz"
2016-02-22 16:15:09 +00:00
quotainstall "k8s.io/kubernetes/pkg/quota/install"
2016-07-02 06:46:00 +00:00
"k8s.io/kubernetes/pkg/runtime/serializer"
2015-12-24 21:54:40 +00:00
"k8s.io/kubernetes/pkg/serviceaccount"
2016-09-16 15:52:29 +00:00
certutil "k8s.io/kubernetes/pkg/util/cert"
2016-02-02 02:09:02 +00:00
"k8s.io/kubernetes/pkg/util/configz"
2015-10-28 06:46:44 +00:00
"k8s.io/kubernetes/pkg/util/wait"
2015-04-18 13:31:24 +00:00
2015-01-30 23:31:36 +00:00
"github.com/golang/glog"
2015-04-22 14:46:03 +00:00
"github.com/prometheus/client_golang/prometheus"
2015-10-12 14:33:39 +00:00
"github.com/spf13/cobra"
2015-01-30 23:31:36 +00:00
"github.com/spf13/pflag"
)
2016-03-30 14:07:30 +00:00
const (
// Jitter used when starting controller managers
ControllerStartJitter = 1.0
)
2015-10-12 14:33:39 +00:00
// NewControllerManagerCommand creates a *cobra.Command object with default parameters
func NewControllerManagerCommand ( ) * cobra . Command {
2015-12-24 23:59:05 +00:00
s := options . NewCMServer ( )
2015-10-12 14:33:39 +00:00
s . AddFlags ( pflag . CommandLine )
cmd := & cobra . Command {
Use : "kube-controller-manager" ,
Long : ` The Kubernetes controller manager is a daemon that embeds
the core control loops shipped with Kubernetes . In applications of robotics and
automation , a control loop is a non - terminating loop that regulates the state of
the system . In Kubernetes , a controller is a control loop that watches the shared
state of the cluster through the apiserver and makes changes attempting to move the
current state towards the desired state . Examples of controllers that ship with
Kubernetes today are the replication controller , endpoints controller , namespace
controller , and serviceaccounts controller . ` ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
} ,
}
return cmd
}
2015-12-24 23:59:05 +00:00
func ResyncPeriod ( s * options . CMServer ) func ( ) time . Duration {
return func ( ) time . Duration {
factor := rand . Float64 ( ) + 1
return time . Duration ( float64 ( s . MinResyncPeriod . Nanoseconds ( ) ) * factor )
}
2015-10-06 09:12:00 +00:00
}
2015-01-30 23:31:36 +00:00
// Run runs the CMServer. This should never exit.
2015-12-24 23:59:05 +00:00
func Run ( s * options . CMServer ) error {
2016-02-02 02:09:02 +00:00
if c , err := configz . New ( "componentconfig" ) ; err == nil {
c . Set ( s . KubeControllerManagerConfiguration )
} else {
glog . Errorf ( "unable to register configz: %s" , err )
}
2015-11-06 18:34:49 +00:00
kubeconfig , err := clientcmd . BuildConfigFromFlags ( s . Master , s . Kubeconfig )
2015-04-17 07:18:07 +00:00
if err != nil {
return err
}
2016-04-19 07:35:32 +00:00
kubeconfig . ContentConfig . ContentType = s . ContentType
2015-10-12 15:56:15 +00:00
// Override kubeconfig qps/burst settings from flags
2015-10-20 12:33:48 +00:00
kubeconfig . QPS = s . KubeAPIQPS
2016-04-27 04:35:14 +00:00
kubeconfig . Burst = int ( s . KubeAPIBurst )
2016-09-20 13:43:11 +00:00
kubeClient , err := clientset . NewForConfig ( restclient . AddUserAgent ( kubeconfig , "controller-manager" ) )
2015-01-30 23:31:36 +00:00
if err != nil {
glog . Fatalf ( "Invalid API configuration: %v" , err )
}
2016-09-26 07:46:59 +00:00
leaderElectionClient := clientset . NewForConfigOrDie ( restclient . AddUserAgent ( kubeconfig , "leader-election" ) )
2015-01-30 23:31:36 +00:00
2015-03-13 15:44:11 +00:00
go func ( ) {
2015-04-22 14:46:03 +00:00
mux := http . NewServeMux ( )
healthz . InstallHandler ( mux )
2015-03-13 15:44:11 +00:00
if s . EnableProfiling {
mux . HandleFunc ( "/debug/pprof/" , pprof . Index )
mux . HandleFunc ( "/debug/pprof/profile" , pprof . Profile )
mux . HandleFunc ( "/debug/pprof/symbol" , pprof . Symbol )
}
2016-07-21 11:27:09 +00:00
configz . InstallHandler ( mux )
2015-04-22 14:46:03 +00:00
mux . Handle ( "/metrics" , prometheus . Handler ( ) )
server := & http . Server {
2016-04-27 04:35:14 +00:00
Addr : net . JoinHostPort ( s . Address , strconv . Itoa ( int ( s . Port ) ) ) ,
2015-04-22 14:46:03 +00:00
Handler : mux ,
}
glog . Fatal ( server . ListenAndServe ( ) )
2015-03-13 15:44:11 +00:00
} ( )
2015-01-30 23:31:36 +00:00
2016-06-21 16:13:23 +00:00
eventBroadcaster := record . NewBroadcaster ( )
eventBroadcaster . StartLogging ( glog . Infof )
2016-09-20 13:43:11 +00:00
eventBroadcaster . StartRecordingToSink ( & unversionedcore . EventSinkImpl { Interface : kubeClient . Core ( ) . Events ( "" ) } )
2016-06-21 16:13:23 +00:00
recorder := eventBroadcaster . NewRecorder ( api . EventSource { Component : "controller-manager" } )
2015-11-04 23:22:11 +00:00
run := func ( stop <- chan struct { } ) {
2016-09-22 19:53:08 +00:00
rootClientBuilder := controller . SimpleControllerClientBuilder {
ClientConfig : kubeconfig ,
}
var clientBuilder controller . ControllerClientBuilder
2016-11-01 13:27:35 +00:00
if len ( s . ServiceAccountKeyFile ) > 0 && s . UseServiceAccountCredentials {
2016-09-22 19:53:08 +00:00
clientBuilder = controller . SAControllerClientBuilder {
ClientConfig : restclient . AnonymousClientConfig ( kubeconfig ) ,
CoreClient : kubeClient . Core ( ) ,
Namespace : "kube-system" ,
}
} else {
clientBuilder = rootClientBuilder
}
err := StartControllers ( s , kubeconfig , rootClientBuilder , clientBuilder , stop , recorder )
2015-11-04 23:22:11 +00:00
glog . Fatalf ( "error running controllers: %v" , err )
panic ( "unreachable" )
}
if ! s . LeaderElection . LeaderElect {
run ( nil )
panic ( "unreachable" )
}
id , err := os . Hostname ( )
if err != nil {
return err
}
2016-09-15 19:17:18 +00:00
// TODO: enable other lock types
rl := resourcelock . EndpointsLock {
2015-11-04 23:22:11 +00:00
EndpointsMeta : api . ObjectMeta {
Namespace : "kube-system" ,
Name : "kube-controller-manager" ,
} ,
2016-09-15 19:17:18 +00:00
Client : leaderElectionClient ,
LockConfig : resourcelock . ResourceLockConfig {
Identity : id ,
EventRecorder : recorder ,
} ,
}
leaderelection . RunOrDie ( leaderelection . LeaderElectionConfig {
Lock : & rl ,
2016-09-26 07:46:59 +00:00
LeaseDuration : s . LeaderElection . LeaseDuration . Duration ,
RenewDeadline : s . LeaderElection . RenewDeadline . Duration ,
RetryPeriod : s . LeaderElection . RetryPeriod . Duration ,
2015-11-04 23:22:11 +00:00
Callbacks : leaderelection . LeaderCallbacks {
OnStartedLeading : run ,
OnStoppedLeading : func ( ) {
glog . Fatalf ( "leaderelection lost" )
} ,
} ,
} )
panic ( "unreachable" )
}
2016-09-22 19:53:08 +00:00
func StartControllers ( s * options . CMServer , kubeconfig * restclient . Config , rootClientBuilder , clientBuilder controller . ControllerClientBuilder , stop <- chan struct { } , recorder record . EventRecorder ) error {
client := func ( serviceAccountName string ) clientset . Interface {
return rootClientBuilder . ClientOrDie ( serviceAccountName )
2016-09-20 13:43:11 +00:00
}
discoveryClient := client ( "controller-discovery" ) . Discovery ( )
sharedInformers := informers . NewSharedInformerFactory ( client ( "shared-informers" ) , ResyncPeriod ( s ) ( ) )
2016-08-04 07:06:29 +00:00
2016-09-22 19:53:08 +00:00
// always start the SA token controller first using a full-power client, since it needs to mint tokens for the rest
if len ( s . ServiceAccountKeyFile ) > 0 {
privateKey , err := serviceaccount . ReadPrivateKey ( s . ServiceAccountKeyFile )
if err != nil {
return fmt . Errorf ( "Error reading key for service account token controller: %v" , err )
} else {
var rootCA [ ] byte
if s . RootCAFile != "" {
rootCA , err = ioutil . ReadFile ( s . RootCAFile )
if err != nil {
return fmt . Errorf ( "error reading root-ca-file at %s: %v" , s . RootCAFile , err )
}
if _ , err := certutil . ParseCertsPEM ( rootCA ) ; err != nil {
return fmt . Errorf ( "error parsing root-ca-file at %s: %v" , s . RootCAFile , err )
}
} else {
rootCA = kubeconfig . CAData
}
go serviceaccountcontroller . NewTokensController (
rootClientBuilder . ClientOrDie ( "tokens-controller" ) ,
serviceaccountcontroller . TokensControllerOptions {
TokenGenerator : serviceaccount . JWTTokenGenerator ( privateKey ) ,
RootCA : rootCA ,
} ,
) . Run ( int ( s . ConcurrentSATokenSyncs ) , wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
}
2016-09-20 13:43:11 +00:00
go endpointcontroller . NewEndpointController ( sharedInformers . Pods ( ) . Informer ( ) , client ( "endpoint-controller" ) ) .
2016-04-27 04:35:14 +00:00
Run ( int ( s . ConcurrentEndpointSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-01-30 23:31:36 +00:00
2015-12-02 12:12:31 +00:00
go replicationcontroller . NewReplicationManager (
2016-08-04 07:06:29 +00:00
sharedInformers . Pods ( ) . Informer ( ) ,
2016-09-22 19:53:08 +00:00
clientBuilder . ClientOrDie ( "replication-controller" ) ,
2015-12-24 23:59:05 +00:00
ResyncPeriod ( s ) ,
2015-12-02 12:12:31 +00:00
replicationcontroller . BurstReplicas ,
2016-04-27 04:35:14 +00:00
int ( s . LookupCacheSizeForRC ) ,
2016-06-10 23:28:42 +00:00
s . EnableGarbageCollector ,
2016-04-27 04:35:14 +00:00
) . Run ( int ( s . ConcurrentRCSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-01-30 23:31:36 +00:00
2016-10-25 00:15:39 +00:00
go podgc . NewPodGC ( client ( "pod-garbage-collector" ) , sharedInformers . Pods ( ) . Informer ( ) ,
int ( s . TerminatedPodGCThreshold ) ) . Run ( wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-09-21 22:51:27 +00:00
2015-07-01 18:41:49 +00:00
cloud , err := cloudprovider . InitCloudProvider ( s . CloudProvider , s . CloudConfigFile )
if err != nil {
glog . Fatalf ( "Cloud provider could not be initialized: %v" , err )
}
2015-02-07 19:53:42 +00:00
2016-05-23 07:37:22 +00:00
_ , clusterCIDR , err := net . ParseCIDR ( s . ClusterCIDR )
if err != nil {
glog . Warningf ( "Unsuccessful parsing of cluster CIDR %v: %v" , s . ClusterCIDR , err )
}
_ , serviceCIDR , err := net . ParseCIDR ( s . ServiceCIDR )
if err != nil {
glog . Warningf ( "Unsuccessful parsing of service CIDR %v: %v" , s . ServiceCIDR , err )
}
2016-09-23 16:01:58 +00:00
nodeController , err := nodecontroller . NewNodeController (
sharedInformers . Pods ( ) , sharedInformers . Nodes ( ) , sharedInformers . DaemonSets ( ) ,
cloud , client ( "node-controller" ) ,
2016-08-05 12:50:19 +00:00
s . PodEvictionTimeout . Duration , s . NodeEvictionRate , s . SecondaryNodeEvictionRate , s . LargeClusterSizeThreshold , s . UnhealthyZoneThreshold , s . NodeMonitorGracePeriod . Duration ,
2016-07-13 08:40:22 +00:00
s . NodeStartupGracePeriod . Duration , s . NodeMonitorPeriod . Duration , clusterCIDR , serviceCIDR ,
int ( s . NodeCIDRMaskSize ) , s . AllocateNodeCIDRs )
2016-07-16 18:52:51 +00:00
if err != nil {
glog . Fatalf ( "Failed to initialize nodecontroller: %v" , err )
}
2016-08-30 12:24:56 +00:00
nodeController . Run ( )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-01-30 23:31:36 +00:00
2016-09-20 13:43:11 +00:00
serviceController , err := servicecontroller . New ( cloud , client ( "service-controller" ) , s . ClusterName )
2016-07-26 05:35:40 +00:00
if err != nil {
2015-03-24 17:32:43 +00:00
glog . Errorf ( "Failed to start service controller: %v" , err )
2016-07-26 05:35:40 +00:00
} else {
serviceController . Run ( int ( s . ConcurrentServiceSyncs ) )
2015-03-24 17:32:43 +00:00
}
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-03-24 17:32:43 +00:00
2016-05-14 13:50:17 +00:00
if s . AllocateNodeCIDRs && s . ConfigureCloudRoutes {
2015-11-24 02:11:51 +00:00
if cloud == nil {
2016-05-14 13:50:17 +00:00
glog . Warning ( "configure-cloud-routes is set, but no cloud provider specified. Will not configure cloud provider routes." )
2015-07-26 00:02:23 +00:00
} else if routes , ok := cloud . Routes ( ) ; ! ok {
2016-05-14 13:50:17 +00:00
glog . Warning ( "configure-cloud-routes is set, but cloud provider does not support routes. Will not configure cloud provider routes." )
2015-07-26 00:02:23 +00:00
} else {
2016-09-20 13:43:11 +00:00
routeController := routecontroller . New ( routes , client ( "route-controller" ) , s . ClusterName , clusterCIDR )
2016-08-31 08:19:53 +00:00
routeController . Run ( s . RouteReconciliationPeriod . Duration )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-05-15 21:49:26 +00:00
}
2016-07-21 10:31:28 +00:00
} else {
glog . Infof ( "Will not configure cloud provider routes for allocate-node-cidrs: %v, configure-cloud-routes: %v." , s . AllocateNodeCIDRs , s . ConfigureCloudRoutes )
2015-05-15 21:49:26 +00:00
}
2016-09-20 13:43:11 +00:00
resourceQuotaControllerClient := client ( "resourcequota-controller" )
2016-10-14 17:44:20 +00:00
resourceQuotaRegistry := quotainstall . NewRegistry ( resourceQuotaControllerClient , sharedInformers )
2016-02-22 16:15:09 +00:00
groupKindsToReplenish := [ ] unversioned . GroupKind {
api . Kind ( "Pod" ) ,
api . Kind ( "Service" ) ,
api . Kind ( "ReplicationController" ) ,
api . Kind ( "PersistentVolumeClaim" ) ,
api . Kind ( "Secret" ) ,
2016-02-29 17:02:05 +00:00
api . Kind ( "ConfigMap" ) ,
2016-02-22 16:15:09 +00:00
}
resourceQuotaControllerOptions := & resourcequotacontroller . ResourceQuotaControllerOptions {
2016-03-07 07:20:32 +00:00
KubeClient : resourceQuotaControllerClient ,
ResyncPeriod : controller . StaticResyncPeriodFunc ( s . ResourceQuotaSyncPeriod . Duration ) ,
Registry : resourceQuotaRegistry ,
2016-10-14 17:44:20 +00:00
ControllerFactory : resourcequotacontroller . NewReplenishmentControllerFactory ( sharedInformers , resourceQuotaControllerClient ) ,
2016-03-07 07:20:32 +00:00
ReplenishmentResyncPeriod : ResyncPeriod ( s ) ,
GroupKindsToReplenish : groupKindsToReplenish ,
2016-02-22 16:15:09 +00:00
}
2016-04-27 04:35:14 +00:00
go resourcequotacontroller . NewResourceQuotaController ( resourceQuotaControllerOptions ) . Run ( int ( s . ConcurrentResourceQuotaSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-01-30 23:31:36 +00:00
2015-10-28 06:46:44 +00:00
// If apiserver is not running we should wait for some time and fail only then. This is particularly
// important when we start apiserver and controller manager at the same time.
var versionStrings [ ] string
err = wait . PollImmediate ( time . Second , 10 * time . Second , func ( ) ( bool , error ) {
2016-02-12 18:58:43 +00:00
if versionStrings , err = restclient . ServerAPIVersions ( kubeconfig ) ; err == nil {
2015-11-11 12:28:25 +00:00
return true , nil
}
glog . Errorf ( "Failed to get api versions from server: %v" , err )
return false , nil
2015-10-28 06:46:44 +00:00
} )
2015-10-12 21:23:50 +00:00
if err != nil {
glog . Fatalf ( "Failed to get api versions from server: %v" , err )
}
2015-10-13 00:31:25 +00:00
versions := & unversioned . APIVersions { Versions : versionStrings }
2015-03-20 16:49:03 +00:00
2016-09-20 13:43:11 +00:00
resourceMap , err := discoveryClient . ServerResources ( )
2015-10-12 21:23:50 +00:00
if err != nil {
glog . Fatalf ( "Failed to get supported resources from server: %v" , err )
}
2015-10-02 21:42:18 +00:00
2016-09-13 03:28:49 +00:00
// TODO: should use a dynamic RESTMapper built from the discovery results.
restMapper := registered . RESTMapper ( )
2016-03-03 04:34:18 +00:00
// Find the list of namespaced resources via discovery that the namespace controller must manage
2016-09-20 13:43:11 +00:00
namespaceKubeClient := client ( "namespace-controller" )
2016-09-13 03:28:49 +00:00
namespaceClientPool := dynamic . NewClientPool ( restclient . AddUserAgent ( kubeconfig , "namespace-controller" ) , restMapper , dynamic . LegacyAPIPathResolverFunc )
2016-05-04 05:31:26 +00:00
groupVersionResources , err := namespaceKubeClient . Discovery ( ) . ServerPreferredNamespacedResources ( )
2016-03-03 04:34:18 +00:00
if err != nil {
glog . Fatalf ( "Failed to get supported resources from server: %v" , err )
}
namespaceController := namespacecontroller . NewNamespaceController ( namespaceKubeClient , namespaceClientPool , groupVersionResources , s . NamespaceSyncPeriod . Duration , api . FinalizerKubernetes )
2016-04-27 04:35:14 +00:00
go namespaceController . Run ( int ( s . ConcurrentNamespaceSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-10-12 21:23:50 +00:00
groupVersion := "extensions/v1beta1"
resources , found := resourceMap [ groupVersion ]
// TODO: this needs to be dynamic so users don't have to restart their controller manager if they change the apiserver
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
2015-10-02 21:42:18 +00:00
2015-10-12 21:23:50 +00:00
if containsResource ( resources , "daemonsets" ) {
glog . Infof ( "Starting daemon set controller" )
2016-09-20 13:43:11 +00:00
go daemon . NewDaemonSetsController ( sharedInformers . DaemonSets ( ) , sharedInformers . Pods ( ) , sharedInformers . Nodes ( ) , client ( "daemon-set-controller" ) , int ( s . LookupCacheSizeForDaemonSet ) ) .
2016-04-27 04:35:14 +00:00
Run ( int ( s . ConcurrentDaemonSetSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-10-12 21:23:50 +00:00
}
if containsResource ( resources , "jobs" ) {
glog . Infof ( "Starting job controller" )
2016-11-01 19:57:49 +00:00
go job . NewJobController ( sharedInformers . Pods ( ) . Informer ( ) , sharedInformers . Jobs ( ) , client ( "job-controller" ) ) .
2016-04-27 04:35:14 +00:00
Run ( int ( s . ConcurrentJobSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-10-12 21:23:50 +00:00
}
2015-10-02 21:42:18 +00:00
2015-10-12 21:23:50 +00:00
if containsResource ( resources , "deployments" ) {
glog . Infof ( "Starting deployment controller" )
2016-10-07 19:06:57 +00:00
go deployment . NewDeploymentController ( sharedInformers . Deployments ( ) , sharedInformers . ReplicaSets ( ) , sharedInformers . Pods ( ) , client ( "deployment-controller" ) ) .
2016-04-27 04:35:14 +00:00
Run ( int ( s . ConcurrentDeploymentSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-10-12 21:23:50 +00:00
}
2016-01-19 00:06:57 +00:00
if containsResource ( resources , "replicasets" ) {
glog . Infof ( "Starting ReplicaSet controller" )
2016-10-07 20:31:34 +00:00
go replicaset . NewReplicaSetController ( sharedInformers . ReplicaSets ( ) , sharedInformers . Pods ( ) , client ( "replicaset-controller" ) , replicaset . BurstReplicas , int ( s . LookupCacheSizeForRS ) , s . EnableGarbageCollector ) .
2016-04-27 04:35:14 +00:00
Run ( int ( s . ConcurrentRSSyncs ) , wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2016-01-19 00:06:57 +00:00
}
2015-09-03 00:02:22 +00:00
}
2015-09-03 14:50:53 +00:00
2016-11-04 09:00:56 +00:00
groupVersion = "autoscaling/v1"
resources , found = resourceMap [ groupVersion ]
glog . Infof ( "Attempting to start horizontal pod autoscaler controller, full resource map %+v" , resourceMap )
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
if containsResource ( resources , "horizontalpodautoscalers" ) {
glog . Infof ( "Starting horizontal pod controller." )
hpaClient := client ( "horizontal-pod-autoscaler" )
metricsClient := metrics . NewHeapsterMetricsClient (
hpaClient ,
metrics . DefaultHeapsterNamespace ,
metrics . DefaultHeapsterScheme ,
metrics . DefaultHeapsterService ,
metrics . DefaultHeapsterPort ,
)
HPA: Consider unready pods and missing metrics
Currently, the HPA considers unready pods the same as ready pods when
looking at their CPU and custom metric usage. However, pods frequently
use extra CPU during initialization, so we want to consider them
separately.
This commit causes the HPA to consider unready pods as having 0 CPU
usage when scaling up, and ignores them when scaling down. If, when
scaling up, factoring the unready pods as having 0 CPU would cause a
downscale instead, we simply choose not to scale. Otherwise, we simply
scale up at the reduced amount caculated by factoring the pods in at
zero CPU usage.
The effect is that unready pods cause the autoscaler to be a bit more
conservative -- large increases in CPU usage can still cause scales,
even with unready pods in the mix, but will not cause the scale factors
to be as large, in anticipation of the new pods later becoming ready and
handling load.
Similarly, if there are pods for which no metrics have been retrieved,
these pods are treated as having 100% of the requested metric when
scaling down, and 0% when scaling up. As above, this cannot change the
direction of the scale.
This commit also changes the HPA to ignore superfluous metrics -- as
long as metrics for all ready pods are present, the HPA we make scaling
decisions. Currently, this only works for CPU. For custom metrics, we
cannot identify which metrics go to which pods if we get superfluous
metrics, so we abort the scale.
2016-09-27 18:47:52 +00:00
replicaCalc := podautoscaler . NewReplicaCalculator ( metricsClient , hpaClient . Core ( ) )
go podautoscaler . NewHorizontalController ( hpaClient . Core ( ) , hpaClient . Extensions ( ) , hpaClient . Autoscaling ( ) , replicaCalc , s . HorizontalPodAutoscalerSyncPeriod . Duration ) .
2016-11-04 09:00:56 +00:00
Run ( wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
}
2016-10-26 08:40:07 +00:00
groupVersion = "policy/v1beta1"
2016-05-13 22:51:05 +00:00
resources , found = resourceMap [ groupVersion ]
glog . Infof ( "Attempting to start disruption controller, full resource map %+v" , resourceMap )
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
if containsResource ( resources , "poddisruptionbudgets" ) {
glog . Infof ( "Starting disruption controller" )
2016-09-20 13:43:11 +00:00
go disruption . NewDisruptionController ( sharedInformers . Pods ( ) . Informer ( ) , client ( "disruption-controller" ) ) . Run ( wait . NeverStop )
2016-05-13 22:51:05 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
}
2016-10-27 21:20:52 +00:00
groupVersion = "apps/v1beta1"
2016-04-25 19:24:40 +00:00
resources , found = resourceMap [ groupVersion ]
2016-10-26 20:44:07 +00:00
glog . Infof ( "Attempting to start statefulset, full resource map %+v" , resourceMap )
2016-04-25 19:24:40 +00:00
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
2016-10-26 20:44:07 +00:00
if containsResource ( resources , "statefulsets" ) {
glog . Infof ( "Starting StatefulSet controller" )
2016-04-25 19:24:40 +00:00
resyncPeriod := ResyncPeriod ( s ) ( )
2016-10-26 20:44:07 +00:00
go petset . NewStatefulSetController (
2016-08-04 07:06:29 +00:00
sharedInformers . Pods ( ) . Informer ( ) ,
2016-10-26 20:44:07 +00:00
client ( "statefulset-controller" ) ,
2016-04-25 19:24:40 +00:00
resyncPeriod ,
) . Run ( 1 , wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
}
2016-05-20 07:53:39 +00:00
groupVersion = "batch/v2alpha1"
resources , found = resourceMap [ groupVersion ]
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
2016-11-01 22:46:23 +00:00
if containsResource ( resources , "cronjobs" ) {
glog . Infof ( "Starting cronjob controller" )
2016-09-13 09:24:01 +00:00
// // TODO: this is a temp fix for allowing kubeClient list v2alpha1 sj, should switch to using clientset
2016-08-10 00:43:38 +00:00
kubeconfig . ContentConfig . GroupVersion = & unversioned . GroupVersion { Group : batch . GroupName , Version : "v2alpha1" }
2016-11-01 22:46:23 +00:00
go cronjob . NewCronJobController ( client ( "cronjob-controller" ) ) .
2016-05-20 07:53:39 +00:00
Run ( wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
} else {
glog . Infof ( "Not starting %s apis" , groupVersion )
}
2016-08-18 08:36:50 +00:00
alphaProvisioner , err := NewAlphaVolumeProvisioner ( cloud , s . VolumeConfiguration )
if err != nil {
glog . Fatalf ( "An backward-compatible provisioner could not be created: %v, but one was expected. Provisioning will not work. This functionality is considered an early Alpha version." , err )
}
2016-09-26 12:15:25 +00:00
params := persistentvolumecontroller . ControllerParameters {
KubeClient : client ( "persistent-volume-binder" ) ,
SyncPeriod : s . PVClaimBinderSyncPeriod . Duration ,
AlphaProvisioner : alphaProvisioner ,
VolumePlugins : ProbeControllerVolumePlugins ( cloud , s . VolumeConfiguration ) ,
Cloud : cloud ,
ClusterName : s . ClusterName ,
EnableDynamicProvisioning : s . VolumeConfiguration . EnableDynamicProvisioning ,
}
volumeController := persistentvolumecontroller . NewController ( params )
2016-08-21 18:32:12 +00:00
volumeController . Run ( wait . NeverStop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-04-16 17:26:08 +00:00
2016-04-30 06:36:27 +00:00
attachDetachController , attachDetachControllerErr :=
2016-07-02 01:50:25 +00:00
attachdetach . NewAttachDetachController (
2016-09-20 13:43:11 +00:00
client ( "attachdetach-controller" ) ,
2016-08-04 07:06:29 +00:00
sharedInformers . Pods ( ) . Informer ( ) ,
sharedInformers . Nodes ( ) . Informer ( ) ,
sharedInformers . PersistentVolumeClaims ( ) . Informer ( ) ,
sharedInformers . PersistentVolumes ( ) . Informer ( ) ,
2016-04-30 06:36:27 +00:00
cloud ,
2016-06-21 16:13:23 +00:00
ProbeAttachableVolumePlugins ( s . VolumeConfiguration ) ,
recorder )
2016-04-30 06:36:27 +00:00
if attachDetachControllerErr != nil {
glog . Fatalf ( "Failed to start attach/detach controller: %v" , attachDetachControllerErr )
}
2016-07-21 10:31:28 +00:00
go attachDetachController . Run ( wait . NeverStop )
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2016-04-30 06:36:27 +00:00
2016-09-01 18:33:14 +00:00
groupVersion = "certificates.k8s.io/v1alpha1"
2016-05-16 02:18:18 +00:00
resources , found = resourceMap [ groupVersion ]
glog . Infof ( "Attempting to start certificates, full resource map %+v" , resourceMap )
if containsVersion ( versions , groupVersion ) && found {
glog . Infof ( "Starting %s apis" , groupVersion )
if containsResource ( resources , "certificatesigningrequests" ) {
glog . Infof ( "Starting certificate request controller" )
resyncPeriod := ResyncPeriod ( s ) ( )
certController , err := certcontroller . NewCertificateController (
2016-09-20 13:43:11 +00:00
client ( "certificate-controller" ) ,
2016-05-16 02:18:18 +00:00
resyncPeriod ,
s . ClusterSigningCertFile ,
s . ClusterSigningKeyFile ,
2016-08-08 22:36:10 +00:00
s . ApproveAllKubeletCSRsForGroup ,
2016-05-16 02:18:18 +00:00
)
if err != nil {
glog . Errorf ( "Failed to start certificate controller: %v" , err )
} else {
go certController . Run ( 1 , wait . NeverStop )
}
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
}
}
2016-10-20 19:08:49 +00:00
go serviceaccountcontroller . NewServiceAccountsController (
sharedInformers . ServiceAccounts ( ) , sharedInformers . Namespaces ( ) ,
2016-09-20 13:43:11 +00:00
client ( "service-account-controller" ) ,
2015-12-24 21:54:40 +00:00
serviceaccountcontroller . DefaultServiceAccountsControllerOptions ( ) ,
2016-10-20 19:08:49 +00:00
) . Run ( 1 , stop )
2016-03-30 14:07:30 +00:00
time . Sleep ( wait . Jitter ( s . ControllerStartInterval . Duration , ControllerStartJitter ) )
2015-04-21 03:25:56 +00:00
2016-05-26 06:05:50 +00:00
if s . EnableGarbageCollector {
2016-09-20 13:43:11 +00:00
gcClientset := client ( "generic-garbage-collector" )
2016-05-26 06:05:50 +00:00
groupVersionResources , err := gcClientset . Discovery ( ) . ServerPreferredResources ( )
if err != nil {
glog . Fatalf ( "Failed to get supported resources from server: %v" , err )
}
2016-09-13 03:28:49 +00:00
2016-07-02 06:46:00 +00:00
config := restclient . AddUserAgent ( kubeconfig , "generic-garbage-collector" )
config . ContentConfig . NegotiatedSerializer = serializer . DirectCodecFactory { CodecFactory : metaonly . NewMetadataCodecFactory ( ) }
2016-09-13 03:28:49 +00:00
metaOnlyClientPool := dynamic . NewClientPool ( config , restMapper , dynamic . LegacyAPIPathResolverFunc )
2016-10-12 20:55:28 +00:00
config . ContentConfig = dynamic . ContentConfig ( )
2016-09-13 03:28:49 +00:00
clientPool := dynamic . NewClientPool ( config , restMapper , dynamic . LegacyAPIPathResolverFunc )
garbageCollector , err := garbagecollector . NewGarbageCollector ( metaOnlyClientPool , clientPool , restMapper , groupVersionResources )
2016-05-26 06:05:50 +00:00
if err != nil {
2016-07-21 11:36:07 +00:00
glog . Errorf ( "Failed to start the generic garbage collector: %v" , err )
2016-05-26 06:05:50 +00:00
} else {
2016-07-01 07:26:35 +00:00
workers := int ( s . ConcurrentGCSyncs )
2016-05-26 06:05:50 +00:00
go garbageCollector . Run ( workers , wait . NeverStop )
}
}
2016-08-04 07:06:29 +00:00
sharedInformers . Start ( stop )
2016-04-14 18:00:52 +00:00
2015-01-30 23:31:36 +00:00
select { }
}
2015-10-12 21:23:50 +00:00
2015-10-13 00:31:25 +00:00
func containsVersion ( versions * unversioned . APIVersions , version string ) bool {
2015-10-12 21:23:50 +00:00
for ix := range versions . Versions {
if versions . Versions [ ix ] == version {
return true
}
}
return false
}
2015-10-13 00:31:25 +00:00
func containsResource ( resources * unversioned . APIResourceList , resourceName string ) bool {
2015-10-12 21:23:50 +00:00
for ix := range resources . APIResources {
resource := resources . APIResources [ ix ]
if resource . Name == resourceName {
return true
}
}
return false
}