//go:build windows // +build windows package agent import ( "net" "path/filepath" "strings" "github.com/k3s-io/k3s/pkg/daemons/config" "github.com/k3s-io/k3s/pkg/util" "github.com/sirupsen/logrus" kubeletconfig "k8s.io/kubelet/config/v1beta1" utilsnet "k8s.io/utils/net" utilsptr "k8s.io/utils/ptr" ) const ( socketPrefix = "npipe://" ) func kubeProxyArgs(cfg *config.Agent) map[string]string { bindAddress := "127.0.0.1" if utilsnet.IsIPv6(net.ParseIP(cfg.NodeIP)) { bindAddress = "::1" } argsMap := map[string]string{ "proxy-mode": "kernelspace", "healthz-bind-address": bindAddress, "kubeconfig": cfg.KubeConfigKubeProxy, "cluster-cidr": util.JoinIPNets(cfg.ClusterCIDRs), } if cfg.NodeName != "" { argsMap["hostname-override"] = cfg.NodeName } return argsMap } // kubeletArgsAndConfig generates default kubelet args and configuration. // Kubelet config is frustratingly split across deprecated CLI flags that raise warnings if you use them, // and a structured configuration file that upstream does not provide a convienent way to initailize with default values. // The defaults and our desired config also vary by OS. func kubeletArgsAndConfig(cfg *config.Agent) (map[string]string, *kubeletconfig.KubeletConfiguration, error) { defaultConfig, err := defaultKubeletConfig(cfg) if err != nil { return nil, nil, err } argsMap := map[string]string{ "config-dir": cfg.KubeletConfigDir, "kubeconfig": cfg.KubeConfigKubelet, // note: KubeletConfiguration will omit this field when marshalling if it is set to 0, so we set it via CLI // https://github.com/k3s-io/k3s/issues/12164 "read-only-port": "0", } if cfg.RootDir != "" { argsMap["root-dir"] = cfg.RootDir argsMap["cert-dir"] = filepath.Join(cfg.RootDir, "pki") } if cfg.RuntimeSocket != "" { defaultConfig.SerializeImagePulls = utilsptr.To(false) // cadvisor wants the containerd CRI socket without the prefix, but kubelet wants it with the prefix if strings.HasPrefix(cfg.RuntimeSocket, socketPrefix) { defaultConfig.ContainerRuntimeEndpoint = cfg.RuntimeSocket } else { defaultConfig.ContainerRuntimeEndpoint = socketPrefix + cfg.RuntimeSocket } } if cfg.ImageServiceSocket != "" { if strings.HasPrefix(cfg.ImageServiceSocket, socketPrefix) { defaultConfig.ImageServiceEndpoint = cfg.ImageServiceSocket } else { defaultConfig.ImageServiceEndpoint = socketPrefix + cfg.ImageServiceSocket } } if cfg.NodeName != "" { argsMap["hostname-override"] = cfg.NodeName } // 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 { argsMap["cloud-provider"] = "external" if nodeIPs := util.JoinIPs(cfg.NodeIPs); nodeIPs != "" { argsMap["node-ip"] = util.JoinIPs(cfg.NodeIPs) } } argsMap["node-labels"] = strings.Join(cfg.NodeLabels, ",") if ImageCredProvAvailable(cfg) { logrus.Infof("Kubelet image credential provider bin dir and configuration file found.") argsMap["image-credential-provider-bin-dir"] = cfg.ImageCredProvBinDir argsMap["image-credential-provider-config"] = cfg.ImageCredProvConfig } return argsMap, defaultConfig, nil }