From 242e071fa24cb8ab11b3a276486e2154770bf3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Fern=C3=A1ndez=20L=C3=B3pez?= Date: Thu, 11 Oct 2018 10:26:53 +0200 Subject: [PATCH] kubeadm: Perform IPVS check on join only if the cluster was set up with IPVS. --- cmd/kubeadm/app/cmd/join.go | 122 ++++++++++++++++------------ cmd/kubeadm/app/preflight/checks.go | 15 +++- 2 files changed, 84 insertions(+), 53 deletions(-) diff --git a/cmd/kubeadm/app/cmd/join.go b/cmd/kubeadm/app/cmd/join.go index 4fa531f4097..58834f434fa 100644 --- a/cmd/kubeadm/app/cmd/join.go +++ b/cmd/kubeadm/app/cmd/join.go @@ -289,6 +289,8 @@ func AddJoinOtherFlags(flagSet *flag.FlagSet, cfgPath *string, ignorePreflightEr // Join defines struct used by kubeadm join command type Join struct { cfg *kubeadmapi.JoinConfiguration + initCfg *kubeadmapi.InitConfiguration + tlsBootstrapCfg *clientcmdapi.Config ignorePreflightErrors sets.String } @@ -303,52 +305,44 @@ func NewJoin(cfgPath string, defaultcfg *kubeadmapiv1beta1.JoinConfiguration, ig glog.V(1).Infoln("[join] found advertiseAddress empty; using default interface's IP address as advertiseAddress") } - internalcfg, err := configutil.JoinConfigFileAndDefaultsToInternalConfig(cfgPath, defaultcfg) + internalCfg, err := configutil.JoinConfigFileAndDefaultsToInternalConfig(cfgPath, defaultcfg) if err != nil { return nil, err } - if err := configutil.VerifyAPIServerBindAddress(internalcfg.APIEndpoint.AdvertiseAddress); err != nil { + if err := configutil.VerifyAPIServerBindAddress(internalCfg.APIEndpoint.AdvertiseAddress); err != nil { return nil, err } - fmt.Println("[preflight] running pre-flight checks") + fmt.Println("[preflight] Running pre-flight checks") - // Then continue with the others... - glog.V(1).Infoln("[preflight] running various checks on all nodes") - if err := preflight.RunJoinNodeChecks(utilsexec.New(), internalcfg, ignorePreflightErrors); err != nil { + // Start with general checks + glog.V(1).Infoln("[preflight] Running general checks") + if err := preflight.RunJoinNodeChecks(utilsexec.New(), internalCfg, ignorePreflightErrors); err != nil { return nil, err } - return &Join{cfg: internalcfg, ignorePreflightErrors: ignorePreflightErrors}, nil + // Fetch the init configuration based on the join configuration + glog.V(1).Infoln("[preflight] Fetching init configuration") + initCfg, tlsBootstrapCfg, err := fetchInitConfigurationFromJoinConfiguration(internalCfg) + if err != nil { + return nil, err + } + + // Continue with more specific checks based on the init configuration + glog.V(1).Infoln("[preflight] Running configuration dependant checks") + if err := preflight.RunOptionalJoinNodeChecks(utilsexec.New(), initCfg, ignorePreflightErrors); err != nil { + return nil, err + } + + return &Join{cfg: internalCfg, initCfg: initCfg, tlsBootstrapCfg: tlsBootstrapCfg, ignorePreflightErrors: ignorePreflightErrors}, nil } // Run executes worker node provisioning and tries to join an existing cluster. func (j *Join) Run(out io.Writer) error { - // Perform the Discovery, which turns a Bootstrap Token and optionally (and preferably) a CA cert hash into a kubeconfig - // file that may be used for the TLS Bootstrapping process the kubelet performs using the Certificates API. - glog.V(1).Infoln("[join] discovering cluster-info") - tlsBootstrapCfg, err := discovery.For(j.cfg) - if err != nil { - return err - } - - // If the node should host a new control plane instance - var initConfiguration *kubeadmapi.InitConfiguration if j.cfg.ControlPlane == true { - // Retrives the kubeadm configuration used during kubeadm init - glog.V(1).Infoln("[join] retrieving kubeconfig objects") - initConfiguration, err = j.FetchInitConfiguration(tlsBootstrapCfg) - if err != nil { - return err - } - - // injects into the kubeadm configuration the information about the joining node - initConfiguration.NodeRegistration = j.cfg.NodeRegistration - initConfiguration.APIEndpoint = j.cfg.APIEndpoint - // Checks if the cluster configuration supports // joining a new control plane instance and if all the necessary certificates are provided - if err = j.CheckIfReadyForAdditionalControlPlane(initConfiguration); err != nil { + if err := j.CheckIfReadyForAdditionalControlPlane(j.initCfg); err != nil { // outputs the not ready for hosting a new control plane instance message ctx := map[string]string{ "Error": err.Error(), @@ -360,12 +354,12 @@ func (j *Join) Run(out io.Writer) error { } // run kubeadm init preflight checks for checking all the prequisites - fmt.Printf("[join] running pre-flight checks before initializing the new control plane instance\n") - preflight.RunInitMasterChecks(utilsexec.New(), initConfiguration, j.ignorePreflightErrors) + fmt.Printf("[join] Running pre-flight checks before initializing the new control plane instance\n") + preflight.RunInitMasterChecks(utilsexec.New(), j.initCfg, j.ignorePreflightErrors) // Prepares the node for hosting a new control plane instance by writing necessary // kubeconfig files, and static pod manifests - if err = j.PrepareForHostingControlPlane(initConfiguration); err != nil { + if err := j.PrepareForHostingControlPlane(j.initCfg); err != nil { return err } } @@ -376,21 +370,21 @@ func (j *Join) Run(out io.Writer) error { // if the node is hosting a new control plane instance, since it uses static pods for the control plane, // as soon as the kubelet starts it will take charge of creating control plane // components on the node. - if err = j.BootstrapKubelet(tlsBootstrapCfg); err != nil { + if err := j.BootstrapKubelet(j.tlsBootstrapCfg); err != nil { return err } // if the node is hosting a new control plane instance if j.cfg.ControlPlane == true { // Completes the control plane setup - if err := j.PostInstallControlPlane(initConfiguration); err != nil { + if err := j.PostInstallControlPlane(j.initCfg); err != nil { return err } // outputs the join control plane done template and exits etcdMessage := "" // in case of local etcd - if initConfiguration.Etcd.External == nil { + if j.initCfg.Etcd.External == nil { etcdMessage = "* A new etcd member was added to the local/stacked etcd cluster." } @@ -408,23 +402,6 @@ func (j *Join) Run(out io.Writer) error { return nil } -// FetchInitConfiguration reads the cluster configuration from the kubeadm-admin configMap, -func (j *Join) FetchInitConfiguration(tlsBootstrapCfg *clientcmdapi.Config) (*kubeadmapi.InitConfiguration, error) { - // creates a client to access the cluster using the bootstrap token identity - tlsClient, err := kubeconfigutil.ToClientSet(tlsBootstrapCfg) - if err != nil { - return nil, errors.Wrap(err, "Unable to access the cluster") - } - - // Fetches the init configuration - initConfiguration, err := configutil.FetchConfigFromFileOrCluster(tlsClient, os.Stdout, "join", "", true) - if err != nil { - return nil, errors.Wrap(err, "Unable to fetch the kubeadm-config ConfigMap") - } - - return initConfiguration, nil -} - // CheckIfReadyForAdditionalControlPlane ensures that the cluster is in a state that supports // joining an additional control plane instance and if the node is ready to join func (j *Join) CheckIfReadyForAdditionalControlPlane(initConfiguration *kubeadmapi.InitConfiguration) error { @@ -624,3 +601,44 @@ func waitForTLSBootstrappedClient() error { return (err == nil), nil }) } + +// fetchInitConfigurationFromJoinConfiguration retrieves the init configuration from a join configuration, performing the discovery +func fetchInitConfigurationFromJoinConfiguration(cfg *kubeadmapi.JoinConfiguration) (*kubeadmapi.InitConfiguration, *clientcmdapi.Config, error) { + // Perform the Discovery, which turns a Bootstrap Token and optionally (and preferably) a CA cert hash into a KubeConfig + // file that may be used for the TLS Bootstrapping process the kubelet performs using the Certificates API. + glog.V(1).Infoln("[join] Discovering cluster-info") + tlsBootstrapCfg, err := discovery.For(cfg) + if err != nil { + return nil, nil, err + } + + // Retrieves the kubeadm configuration + glog.V(1).Infoln("[join] Retrieving KubeConfig objects") + initConfiguration, err := fetchInitConfiguration(tlsBootstrapCfg) + if err != nil { + return nil, nil, err + } + + // injects into the kubeadm configuration the information about the joining node + initConfiguration.NodeRegistration = cfg.NodeRegistration + initConfiguration.APIEndpoint = cfg.APIEndpoint + + return initConfiguration, tlsBootstrapCfg, nil +} + +// fetchInitConfiguration reads the cluster configuration from the kubeadm-admin configMap +func fetchInitConfiguration(tlsBootstrapCfg *clientcmdapi.Config) (*kubeadmapi.InitConfiguration, error) { + // creates a client to access the cluster using the bootstrap token identity + tlsClient, err := kubeconfigutil.ToClientSet(tlsBootstrapCfg) + if err != nil { + return nil, errors.Wrap(err, "unable to access the cluster") + } + + // Fetches the init configuration + initConfiguration, err := configutil.FetchConfigFromFileOrCluster(tlsClient, os.Stdout, "join", "", true) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap") + } + + return initConfiguration, nil +} diff --git a/cmd/kubeadm/app/preflight/checks.go b/cmd/kubeadm/app/preflight/checks.go index fcc101426d2..032e2b0426f 100644 --- a/cmd/kubeadm/app/preflight/checks.go +++ b/cmd/kubeadm/app/preflight/checks.go @@ -941,7 +941,6 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura DirAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName)}, FileAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)}, FileAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletBootstrapKubeConfigFileName)}, - ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer}, } checks = addCommonChecks(execer, cfg, checks) if !cfg.ControlPlane { @@ -974,6 +973,20 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura return RunChecks(checks, os.Stderr, ignorePreflightErrors) } +// RunOptionalJoinNodeChecks executes all individual, applicable to node configuration dependant checks +func RunOptionalJoinNodeChecks(execer utilsexec.Interface, initCfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.String) error { + checks := []Checker{} + + // Check ipvs required kernel module if we use ipvs kube-proxy mode + if initCfg.ComponentConfigs.KubeProxy != nil && initCfg.ComponentConfigs.KubeProxy.Mode == ipvsutil.IPVSProxyMode { + checks = append(checks, + ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer}, + ) + } + + return RunChecks(checks, os.Stderr, ignorePreflightErrors) +} + // addCommonChecks is a helper function to deplicate checks that are common between both the // kubeadm init and join commands func addCommonChecks(execer utilsexec.Interface, cfg kubeadmapi.CommonConfiguration, checks []Checker) []Checker {