Skip to content

Commit a169305

Browse files
author
Xianglin Gao
committed
kubeadm: add pull images check in upgrade apply and upgrade node
Signed-off-by: Xianglin Gao <[email protected]>
1 parent 6c6a702 commit a169305

File tree

6 files changed

+148
-25
lines changed

6 files changed

+148
-25
lines changed

cmd/kubeadm/app/cmd/phases/upgrade/node/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ go_library(
66
"controlplane.go",
77
"data.go",
88
"kubeletconfig.go",
9+
"preflight.go",
910
],
1011
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node",
1112
visibility = ["//visibility:public"],
@@ -17,11 +18,14 @@ go_library(
1718
"//cmd/kubeadm/app/constants:go_default_library",
1819
"//cmd/kubeadm/app/phases/kubelet:go_default_library",
1920
"//cmd/kubeadm/app/phases/upgrade:go_default_library",
21+
"//cmd/kubeadm/app/preflight:go_default_library",
2022
"//cmd/kubeadm/app/util/apiclient:go_default_library",
2123
"//cmd/kubeadm/app/util/dryrun:go_default_library",
24+
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
2225
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
2326
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
2427
"//vendor/github.com/pkg/errors:go_default_library",
28+
"//vendor/k8s.io/utils/exec:go_default_library",
2529
],
2630
)
2731

cmd/kubeadm/app/cmd/phases/upgrade/node/data.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package node
1818

1919
import (
20+
"k8s.io/apimachinery/pkg/util/sets"
2021
clientset "k8s.io/client-go/kubernetes"
2122
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
2223
)
@@ -31,5 +32,6 @@ type Data interface {
3132
Cfg() *kubeadmapi.InitConfiguration
3233
IsControlPlaneNode() bool
3334
Client() clientset.Interface
35+
IgnorePreflightErrors() sets.String
3436
KustomizeDir() string
3537
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
Copyright 2017 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+
package node
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/pkg/errors"
23+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
24+
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
25+
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
26+
utilsexec "k8s.io/utils/exec"
27+
)
28+
29+
// NewPreflightPhase creates a kubeadm workflow phase that implements preflight checks for a new node join
30+
func NewPreflightPhase() workflow.Phase {
31+
return workflow.Phase{
32+
Name: "preflight",
33+
Short: "Run upgrade node pre-flight checks",
34+
Long: "Run pre-flight checks for kubeadm upgrade node.",
35+
Run: runPreflight,
36+
InheritFlags: []string{
37+
options.IgnorePreflightErrors,
38+
},
39+
}
40+
}
41+
42+
// runPreflight executes preflight checks logic.
43+
func runPreflight(c workflow.RunData) error {
44+
data, ok := c.(Data)
45+
if !ok {
46+
return errors.New("preflight phase invoked with an invalid data struct")
47+
}
48+
fmt.Println("[preflight] Running pre-flight checks")
49+
50+
// First, check if we're root separately from the other preflight checks and fail fast
51+
if err := preflight.RunRootCheckOnly(data.IgnorePreflightErrors()); err != nil {
52+
return err
53+
}
54+
55+
// if this is a control-plane node, pull the basic images
56+
if data.IsControlPlaneNode() {
57+
if !data.DryRun() {
58+
fmt.Println("[preflight] Pulling images required for setting up a Kubernetes cluster")
59+
fmt.Println("[preflight] This might take a minute or two, depending on the speed of your internet connection")
60+
fmt.Println("[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'")
61+
if err := preflight.RunPullImagesCheck(utilsexec.New(), data.Cfg(), data.IgnorePreflightErrors()); err != nil {
62+
return err
63+
}
64+
} else {
65+
fmt.Println("[preflight] Would pull the required images (like 'kubeadm config images pull')")
66+
}
67+
} else {
68+
fmt.Println("[preflight] Skipping prepull. Not a control plane node.")
69+
return nil
70+
}
71+
72+
return nil
73+
}

cmd/kubeadm/app/cmd/upgrade/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ go_library(
4242
"//vendor/github.com/spf13/cobra:go_default_library",
4343
"//vendor/github.com/spf13/pflag:go_default_library",
4444
"//vendor/k8s.io/klog:go_default_library",
45+
"//vendor/k8s.io/utils/exec:go_default_library",
4546
],
4647
)
4748

cmd/kubeadm/app/cmd/upgrade/apply.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,27 @@ package upgrade
1818

