Worker node upgrade chain
This commit is contained in:
@@ -272,11 +272,17 @@ func listTargetNodeNames(
|
||||
})
|
||||
|
||||
if osu.Spec.NodeSelector != nil {
|
||||
sel, err := metav1.LabelSelectorAsSelector(osu.Spec.NodeSelector)
|
||||
userSelector, err := metav1.LabelSelectorAsSelector(osu.Spec.NodeSelector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid nodeSelector: %w", err)
|
||||
}
|
||||
selector = sel
|
||||
|
||||
reqs, selectable := userSelector.Requirements()
|
||||
if !selectable {
|
||||
selector = labels.Nothing()
|
||||
} else {
|
||||
selector = selector.Add(reqs...)
|
||||
}
|
||||
}
|
||||
|
||||
list, err := clients.Kubernetes.CoreV1().
|
||||
|
||||
108
clitools/pkg/node/kubeadm_compat.go
Normal file
108
clitools/pkg/node/kubeadm_compat.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"example.com/monok8s/pkg/system"
|
||||
)
|
||||
|
||||
const kubeadmUpgradeNodeHostnameBugFixedIn = "v1.35.0"
|
||||
|
||||
// COMPAT(kubeadm-upgrade-node-hostname)
|
||||
// Affects: Kubernetes/kubeadm < v1.35.0
|
||||
// Upstream: kubernetes/kubeadm#3244, kubernetes/kubernetes#134319
|
||||
// RemoveWhen: minimum supported Kubernetes version >= v1.35.0
|
||||
//
|
||||
// Affected kubeadm versions can derive the target Node name for
|
||||
// `kubeadm upgrade node` from the local OS hostname instead of the existing
|
||||
// kubeadm NodeRegistration / kubelet --hostname-override state.
|
||||
func needsKubeadmUpgradeNodeHostnameWorkaround(kubeadmVersion string) bool {
|
||||
lt, err := versionLt(kubeadmVersion, kubeadmUpgradeNodeHostnameBugFixedIn)
|
||||
if err != nil {
|
||||
klog.Warningf(
|
||||
"could not parse kubeadm version %q; enabling kubeadm upgrade node hostname workaround: %v",
|
||||
kubeadmVersion,
|
||||
err,
|
||||
)
|
||||
return true
|
||||
}
|
||||
return lt
|
||||
}
|
||||
|
||||
// runWithTemporaryHostname works around kubernetes/kubeadm#3244, fixed by
|
||||
// kubernetes/kubernetes#134319 in Kubernetes v1.35.0.
|
||||
//
|
||||
// Affected kubeadm versions can derive the target Node name for
|
||||
// `kubeadm upgrade node` from the local OS hostname instead of the existing
|
||||
// kubeadm NodeRegistration / kubelet --hostname-override state. That breaks
|
||||
// valid setups where the machine hostname differs from the Kubernetes Node
|
||||
// name: kubeadm may authenticate as one node but try to get/patch another Node,
|
||||
// and the Node authorizer correctly rejects it.
|
||||
//
|
||||
// Keep this workaround scoped to affected kubeadm versions only. Set the
|
||||
// temporary hostname to the Kubernetes Node name, run kubeadm, then restore the
|
||||
// configured machine hostname immediately afterward.
|
||||
func runWithTemporaryHostname(ctx context.Context, nctx *NodeContext, fn func(context.Context) error) error {
|
||||
if nctx == nil {
|
||||
return errors.New("node context is nil")
|
||||
}
|
||||
|
||||
temporaryHostname := strings.TrimSpace(nctx.Config.Spec.NodeName)
|
||||
if temporaryHostname == "" {
|
||||
return errors.New("temporary hostname is required")
|
||||
}
|
||||
|
||||
originalHostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return fmt.Errorf("get current hostname: %w", err)
|
||||
}
|
||||
|
||||
if originalHostname == temporaryHostname {
|
||||
return fn(ctx)
|
||||
}
|
||||
|
||||
restoreHostname := strings.TrimSpace(nctx.Config.Spec.Network.Hostname)
|
||||
if restoreHostname == "" {
|
||||
restoreHostname = originalHostname
|
||||
}
|
||||
|
||||
klog.Warningf(
|
||||
"temporarily changing hostname for kubeadm upgrade node: current=%q temporary=%q restore=%q",
|
||||
originalHostname,
|
||||
temporaryHostname,
|
||||
restoreHostname,
|
||||
)
|
||||
|
||||
if err := system.SetHostname(temporaryHostname); err != nil {
|
||||
return fmt.Errorf("set temporary hostname to %q: %w", temporaryHostname, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := system.SetHostname(restoreHostname); err != nil {
|
||||
klog.Errorf("failed to restore hostname to %q: %v", restoreHostname, err)
|
||||
}
|
||||
}()
|
||||
|
||||
return fn(ctx)
|
||||
}
|
||||
|
||||
// COMPAT(kubeadm-upgrade-node-hostname)
|
||||
// RemoveWhen: minimum supported Kubernetes version >= v1.35.0
|
||||
func runKubeadmUpgradeNodeWithCompat(
|
||||
ctx context.Context,
|
||||
nctx *NodeContext,
|
||||
kubeadmVersion string,
|
||||
fn func(context.Context) error,
|
||||
) error {
|
||||
if needsKubeadmUpgradeNodeHostnameWorkaround(kubeadmVersion) {
|
||||
return runWithTemporaryHostname(ctx, nctx, fn)
|
||||
}
|
||||
|
||||
return fn(ctx)
|
||||
}
|
||||
@@ -329,21 +329,28 @@ func RunKubeadmUpgradeNode(ctx context.Context, nctx *NodeContext) error {
|
||||
kubeconfigPath,
|
||||
}
|
||||
|
||||
_, err := nctx.SystemRunner.RunWithOptions(
|
||||
ctx,
|
||||
"kubeadm",
|
||||
args,
|
||||
system.RunOptions{
|
||||
Timeout: 10 * time.Minute,
|
||||
OnStdoutLine: func(line string) {
|
||||
klog.Infof("[kubeadm] %s", line)
|
||||
runKubeadm := func(ctx context.Context) error {
|
||||
_, err := nctx.SystemRunner.RunWithOptions(
|
||||
ctx,
|
||||
"kubeadm",
|
||||
args,
|
||||
system.RunOptions{
|
||||
Timeout: 10 * time.Minute,
|
||||
OnStdoutLine: func(line string) {
|
||||
klog.Infof("[kubeadm] %s", line)
|
||||
},
|
||||
OnStderrLine: func(line string) {
|
||||
klog.Infof("[kubeadm] %s", line)
|
||||
},
|
||||
},
|
||||
OnStderrLine: func(line string) {
|
||||
klog.Infof("[kubeadm] %s", line)
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// COMPAT(kubeadm-upgrade-node-hostname)
|
||||
// RemoveWhen: minimum supported Kubernetes version >= v1.35.0
|
||||
// Replace this wrapper with direct runKubeadm(ctx).
|
||||
if err := runKubeadmUpgradeNodeWithCompat(ctx, nctx, wantVersion, runKubeadm); err != nil {
|
||||
return fmt.Errorf("run kubeadm upgrade node: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +203,26 @@ func versionEq(a, b string) bool {
|
||||
return normalizeKubeVersion(a) == normalizeKubeVersion(b)
|
||||
}
|
||||
|
||||
func versionLt(a, b string) (bool, error) {
|
||||
av, err := parseKubeVersion(a)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
bv, err := parseKubeVersion(b)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if av.Major != bv.Major {
|
||||
return av.Major < bv.Major, nil
|
||||
}
|
||||
if av.Minor != bv.Minor {
|
||||
return av.Minor < bv.Minor, nil
|
||||
}
|
||||
return av.Patch < bv.Patch, nil
|
||||
}
|
||||
|
||||
func normalizeKubeVersion(v string) string {
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
|
||||
Reference in New Issue
Block a user