diff --git a/pkg/agent/config/config.go b/pkg/agent/config/config.go index 6282de51cf..8cfd815e7e 100644 --- a/pkg/agent/config/config.go +++ b/pkg/agent/config/config.go @@ -370,10 +370,9 @@ func get(ctx context.Context, envInfo *cmds.Agent, proxy proxy.Proxy) (*config.N if err != nil { return nil, errors.Wrap(err, "failed to retrieve configuration from server") } - // If the supervisor and externally-facing apiserver are not on the same port, tell the proxy where to find the apiserver. if controlConfig.SupervisorPort != controlConfig.HTTPSPort { - isIPv6 := utilsnet.IsIPv6(net.ParseIP([]string{envInfo.NodeIP.String()}[0])) + isIPv6 := utilsnet.IsIPv6(net.ParseIP(util.GetFirstValidIPString(envInfo.NodeIP))) if err := proxy.SetAPIServerPort(controlConfig.HTTPSPort, isIPv6); err != nil { return nil, errors.Wrapf(err, "failed to set apiserver port to %d", controlConfig.HTTPSPort) } diff --git a/pkg/agent/run.go b/pkg/agent/run.go index aa9f5a5ce5..93b4e27b62 100644 --- a/pkg/agent/run.go +++ b/pkg/agent/run.go @@ -322,7 +322,7 @@ func createProxyAndValidateToken(ctx context.Context, cfg *cmds.Agent) (proxy.Pr if err := os.MkdirAll(agentDir, 0700); err != nil { return nil, err } - isIPv6 := utilsnet.IsIPv6(net.ParseIP([]string{cfg.NodeIP.String()}[0])) + isIPv6 := utilsnet.IsIPv6(net.ParseIP(util.GetFirstValidIPString(cfg.NodeIP))) proxy, err := proxy.NewSupervisorProxy(ctx, !cfg.DisableLoadBalancer, agentDir, cfg.ServerURL, cfg.LBServerPort, isIPv6) if err != nil { diff --git a/pkg/daemons/agent/agent_linux.go b/pkg/daemons/agent/agent_linux.go index 5e22fbc085..ca7f94a529 100644 --- a/pkg/daemons/agent/agent_linux.go +++ b/pkg/daemons/agent/agent_linux.go @@ -34,8 +34,7 @@ func createRootlessConfig(argsMap map[string]string, controllers map[string]bool func kubeProxyArgs(cfg *config.Agent) map[string]string { bindAddress := "127.0.0.1" - isIPv6 := utilsnet.IsIPv6(net.ParseIP([]string{cfg.NodeIP}[0])) - if isIPv6 { + if utilsnet.IsIPv6(net.ParseIP(cfg.NodeIP)) { bindAddress = "::1" } argsMap := map[string]string{ @@ -67,8 +66,7 @@ func kubeProxyArgs(cfg *config.Agent) map[string]string { func kubeletArgs(cfg *config.Agent) map[string]string { bindAddress := "127.0.0.1" - isIPv6 := utilsnet.IsIPv6(net.ParseIP([]string{cfg.NodeIP}[0])) - if isIPv6 { + if utilsnet.IsIPv6(net.ParseIP(cfg.NodeIP)) { bindAddress = "::1" } argsMap := map[string]string{ diff --git a/pkg/daemons/agent/agent_windows.go b/pkg/daemons/agent/agent_windows.go index 69995f5e9f..7bbf468eb6 100644 --- a/pkg/daemons/agent/agent_windows.go +++ b/pkg/daemons/agent/agent_windows.go @@ -4,6 +4,7 @@ package agent import ( + "net" "os" "path/filepath" "strings" @@ -11,8 +12,8 @@ import ( "github.com/k3s-io/k3s/pkg/daemons/config" "github.com/k3s-io/k3s/pkg/util" "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/util/net" "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" + utilsnet "k8s.io/utils/net" ) const ( @@ -21,8 +22,7 @@ const ( func kubeProxyArgs(cfg *config.Agent) map[string]string { bindAddress := "127.0.0.1" - _, IPv6only, _ := util.GetFirstString([]string{cfg.NodeIP}) - if IPv6only { + if utilsnet.IsIPv6(net.ParseIP(cfg.NodeIP)) { bindAddress = "::1" } argsMap := map[string]string{ @@ -95,9 +95,22 @@ func kubeletArgs(cfg *config.Agent) map[string]string { if cfg.NodeName != "" { argsMap["hostname-override"] = cfg.NodeName } - defaultIP, err := net.ChooseHostInterface() - if err != nil || defaultIP.String() != cfg.NodeIP { - argsMap["node-ip"] = cfg.NodeIP + + // If the embedded CCM is disabled, don't assume that dual-stack node IPs are safe. + // When using an external CCM, the user wants dual-stack node IPs, they will need to set the node-ip kubelet arg directly. + // This should be fine since most cloud providers have their own way of finding node IPs that doesn't depend on the kubelet + // setting them. + if cfg.DisableCCM { + dualStack, err := utilsnet.IsDualStackIPs(cfg.NodeIPs) + if err == nil && !dualStack { + argsMap["node-ip"] = cfg.NodeIP + } + } else { + // Cluster is using the embedded CCM, we know that the feature-gate will be enabled there as well. + argsMap["feature-gates"] = util.AddFeatureGate(argsMap["feature-gates"], "CloudDualStackNodeIPs=true") + if nodeIPs := util.JoinIPs(cfg.NodeIPs); nodeIPs != "" { + argsMap["node-ip"] = util.JoinIPs(cfg.NodeIPs) + } } argsMap["node-labels"] = strings.Join(cfg.NodeLabels, ",")