kubeadm: move show-join-command as a separate phase

This commit is contained in:
SataQiu 2022-08-26 23:32:57 +08:00
parent 6dd8b86124
commit 8e4cf3b8d2
4 changed files with 147 additions and 83 deletions

View File

@ -21,9 +21,7 @@ import (
"io"
"os"
"path/filepath"
"text/template"
"github.com/lithammer/dedent"
"github.com/pkg/errors"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
@ -48,46 +46,6 @@ import (
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
)
var (
initDoneTempl = template.Must(template.New("init").Parse(dedent.Dedent(`
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i {{.KubeConfigPath}} $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
{{if .ControlPlaneEndpoint -}}
{{if .UploadCerts -}}
You can now join any number of the control-plane node running the following command on each as root:
{{.joinControlPlaneCommand}}
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
{{else -}}
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
{{.joinControlPlaneCommand}}
{{end}}{{end}}Then you can join any number of worker nodes by running the following on each as root:
{{.joinWorkerCommand}}
`)))
)
// initOptions defines all the init options exposed via flags by kubeadm init.
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
// supported by this api will be exposed as a flag.
@ -151,11 +109,7 @@ func newCmdInit(out io.Writer, initOptions *initOptions) *cobra.Command {
data := c.(*initData)
fmt.Printf("[init] Using Kubernetes version: %s\n", data.cfg.KubernetesVersion)
if err := initRunner.Run(args); err != nil {
return err
}
return showJoinCommand(data, out)
return initRunner.Run(args)
},
Args: cobra.NoArgs,
}
@ -191,6 +145,7 @@ func newCmdInit(out io.Writer, initOptions *initOptions) *cobra.Command {
initRunner.AppendPhase(phases.NewBootstrapTokenPhase())
initRunner.AppendPhase(phases.NewKubeletFinalizePhase())
initRunner.AppendPhase(phases.NewAddonPhase())
initRunner.AppendPhase(phases.NewShowJoinCommandPhase())
// sets the data builder function, that will be used by the runner
// both when running the entire workflow or single phases
@ -565,39 +520,3 @@ func (d *initData) PatchesDir() string {
}
return ""
}
func printJoinCommand(out io.Writer, adminKubeConfigPath, token string, i *initData) error {
joinControlPlaneCommand, err := cmdutil.GetJoinControlPlaneCommand(adminKubeConfigPath, token, i.CertificateKey(), i.skipTokenPrint, i.skipCertificateKeyPrint)
if err != nil {
return err
}
joinWorkerCommand, err := cmdutil.GetJoinWorkerCommand(adminKubeConfigPath, token, i.skipTokenPrint)
if err != nil {
return err
}
ctx := map[string]interface{}{
"KubeConfigPath": adminKubeConfigPath,
"ControlPlaneEndpoint": i.Cfg().ControlPlaneEndpoint,
"UploadCerts": i.uploadCerts,
"joinControlPlaneCommand": joinControlPlaneCommand,
"joinWorkerCommand": joinWorkerCommand,
}
return initDoneTempl.Execute(out, ctx)
}
// showJoinCommand prints the join command after all the phases in init have finished
func showJoinCommand(i *initData, out io.Writer) error {
adminKubeConfigPath := i.KubeConfigPath()
// Prints the join command, multiple times in case the user has multiple tokens
for _, token := range i.Tokens() {
if err := printJoinCommand(out, adminKubeConfigPath, token, i); err != nil {
return errors.Wrap(err, "failed to print join command")
}
}
return nil
}

View File

@ -0,0 +1,119 @@
/*
Copyright 2022 The Kubernetes Authors.
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.
*/
package phases
import (
"io"
"text/template"
"github.com/lithammer/dedent"
"github.com/pkg/errors"
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
)
var (
initDoneTempl = template.Must(template.New("init").Parse(dedent.Dedent(`
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i {{.KubeConfigPath}} $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
{{if .ControlPlaneEndpoint -}}
{{if .UploadCerts -}}
You can now join any number of the control-plane node running the following command on each as root:
{{.joinControlPlaneCommand}}
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
{{else -}}
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
{{.joinControlPlaneCommand}}
{{end}}{{end}}Then you can join any number of worker nodes by running the following on each as root:
{{.joinWorkerCommand}}
`)))
)
// NewShowJoinCommandPhase creates a kubeadm workflow phase that implements showing the join command.
func NewShowJoinCommandPhase() workflow.Phase {
return workflow.Phase{
Name: "show-join-command",
Short: "Show the join command for control-plane and worker node",
Run: showJoinCommand,
Dependencies: []string{"bootstrap-token", "upload-certs"},
}
}
// showJoinCommand prints the join command after all the phases in init have finished
func showJoinCommand(c workflow.RunData) error {
data, ok := c.(InitData)
if !ok {
return errors.New("show-join-command phase invoked with an invalid data struct")
}
adminKubeConfigPath := data.KubeConfigPath()
// Prints the join command, multiple times in case the user has multiple tokens
for _, token := range data.Tokens() {
if err := printJoinCommand(data.OutputWriter(), adminKubeConfigPath, token, data); err != nil {
return errors.Wrap(err, "failed to print join command")
}
}
return nil
}
func printJoinCommand(out io.Writer, adminKubeConfigPath, token string, i InitData) error {
joinControlPlaneCommand, err := cmdutil.GetJoinControlPlaneCommand(adminKubeConfigPath, token, i.CertificateKey(), i.SkipTokenPrint(), i.SkipCertificateKeyPrint())
if err != nil {
return err
}
joinWorkerCommand, err := cmdutil.GetJoinWorkerCommand(adminKubeConfigPath, token, i.SkipTokenPrint())
if err != nil {
return err
}
ctx := map[string]interface{}{
"KubeConfigPath": adminKubeConfigPath,
"ControlPlaneEndpoint": i.Cfg().ControlPlaneEndpoint,
"UploadCerts": i.UploadCerts(),
"joinControlPlaneCommand": joinControlPlaneCommand,
"joinWorkerCommand": joinWorkerCommand,
}
return initDoneTempl.Execute(out, ctx)
}

View File

@ -78,6 +78,9 @@ type Phase struct {
// ArgsValidator defines the positional arg function to be used for validating args for this phase
// If not set a phase will adopt the args of the top level command.
ArgsValidator cobra.PositionalArgs
// Dependencies is a list of phases that the specific phase depends on.
Dependencies []string
}
// AppendPhase adds the given phase to the nested, ordered sequence of phases.

View File

@ -198,6 +198,29 @@ func (e *Runner) Run(args []string) error {
return err
}
// precheck phase dependencies before actual execution
missedDeps := make(map[string][]string)
visited := make(map[string]struct{})
for _, p := range e.phaseRunners {
if run, ok := phaseRunFlags[p.generatedName]; !run || !ok {
continue
}
for _, dep := range p.Phase.Dependencies {
if _, ok := visited[dep]; !ok {
missedDeps[p.Phase.Name] = append(missedDeps[p.Phase.Name], dep)
}
}
visited[p.Phase.Name] = struct{}{}
}
if len(missedDeps) > 0 {
var msg strings.Builder
msg.WriteString("unresolved dependencies:")
for phase, missedPhases := range missedDeps {
msg.WriteString(fmt.Sprintf("\n\tmissing %v phase(s) needed by %q phase", missedPhases, phase))
}
return errors.New(msg.String())
}
// builds the runner data
var data RunData
if data, err = e.InitData(args); err != nil {