mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-02 08:17:26 +00:00
kubeadm graduate preflight phase
This commit is contained in:
parent
ce7e7e3c34
commit
abac950cd7
@ -37,6 +37,7 @@ import (
|
|||||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
@ -126,6 +127,9 @@ type initData struct {
|
|||||||
skipTokenPrint bool
|
skipTokenPrint bool
|
||||||
dryRun bool
|
dryRun bool
|
||||||
ignorePreflightErrors sets.String
|
ignorePreflightErrors sets.String
|
||||||
|
certificatesDir string
|
||||||
|
dryRunDir string
|
||||||
|
client clientset.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdInit returns "kubeadm init" command.
|
// NewCmdInit returns "kubeadm init" command.
|
||||||
@ -160,7 +164,8 @@ func NewCmdInit(out io.Writer) *cobra.Command {
|
|||||||
options.bto.AddTTLFlag(cmd.PersistentFlags())
|
options.bto.AddTTLFlag(cmd.PersistentFlags())
|
||||||
|
|
||||||
// initialize the workflow runner with the list of phases
|
// initialize the workflow runner with the list of phases
|
||||||
// TODO: add the phases to the runner. e.g. initRunner.AppendPhase(phases.PreflightMaster)
|
initRunner.AppendPhase(phases.NewPreflightMasterPhase())
|
||||||
|
// TODO: add other phases to the runner.
|
||||||
|
|
||||||
// sets the data builder function, that will be used by the runner
|
// sets the data builder function, that will be used by the runner
|
||||||
// both when running the entire workflow or single phases
|
// both when running the entire workflow or single phases
|
||||||
@ -297,31 +302,113 @@ func newInitData(cmd *cobra.Command, options *initOptions) (initData, error) {
|
|||||||
return initData{}, err
|
return initData{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if dry running creates a temporary folder for saving kubeadm generated files
|
||||||
|
dryRunDir := ""
|
||||||
|
if options.dryRun {
|
||||||
|
if dryRunDir, err = ioutil.TempDir("", "kubeadm-init-dryrun"); err != nil {
|
||||||
|
return initData{}, fmt.Errorf("couldn't create a temporary directory: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return initData{
|
return initData{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
certificatesDir: cfg.CertificatesDir,
|
||||||
skipTokenPrint: options.skipTokenPrint,
|
skipTokenPrint: options.skipTokenPrint,
|
||||||
dryRun: options.dryRun,
|
dryRun: options.dryRun,
|
||||||
|
dryRunDir: dryRunDir,
|
||||||
ignorePreflightErrors: ignorePreflightErrorsSet,
|
ignorePreflightErrors: ignorePreflightErrorsSet,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cfg returns initConfiguration.
|
||||||
|
func (d initData) Cfg() *kubeadmapi.InitConfiguration {
|
||||||
|
return d.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// DryRun returns the DryRun flag.
|
||||||
|
func (d initData) DryRun() bool {
|
||||||
|
return d.dryRun
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipTokenPrint returns the SkipTokenPrint flag.
|
||||||
|
func (d initData) SkipTokenPrint() bool {
|
||||||
|
return d.skipTokenPrint
|
||||||
|
}
|
||||||
|
|
||||||
|
// IgnorePreflightErrors returns the IgnorePreflightErrors flag.
|
||||||
|
func (d initData) IgnorePreflightErrors() sets.String {
|
||||||
|
return d.ignorePreflightErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateWriteDir returns the path to the certificate folder or the temporary folder path in case of DryRun.
|
||||||
|
func (d initData) CertificateWriteDir() string {
|
||||||
|
if d.dryRun {
|
||||||
|
return d.dryRunDir
|
||||||
|
}
|
||||||
|
return d.certificatesDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateDir returns the CertificateDir as originally specified by the user.
|
||||||
|
func (d initData) CertificateDir() string {
|
||||||
|
return d.certificatesDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// KubeConfigDir returns the path of the kubernetes configuration folder or the temporary folder path in case of DryRun.
|
||||||
|
func (d initData) KubeConfigDir() string {
|
||||||
|
if d.dryRun {
|
||||||
|
return d.dryRunDir
|
||||||
|
}
|
||||||
|
return kubeadmconstants.KubernetesDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// KubeConfigDir returns the path where manifest should be stored or the temporary folder path in case of DryRun.
|
||||||
|
func (d initData) ManifestDir() string {
|
||||||
|
if d.dryRun {
|
||||||
|
return d.dryRunDir
|
||||||
|
}
|
||||||
|
return kubeadmconstants.GetStaticPodDirectory()
|
||||||
|
}
|
||||||
|
|
||||||
|
// KubeletDir returns path of the kubelet configuration folder or the temporary folder in case of DryRun.
|
||||||
|
func (d initData) KubeletDir() string {
|
||||||
|
if d.dryRun {
|
||||||
|
return d.dryRunDir
|
||||||
|
}
|
||||||
|
return kubeadmconstants.KubeletRunDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client returns a Kubernetes client to be used by kubeadm.
|
||||||
|
// This function is implemented as a singleton, thus avoiding to recreate the client when it is used by different phases.
|
||||||
|
// Important. This function must be called after the admin.conf kubeconfig file is created.
|
||||||
|
func (d initData) Client() (clientset.Interface, error) {
|
||||||
|
if d.client == nil {
|
||||||
|
if d.dryRun {
|
||||||
|
// If we're dry-running; we should create a faked client that answers some GETs in order to be able to do the full init flow and just logs the rest of requests
|
||||||
|
dryRunGetter := apiclient.NewInitDryRunGetter(d.cfg.NodeRegistration.Name, d.cfg.Networking.ServiceSubnet)
|
||||||
|
d.client = apiclient.NewDryRunClient(dryRunGetter, os.Stdout)
|
||||||
|
} else {
|
||||||
|
// If we're acting for real, we should create a connection to the API server and wait for it to come up
|
||||||
|
var err error
|
||||||
|
d.client, err = kubeconfigutil.ClientSetFromFile(kubeadmconstants.GetAdminKubeConfigPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d.client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokens returns an array of token strings.
|
||||||
|
func (d initData) Tokens() []string {
|
||||||
|
tokens := []string{}
|
||||||
|
for _, bt := range d.cfg.BootstrapTokens {
|
||||||
|
tokens = append(tokens, bt.Token.String())
|
||||||
|
}
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
// runInit executes master node provisioning
|
// runInit executes master node provisioning
|
||||||
func runInit(i *initData, out io.Writer) error {
|
func runInit(i *initData, out io.Writer) error {
|
||||||
fmt.Println("[preflight] running pre-flight checks")
|
|
||||||
if err := preflight.RunInitMasterChecks(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !i.dryRun {
|
|
||||||
fmt.Println("[preflight/images] Pulling images required for setting up a Kubernetes cluster")
|
|
||||||
fmt.Println("[preflight/images] This might take a minute or two, depending on the speed of your internet connection")
|
|
||||||
fmt.Println("[preflight/images] You can also perform this action in beforehand using 'kubeadm config images pull'")
|
|
||||||
if err := preflight.RunPullImagesCheck(utilsexec.New(), i.cfg, i.ignorePreflightErrors); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("[preflight/images] Would pull the required images (like 'kubeadm config images pull')")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get directories to write files to; can be faked if we're dry-running
|
// Get directories to write files to; can be faked if we're dry-running
|
||||||
glog.V(1).Infof("[init] Getting certificates directory from configuration")
|
glog.V(1).Infof("[init] Getting certificates directory from configuration")
|
||||||
|
@ -21,11 +21,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
||||||
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
||||||
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
|
||||||
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
|
||||||
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
||||||
@ -35,13 +37,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
masterPreflightLongDesc = normalizer.LongDesc(`
|
|
||||||
Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.
|
|
||||||
` + cmdutil.AlphaDisclaimer)
|
|
||||||
|
|
||||||
masterPreflightExample = normalizer.Examples(`
|
masterPreflightExample = normalizer.Examples(`
|
||||||
# Run master pre-flight checks.
|
# Run master pre-flight checks using a config file.
|
||||||
kubeadm alpha phase preflight master
|
kubeadm init phase preflight --config kubeadm-config.yml
|
||||||
`)
|
`)
|
||||||
|
|
||||||
nodePreflightLongDesc = normalizer.LongDesc(`
|
nodePreflightLongDesc = normalizer.LongDesc(`
|
||||||
@ -56,6 +54,52 @@ var (
|
|||||||
errorMissingConfigFlag = errors.New("the --config flag is mandatory")
|
errorMissingConfigFlag = errors.New("the --config flag is mandatory")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// preflightMasterData defines the behavior that a runtime data struct passed to the PreflightMaster master phase
|
||||||
|
// should have. Please note that we are using an interface in order to make this phase reusable in different workflows
|
||||||
|
// (and thus with different runtime data struct, all of them requested to be compliant to this interface)
|
||||||
|
type preflightMasterData interface {
|
||||||
|
Cfg() *kubeadmapi.InitConfiguration
|
||||||
|
DryRun() bool
|
||||||
|
IgnorePreflightErrors() sets.String
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPreflightMasterPhase creates a kubeadm workflow phase that implements preflight checks for a new master node.
|
||||||
|
func NewPreflightMasterPhase() workflow.Phase {
|
||||||
|
return workflow.Phase{
|
||||||
|
Name: "preflight",
|
||||||
|
Short: "Run master pre-flight checks",
|
||||||
|
Long: "Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.",
|
||||||
|
Example: masterPreflightExample,
|
||||||
|
Run: runPreflightMaster,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runPreflightMaster executes preflight checks logic.
|
||||||
|
func runPreflightMaster(c workflow.RunData) error {
|
||||||
|
data, ok := c.(preflightMasterData)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("preflight phase invoked with an invalid data struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[preflight] running pre-flight checks")
|
||||||
|
if err := preflight.RunInitMasterChecks(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.DryRun() {
|
||||||
|
fmt.Println("[preflight] Pulling images required for setting up a Kubernetes cluster")
|
||||||
|
fmt.Println("[preflight] This might take a minute or two, depending on the speed of your internet connection")
|
||||||
|
fmt.Println("[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'")
|
||||||
|
if err := preflight.RunPullImagesCheck(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("[preflight] Would pull the required images (like 'kubeadm config images pull')")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewCmdPreFlight calls cobra.Command for preflight checks
|
// NewCmdPreFlight calls cobra.Command for preflight checks
|
||||||
func NewCmdPreFlight() *cobra.Command {
|
func NewCmdPreFlight() *cobra.Command {
|
||||||
var cfgPath string
|
var cfgPath string
|
||||||
@ -70,47 +114,11 @@ func NewCmdPreFlight() *cobra.Command {
|
|||||||
options.AddConfigFlag(cmd.PersistentFlags(), &cfgPath)
|
options.AddConfigFlag(cmd.PersistentFlags(), &cfgPath)
|
||||||
options.AddIgnorePreflightErrorsFlag(cmd.PersistentFlags(), &ignorePreflightErrors)
|
options.AddIgnorePreflightErrorsFlag(cmd.PersistentFlags(), &ignorePreflightErrors)
|
||||||
|
|
||||||
cmd.AddCommand(NewCmdPreFlightMaster(&cfgPath, &ignorePreflightErrors))
|
|
||||||
cmd.AddCommand(NewCmdPreFlightNode(&cfgPath, &ignorePreflightErrors))
|
cmd.AddCommand(NewCmdPreFlightNode(&cfgPath, &ignorePreflightErrors))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdPreFlightMaster calls cobra.Command for master preflight checks
|
|
||||||
func NewCmdPreFlightMaster(cfgPath *string, ignorePreflightErrors *[]string) *cobra.Command {
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "master",
|
|
||||||
Short: "Run master pre-flight checks",
|
|
||||||
Long: masterPreflightLongDesc,
|
|
||||||
Example: masterPreflightExample,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
if len(*cfgPath) == 0 {
|
|
||||||
kubeadmutil.CheckErr(errorMissingConfigFlag)
|
|
||||||
}
|
|
||||||
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(*ignorePreflightErrors)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
|
|
||||||
cfg := &kubeadmapiv1beta1.InitConfiguration{}
|
|
||||||
kubeadmscheme.Scheme.Default(cfg)
|
|
||||||
|
|
||||||
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
err = configutil.VerifyAPIServerBindAddress(internalcfg.APIEndpoint.AdvertiseAddress)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
|
|
||||||
fmt.Println("[preflight] running pre-flight checks")
|
|
||||||
|
|
||||||
err = preflight.RunInitMasterChecks(utilsexec.New(), internalcfg, ignorePreflightErrorsSet)
|
|
||||||
kubeadmutil.CheckErr(err)
|
|
||||||
|
|
||||||
fmt.Println("[preflight] pre-flight checks passed")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCmdPreFlightNode calls cobra.Command for node preflight checks
|
// NewCmdPreFlightNode calls cobra.Command for node preflight checks
|
||||||
func NewCmdPreFlightNode(cfgPath *string, ignorePreflightErrors *[]string) *cobra.Command {
|
func NewCmdPreFlightNode(cfgPath *string, ignorePreflightErrors *[]string) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
Loading…
Reference in New Issue
Block a user