1919
import (
2020
"fmt"
21+
"time"
2122

2223
"github.com/pkg/errors"
2324
"github.com/spf13/cobra"
25+
"k8s.io/apimachinery/pkg/util/sets"
2426
"k8s.io/apimachinery/pkg/util/version"
2527
clientset "k8s.io/client-go/kubernetes"
2628
"k8s.io/klog"
2729
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
2830
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
2931
"k8s.io/kubernetes/cmd/kubeadm/app/features"
3032
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
33+
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
3134
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
3235
"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
3336
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
37+
utilsexec "k8s.io/utils/exec"
38+
)
39+
40+
const (
41+
defaultImagePullTimeout = 15 * time.Minute
3442
)
3543

3644
// applyFlags holds the information about the flags that can be passed to apply
@@ -42,6 +50,7 @@ type applyFlags struct {
4250
dryRun bool
4351
etcdUpgrade bool
4452
renewCerts bool
53+
imagePullTimeout time.Duration
4554
kustomizeDir string
4655
}
4756

@@ -53,9 +62,10 @@ func (f *applyFlags) sessionIsInteractive() bool {
5362
// NewCmdApply returns the cobra command for `kubeadm upgrade apply`
5463
func NewCmdApply(apf *applyPlanFlags) *cobra.Command {
5564
flags := &applyFlags{
56-
applyPlanFlags: apf,
57-
etcdUpgrade: true,
58-
renewCerts: true,
65+
applyPlanFlags: apf,
66+
imagePullTimeout: defaultImagePullTimeout,
67+
etcdUpgrade: true,
68+
renewCerts: true,
5969
}
6070

6171
cmd := &cobra.Command{
@@ -80,6 +90,9 @@ func NewCmdApply(apf *applyPlanFlags) *cobra.Command {
8090
cmd.Flags().BoolVar(&flags.dryRun, options.DryRun, flags.dryRun, "Do not change any state, just output what actions would be performed.")
8191
cmd.Flags().BoolVar(&flags.etcdUpgrade, "etcd-upgrade", flags.etcdUpgrade, "Perform the upgrade of etcd.")
8292
cmd.Flags().BoolVar(&flags.renewCerts, options.CertificateRenewal, flags.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
93+
cmd.Flags().DurationVar(&flags.imagePullTimeout, "image-pull-timeout", flags.imagePullTimeout, "The maximum amount of time to wait for the control plane pods to be downloaded.")
94+
// TODO: The flag was deprecated in 1.19; remove the flag following a GA deprecation policy of 12 months or 2 releases (whichever is longer)
95+
cmd.Flags().MarkDeprecated("image-pull-timeout", "This flag is deprecated and will be removed in a future version.")
8396
options.AddKustomizePodsFlag(cmd.Flags(), &flags.kustomizeDir)
8497

8598
return cmd
@@ -136,6 +149,17 @@ func runApply(flags *applyFlags, userVersion string) error {
136149
}
137150
}
138151

152+
if !flags.dryRun {
153+
fmt.Println("[upgrade/prepull] Pulling images required for setting up a Kubernetes cluster")
154+
fmt.Println("[upgrade/prepull] This might take a minute or two, depending on the speed of your internet connection")
155+
fmt.Println("[upgrade/prepull] You can also perform this action in beforehand using 'kubeadm config images pull'")
156+
if err := preflight.RunPullImagesCheck(utilsexec.New(), cfg, sets.NewString(cfg.NodeRegistration.IgnorePreflightErrors...)); err != nil {
157+
return err
158+
}
159+
} else {
160+
fmt.Println("[upgrade/prepull] Would pull the required images (like 'kubeadm config images pull')")
161+
}
162+
139163
waiter := getWaiter(flags.dryRun, client, upgrade.UpgradeManifestTimeout)
140164

141165
// Now; perform the upgrade procedure

cmd/kubeadm/app/cmd/upgrade/node.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ import (
2323
"github.com/spf13/cobra"
2424
flag "github.com/spf13/pflag"
2525

26+
"k8s.io/apimachinery/pkg/util/sets"
2627
clientset "k8s.io/client-go/kubernetes"
2728
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
29+
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
2830
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
2931
phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
3032
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
@@ -36,12 +38,13 @@ import (
3638
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
3739
// supported by this api will be exposed as a flag.
3840
type nodeOptions struct {
39-
kubeConfigPath string
40-
kubeletVersion string
41-
etcdUpgrade bool
42-
renewCerts bool
43-
dryRun bool
44-
kustomizeDir string
41+
kubeConfigPath string
42+
kubeletVersion string
43+
etcdUpgrade bool
44+
renewCerts bool
45+
dryRun bool
46+
kustomizeDir string
47+
ignorePreflightErrors []string
4548
}
4649

4750
// compile-time assert that the local data object satisfies the phases data interface.
@@ -50,14 +53,15 @@ var _ phases.Data = &nodeData{}
5053
// nodeData defines all the runtime information used when running the kubeadm upgrade node worklow;
5154
// this data is shared across all the phases that are included in the workflow.
5255
type nodeData struct {
53-
etcdUpgrade bool
54-
renewCerts bool
55-
dryRun bool
56-
kubeletVersion string
57-
cfg *kubeadmapi.InitConfiguration
58-
isControlPlaneNode bool
59-
client clientset.Interface
60-
kustomizeDir string
56+
etcdUpgrade bool
57+
renewCerts bool
58+
dryRun bool
59+
kubeletVersion string
60+
cfg *kubeadmapi.InitConfiguration
61+
isControlPlaneNode bool
62+
client clientset.Interface
63+
kustomizeDir string
64+
ignorePreflightErrors sets.String
6165
}
6266

6367
// NewCmdNode returns the cobra command for `kubeadm upgrade node`
@@ -80,6 +84,7 @@ func NewCmdNode() *cobra.Command {
8084
options.AddKustomizePodsFlag(cmd.Flags(), &nodeOptions.kustomizeDir)
8185

8286
// initialize the workflow runner with the list of phases
87+
nodeRunner.AppendPhase(phases.NewPreflightPhase())
8388
nodeRunner.AppendPhase(phases.NewControlPlane())
8489
nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())
8590

@@ -113,6 +118,7 @@ func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) {
113118
flagSet.MarkDeprecated(options.KubeletVersion, "This flag is deprecated and will be removed in a future version.")
114119
flagSet.BoolVar(&nodeOptions.renewCerts, options.CertificateRenewal, nodeOptions.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
115120
flagSet.BoolVar(&nodeOptions.etcdUpgrade, options.EtcdUpgrade, nodeOptions.etcdUpgrade, "Perform the upgrade of etcd.")
121+
flagSet.StringSliceVar(&nodeOptions.ignorePreflightErrors, options.IgnorePreflightErrors, nodeOptions.ignorePreflightErrors, "A list of checks whose errors will be shown as warnings. Example: 'IsPrivilegedUser,Swap'. Value 'all' ignores errors from all checks.")
116122
}
117123

118124
// newNodeData returns a new nodeData struct to be used for the execution of the kubeadm upgrade node workflow.
@@ -140,15 +146,23 @@ func newNodeData(cmd *cobra.Command, args []string, options *nodeOptions) (*node
140146
return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
141147
}
142148

149+
ignorePreflightErrorsSet, err := validation.ValidateIgnorePreflightErrors(options.ignorePreflightErrors, cfg.NodeRegistration.IgnorePreflightErrors)
150+
if err != nil {
151+
return nil, err
152+
}
153+
// Also set the union of pre-flight errors to JoinConfiguration, to provide a consistent view of the runtime configuration:
154+
cfg.NodeRegistration.IgnorePreflightErrors = ignorePreflightErrorsSet.List()
155+
143156
return &nodeData{
144-
etcdUpgrade: options.etcdUpgrade,
145-
renewCerts: options.renewCerts,
146-
dryRun: options.dryRun,
147-
kubeletVersion: options.kubeletVersion,
148-
cfg: cfg,
149-
client: client,
150-
isControlPlaneNode: isControlPlaneNode,
151-
kustomizeDir: options.kustomizeDir,
157+
etcdUpgrade: options.etcdUpgrade,
158+
renewCerts: options.renewCerts,
159+
dryRun: options.dryRun,
160+
kubeletVersion: options.kubeletVersion,
161+
cfg: cfg,
162+
client: client,
163+
isControlPlaneNode: isControlPlaneNode,
164+
kustomizeDir: options.kustomizeDir,
165+
ignorePreflightErrors: ignorePreflightErrorsSet,
152166
}, nil
153167
}
154168

@@ -191,3 +205,8 @@ func (d *nodeData) Client() clientset.Interface {
191205
func (d *nodeData) KustomizeDir() string {
192206
return d.kustomizeDir
193207
}
208+
209+
// IgnorePreflightErrors returns the list of preflight errors to ignore.
210+
func (d *nodeData) IgnorePreflightErrors() sets.String {
211+
return d.ignorePreflightErrors
212+
}

0 commit comments

Comments
 (0)