sigs.k8s.io/cluster-api@v1.7.1/bootstrap/kubeadm/main.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // main is the main package for the Kubeadm Bootstrap provider. 18 package main 19 20 import ( 21 "context" 22 "flag" 23 "fmt" 24 "os" 25 goruntime "runtime" 26 "time" 27 28 "github.com/spf13/pflag" 29 corev1 "k8s.io/api/core/v1" 30 "k8s.io/apimachinery/pkg/labels" 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/selection" 33 clientgoscheme "k8s.io/client-go/kubernetes/scheme" 34 "k8s.io/client-go/tools/leaderelection/resourcelock" 35 cliflag "k8s.io/component-base/cli/flag" 36 "k8s.io/component-base/logs" 37 logsv1 "k8s.io/component-base/logs/api/v1" 38 _ "k8s.io/component-base/logs/json/register" 39 "k8s.io/klog/v2" 40 ctrl "sigs.k8s.io/controller-runtime" 41 "sigs.k8s.io/controller-runtime/pkg/cache" 42 "sigs.k8s.io/controller-runtime/pkg/client" 43 "sigs.k8s.io/controller-runtime/pkg/controller" 44 "sigs.k8s.io/controller-runtime/pkg/webhook" 45 46 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 47 bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" 48 kubeadmbootstrapcontrollers "sigs.k8s.io/cluster-api/bootstrap/kubeadm/controllers" 49 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/internal/webhooks" 50 "sigs.k8s.io/cluster-api/controllers/remote" 51 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 52 "sigs.k8s.io/cluster-api/feature" 53 bootstrapv1alpha3 "sigs.k8s.io/cluster-api/internal/apis/bootstrap/kubeadm/v1alpha3" 54 bootstrapv1alpha4 "sigs.k8s.io/cluster-api/internal/apis/bootstrap/kubeadm/v1alpha4" 55 "sigs.k8s.io/cluster-api/util/flags" 56 "sigs.k8s.io/cluster-api/version" 57 ) 58 59 var ( 60 scheme = runtime.NewScheme() 61 setupLog = ctrl.Log.WithName("setup") 62 controllerName = "cluster-api-kubeadm-bootstrap-manager" 63 64 // flags. 65 enableLeaderElection bool 66 leaderElectionLeaseDuration time.Duration 67 leaderElectionRenewDeadline time.Duration 68 leaderElectionRetryPeriod time.Duration 69 watchFilterValue string 70 watchNamespace string 71 profilerAddress string 72 enableContentionProfiling bool 73 syncPeriod time.Duration 74 restConfigQPS float32 75 restConfigBurst int 76 webhookPort int 77 webhookCertDir string 78 healthAddr string 79 tlsOptions = flags.TLSOptions{} 80 diagnosticsOptions = flags.DiagnosticsOptions{} 81 logOptions = logs.NewOptions() 82 // CABPK specific flags. 83 clusterConcurrency int 84 clusterCacheTrackerConcurrency int 85 kubeadmConfigConcurrency int 86 tokenTTL time.Duration 87 ) 88 89 func init() { 90 _ = clientgoscheme.AddToScheme(scheme) 91 _ = clusterv1.AddToScheme(scheme) 92 _ = expv1.AddToScheme(scheme) 93 _ = bootstrapv1alpha3.AddToScheme(scheme) 94 _ = bootstrapv1alpha4.AddToScheme(scheme) 95 _ = bootstrapv1.AddToScheme(scheme) 96 } 97 98 // InitFlags initializes the flags. 99 func InitFlags(fs *pflag.FlagSet) { 100 logsv1.AddFlags(logOptions, fs) 101 102 fs.BoolVar(&enableLeaderElection, "leader-elect", false, 103 "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") 104 105 fs.DurationVar(&leaderElectionLeaseDuration, "leader-elect-lease-duration", 15*time.Second, 106 "Interval at which non-leader candidates will wait to force acquire leadership (duration string)") 107 108 fs.DurationVar(&leaderElectionRenewDeadline, "leader-elect-renew-deadline", 10*time.Second, 109 "Duration that the leading controller manager will retry refreshing leadership before giving up (duration string)") 110 111 fs.DurationVar(&leaderElectionRetryPeriod, "leader-elect-retry-period", 2*time.Second, 112 "Duration the LeaderElector clients should wait between tries of actions (duration string)") 113 114 fs.StringVar(&watchNamespace, "namespace", "", 115 "Namespace that the controller watches to reconcile cluster-api objects. If unspecified, the controller watches for cluster-api objects across all namespaces.") 116 117 fs.StringVar(&watchFilterValue, "watch-filter", "", 118 fmt.Sprintf("Label value that the controller watches to reconcile cluster-api objects. Label key is always %s. If unspecified, the controller watches for all cluster-api objects.", clusterv1.WatchLabel)) 119 120 fs.StringVar(&profilerAddress, "profiler-address", "", 121 "Bind address to expose the pprof profiler (e.g. localhost:6060)") 122 123 fs.BoolVar(&enableContentionProfiling, "contention-profiling", false, 124 "Enable block profiling") 125 126 fs.IntVar(&clusterConcurrency, "cluster-concurrency", 10, 127 "Number of clusters to process simultaneously") 128 _ = fs.MarkDeprecated("cluster-concurrency", "This flag has no function anymore and is going to be removed in a next release. Use \"--clustercachetracker-concurrency\" instead.") 129 130 fs.IntVar(&clusterCacheTrackerConcurrency, "clustercachetracker-concurrency", 10, 131 "Number of clusters to process simultaneously") 132 133 fs.IntVar(&kubeadmConfigConcurrency, "kubeadmconfig-concurrency", 10, 134 "Number of kubeadm configs to process simultaneously") 135 136 fs.DurationVar(&syncPeriod, "sync-period", 10*time.Minute, 137 "The minimum interval at which watched resources are reconciled (e.g. 15m)") 138 139 fs.Float32Var(&restConfigQPS, "kube-api-qps", 20, 140 "Maximum queries per second from the controller client to the Kubernetes API server. Defaults to 20") 141 142 fs.IntVar(&restConfigBurst, "kube-api-burst", 30, 143 "Maximum number of queries that should be allowed in one burst from the controller client to the Kubernetes API server. Default 30") 144 145 fs.DurationVar(&tokenTTL, "bootstrap-token-ttl", kubeadmbootstrapcontrollers.DefaultTokenTTL, 146 "The amount of time the bootstrap token will be valid") 147 148 fs.IntVar(&webhookPort, "webhook-port", 9443, 149 "Webhook Server port") 150 151 fs.StringVar(&webhookCertDir, "webhook-cert-dir", "/tmp/k8s-webhook-server/serving-certs/", 152 "Webhook cert dir, only used when webhook-port is specified.") 153 154 fs.StringVar(&healthAddr, "health-addr", ":9440", 155 "The address the health endpoint binds to.") 156 157 flags.AddDiagnosticsOptions(fs, &diagnosticsOptions) 158 flags.AddTLSOptions(fs, &tlsOptions) 159 160 feature.MutableGates.AddFlag(fs) 161 } 162 163 // Add RBAC for the authorized diagnostics endpoint. 164 // +kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create 165 // +kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create 166 167 func main() { 168 InitFlags(pflag.CommandLine) 169 pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc) 170 pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 171 // Set log level 2 as default. 172 if err := pflag.CommandLine.Set("v", "2"); err != nil { 173 setupLog.Error(err, "failed to set default log level") 174 os.Exit(1) 175 } 176 pflag.Parse() 177 178 if err := logsv1.ValidateAndApply(logOptions, nil); err != nil { 179 setupLog.Error(err, "unable to start manager") 180 os.Exit(1) 181 } 182 183 // klog.Background will automatically use the right logger. 184 ctrl.SetLogger(klog.Background()) 185 186 restConfig := ctrl.GetConfigOrDie() 187 restConfig.QPS = restConfigQPS 188 restConfig.Burst = restConfigBurst 189 restConfig.UserAgent = remote.DefaultClusterAPIUserAgent(controllerName) 190 191 tlsOptionOverrides, err := flags.GetTLSOptionOverrideFuncs(tlsOptions) 192 if err != nil { 193 setupLog.Error(err, "unable to add TLS settings to the webhook server") 194 os.Exit(1) 195 } 196 197 diagnosticsOpts := flags.GetDiagnosticsOptions(diagnosticsOptions) 198 199 var watchNamespaces map[string]cache.Config 200 if watchNamespace != "" { 201 watchNamespaces = map[string]cache.Config{ 202 watchNamespace: {}, 203 } 204 } 205 206 if enableContentionProfiling { 207 goruntime.SetBlockProfileRate(1) 208 } 209 210 req, _ := labels.NewRequirement(clusterv1.ClusterNameLabel, selection.Exists, nil) 211 clusterSecretCacheSelector := labels.NewSelector().Add(*req) 212 213 ctrlOptions := ctrl.Options{ 214 Scheme: scheme, 215 LeaderElection: enableLeaderElection, 216 LeaderElectionID: "kubeadm-bootstrap-manager-leader-election-capi", 217 LeaseDuration: &leaderElectionLeaseDuration, 218 RenewDeadline: &leaderElectionRenewDeadline, 219 RetryPeriod: &leaderElectionRetryPeriod, 220 LeaderElectionResourceLock: resourcelock.LeasesResourceLock, 221 HealthProbeBindAddress: healthAddr, 222 PprofBindAddress: profilerAddress, 223 Metrics: diagnosticsOpts, 224 Cache: cache.Options{ 225 DefaultNamespaces: watchNamespaces, 226 SyncPeriod: &syncPeriod, 227 ByObject: map[client.Object]cache.ByObject{ 228 // Note: Only Secrets with the cluster name label are cached. 229 // The default client of the manager won't use the cache for secrets at all (see Client.Cache.DisableFor). 230 // The cached secrets will only be used by the secretCachingClient we create below. 231 &corev1.Secret{}: { 232 Label: clusterSecretCacheSelector, 233 }, 234 }, 235 }, 236 Client: client.Options{ 237 Cache: &client.CacheOptions{ 238 DisableFor: []client.Object{ 239 &corev1.ConfigMap{}, 240 &corev1.Secret{}, 241 }, 242 }, 243 }, 244 WebhookServer: webhook.NewServer( 245 webhook.Options{ 246 Port: webhookPort, 247 CertDir: webhookCertDir, 248 TLSOpts: tlsOptionOverrides, 249 }, 250 ), 251 } 252 253 mgr, err := ctrl.NewManager(restConfig, ctrlOptions) 254 if err != nil { 255 setupLog.Error(err, "unable to start manager") 256 os.Exit(1) 257 } 258 259 // Setup the context that's going to be used in controllers and for the manager. 260 ctx := ctrl.SetupSignalHandler() 261 262 setupChecks(mgr) 263 setupWebhooks(mgr) 264 setupReconcilers(ctx, mgr) 265 266 setupLog.Info("starting manager", "version", version.Get().String()) 267 if err := mgr.Start(ctx); err != nil { 268 setupLog.Error(err, "problem running manager") 269 os.Exit(1) 270 } 271 } 272 273 func setupChecks(mgr ctrl.Manager) { 274 if err := mgr.AddReadyzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil { 275 setupLog.Error(err, "unable to create ready check") 276 os.Exit(1) 277 } 278 279 if err := mgr.AddHealthzCheck("webhook", mgr.GetWebhookServer().StartedChecker()); err != nil { 280 setupLog.Error(err, "unable to create health check") 281 os.Exit(1) 282 } 283 } 284 285 func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { 286 secretCachingClient, err := client.New(mgr.GetConfig(), client.Options{ 287 HTTPClient: mgr.GetHTTPClient(), 288 Cache: &client.CacheOptions{ 289 Reader: mgr.GetCache(), 290 }, 291 }) 292 if err != nil { 293 setupLog.Error(err, "unable to create secret caching client") 294 os.Exit(1) 295 } 296 297 // Set up a ClusterCacheTracker and ClusterCacheReconciler to provide to controllers 298 // requiring a connection to a remote cluster 299 tracker, err := remote.NewClusterCacheTracker( 300 mgr, 301 remote.ClusterCacheTrackerOptions{ 302 SecretCachingClient: secretCachingClient, 303 ControllerName: controllerName, 304 Log: &ctrl.Log, 305 }, 306 ) 307 if err != nil { 308 setupLog.Error(err, "unable to create cluster cache tracker") 309 os.Exit(1) 310 } 311 if err := (&remote.ClusterCacheReconciler{ 312 Client: mgr.GetClient(), 313 Tracker: tracker, 314 WatchFilterValue: watchFilterValue, 315 }).SetupWithManager(ctx, mgr, concurrency(clusterCacheTrackerConcurrency)); err != nil { 316 setupLog.Error(err, "unable to create controller", "controller", "ClusterCacheReconciler") 317 os.Exit(1) 318 } 319 320 if err := (&kubeadmbootstrapcontrollers.KubeadmConfigReconciler{ 321 Client: mgr.GetClient(), 322 SecretCachingClient: secretCachingClient, 323 Tracker: tracker, 324 WatchFilterValue: watchFilterValue, 325 TokenTTL: tokenTTL, 326 }).SetupWithManager(ctx, mgr, concurrency(kubeadmConfigConcurrency)); err != nil { 327 setupLog.Error(err, "unable to create controller", "controller", "KubeadmConfig") 328 os.Exit(1) 329 } 330 } 331 332 func setupWebhooks(mgr ctrl.Manager) { 333 if err := (&webhooks.KubeadmConfig{}).SetupWebhookWithManager(mgr); err != nil { 334 setupLog.Error(err, "unable to create webhook", "webhook", "KubeadmConfig") 335 os.Exit(1) 336 } 337 if err := (&webhooks.KubeadmConfigTemplate{}).SetupWebhookWithManager(mgr); err != nil { 338 setupLog.Error(err, "unable to create webhook", "webhook", "KubeadmConfigTemplate") 339 os.Exit(1) 340 } 341 } 342 343 func concurrency(c int) controller.Options { 344 return controller.Options{MaxConcurrentReconciles: c} 345 }