k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kube-proxy/app/server.go (about)

     1  /*
     2  Copyright 2014 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 app does all of the work necessary to configure and run a
    18  // Kubernetes app process.
    19  package app
    20  
    21  import (
    22  	"context"
    23  	goflag "flag"
    24  	"fmt"
    25  	"net"
    26  	"net/http"
    27  	"os"
    28  	"strings"
    29  	"time"
    30  
    31  	"github.com/fsnotify/fsnotify"
    32  	"github.com/spf13/cobra"
    33  	"github.com/spf13/pflag"
    34  
    35  	v1 "k8s.io/api/core/v1"
    36  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    37  	"k8s.io/apimachinery/pkg/fields"
    38  	"k8s.io/apimachinery/pkg/labels"
    39  	"k8s.io/apimachinery/pkg/runtime"
    40  	"k8s.io/apimachinery/pkg/runtime/serializer"
    41  	"k8s.io/apimachinery/pkg/selection"
    42  	"k8s.io/apimachinery/pkg/types"
    43  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    44  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    45  	"k8s.io/apimachinery/pkg/util/validation/field"
    46  	"k8s.io/apimachinery/pkg/util/wait"
    47  	"k8s.io/apiserver/pkg/server/healthz"
    48  	"k8s.io/apiserver/pkg/server/mux"
    49  	"k8s.io/apiserver/pkg/server/routes"
    50  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    51  	"k8s.io/client-go/informers"
    52  	clientset "k8s.io/client-go/kubernetes"
    53  	"k8s.io/client-go/rest"
    54  	"k8s.io/client-go/tools/clientcmd"
    55  	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
    56  	"k8s.io/client-go/tools/events"
    57  	cliflag "k8s.io/component-base/cli/flag"
    58  	componentbaseconfig "k8s.io/component-base/config"
    59  	"k8s.io/component-base/configz"
    60  	"k8s.io/component-base/logs"
    61  	logsapi "k8s.io/component-base/logs/api/v1"
    62  	"k8s.io/component-base/metrics"
    63  	metricsfeatures "k8s.io/component-base/metrics/features"
    64  	"k8s.io/component-base/metrics/legacyregistry"
    65  	"k8s.io/component-base/metrics/prometheus/slis"
    66  	"k8s.io/component-base/version"
    67  	"k8s.io/component-base/version/verflag"
    68  	nodeutil "k8s.io/component-helpers/node/util"
    69  	"k8s.io/klog/v2"
    70  	"k8s.io/kube-proxy/config/v1alpha1"
    71  	api "k8s.io/kubernetes/pkg/apis/core"
    72  	"k8s.io/kubernetes/pkg/cluster/ports"
    73  	"k8s.io/kubernetes/pkg/features"
    74  	"k8s.io/kubernetes/pkg/kubelet/qos"
    75  	"k8s.io/kubernetes/pkg/proxy"
    76  	"k8s.io/kubernetes/pkg/proxy/apis"
    77  	kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
    78  	proxyconfigscheme "k8s.io/kubernetes/pkg/proxy/apis/config/scheme"
    79  	kubeproxyconfigv1alpha1 "k8s.io/kubernetes/pkg/proxy/apis/config/v1alpha1"
    80  	"k8s.io/kubernetes/pkg/proxy/apis/config/validation"
    81  	"k8s.io/kubernetes/pkg/proxy/config"
    82  	"k8s.io/kubernetes/pkg/proxy/healthcheck"
    83  	proxymetrics "k8s.io/kubernetes/pkg/proxy/metrics"
    84  	proxyutil "k8s.io/kubernetes/pkg/proxy/util"
    85  	"k8s.io/kubernetes/pkg/util/filesystem"
    86  	utilflag "k8s.io/kubernetes/pkg/util/flag"
    87  	utilnode "k8s.io/kubernetes/pkg/util/node"
    88  	"k8s.io/kubernetes/pkg/util/oom"
    89  	netutils "k8s.io/utils/net"
    90  	"k8s.io/utils/ptr"
    91  )
    92  
    93  func init() {
    94  	utilruntime.Must(metricsfeatures.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
    95  	utilruntime.Must(logsapi.AddFeatureGates(utilfeature.DefaultMutableFeatureGate))
    96  }
    97  
    98  // proxyRun defines the interface to run a specified ProxyServer
    99  type proxyRun interface {
   100  	Run(ctx context.Context) error
   101  }
   102  
   103  // Options contains everything necessary to create and run a proxy server.
   104  type Options struct {
   105  	// ConfigFile is the location of the proxy server's configuration file.
   106  	ConfigFile string
   107  	// WriteConfigTo is the path where the default configuration will be written.
   108  	WriteConfigTo string
   109  	// CleanupAndExit, when true, makes the proxy server clean up iptables and ipvs rules, then exit.
   110  	CleanupAndExit bool
   111  	// InitAndExit, when true, makes the proxy server makes configurations that need privileged access, then exit.
   112  	InitAndExit bool
   113  	// WindowsService should be set to true if kube-proxy is running as a service on Windows.
   114  	// Its corresponding flag only gets registered in Windows builds
   115  	WindowsService bool
   116  	// config is the proxy server's configuration object.
   117  	config *kubeproxyconfig.KubeProxyConfiguration
   118  	// watcher is used to watch on the update change of ConfigFile
   119  	watcher filesystem.FSWatcher
   120  	// proxyServer is the interface to run the proxy server
   121  	proxyServer proxyRun
   122  	// errCh is the channel that errors will be sent
   123  	errCh chan error
   124  
   125  	// The fields below here are placeholders for flags that can't be directly mapped into
   126  	// config.KubeProxyConfiguration.
   127  	//
   128  	// TODO remove these fields once the deprecated flags are removed.
   129  
   130  	// master is used to override the kubeconfig's URL to the apiserver.
   131  	master string
   132  	// healthzPort is the port to be used by the healthz server.
   133  	healthzPort int32
   134  	// metricsPort is the port to be used by the metrics server.
   135  	metricsPort int32
   136  
   137  	// hostnameOverride, if set from the command line flag, takes precedence over the `HostnameOverride` value from the config file
   138  	hostnameOverride string
   139  
   140  	logger klog.Logger
   141  }
   142  
   143  // AddFlags adds flags to fs and binds them to options.
   144  func (o *Options) AddFlags(fs *pflag.FlagSet) {
   145  	o.addOSFlags(fs)
   146  
   147  	fs.StringVar(&o.ConfigFile, "config", o.ConfigFile, "The path to the configuration file.")
   148  	fs.StringVar(&o.WriteConfigTo, "write-config-to", o.WriteConfigTo, "If set, write the default configuration values to this file and exit.")
   149  
   150  	fs.BoolVar(&o.CleanupAndExit, "cleanup", o.CleanupAndExit, "If true cleanup iptables and ipvs rules and exit.")
   151  
   152  	fs.Var(cliflag.NewMapStringBool(&o.config.FeatureGates), "feature-gates", "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
   153  		"Options are:\n"+strings.Join(utilfeature.DefaultFeatureGate.KnownFeatures(), "\n")+"\n"+
   154  		"This parameter is ignored if a config file is specified by --config.")
   155  
   156  	fs.StringVar(&o.config.ClientConnection.Kubeconfig, "kubeconfig", o.config.ClientConnection.Kubeconfig, "Path to kubeconfig file with authorization information (the master location can be overridden by the master flag).")
   157  	fs.StringVar(&o.master, "master", o.master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
   158  	fs.StringVar(&o.config.ClientConnection.ContentType, "kube-api-content-type", o.config.ClientConnection.ContentType, "Content type of requests sent to apiserver.")
   159  	fs.Int32Var(&o.config.ClientConnection.Burst, "kube-api-burst", o.config.ClientConnection.Burst, "Burst to use while talking with kubernetes apiserver")
   160  	fs.Float32Var(&o.config.ClientConnection.QPS, "kube-api-qps", o.config.ClientConnection.QPS, "QPS to use while talking with kubernetes apiserver")
   161  
   162  	fs.StringVar(&o.hostnameOverride, "hostname-override", o.hostnameOverride, "If non-empty, will be used as the name of the Node that kube-proxy is running on. If unset, the node name is assumed to be the same as the node's hostname.")
   163  	fs.Var(&utilflag.IPVar{Val: &o.config.BindAddress}, "bind-address", "Overrides kube-proxy's idea of what its node's primary IP is. Note that the name is a historical artifact, and kube-proxy does not actually bind any sockets to this IP. This parameter is ignored if a config file is specified by --config.")
   164  	fs.Var(&utilflag.IPPortVar{Val: &o.config.HealthzBindAddress}, "healthz-bind-address", "The IP address and port for the health check server to serve on, defaulting to \"0.0.0.0:10256\". This parameter is ignored if a config file is specified by --config.")
   165  	fs.Var(&utilflag.IPPortVar{Val: &o.config.MetricsBindAddress}, "metrics-bind-address", "The IP address and port for the metrics server to serve on, defaulting to \"127.0.0.1:10249\". (Set to \"0.0.0.0:10249\" / \"[::]:10249\" to bind on all interfaces.) Set empty to disable. This parameter is ignored if a config file is specified by --config.")
   166  	fs.BoolVar(&o.config.BindAddressHardFail, "bind-address-hard-fail", o.config.BindAddressHardFail, "If true kube-proxy will treat failure to bind to a port as fatal and exit")
   167  	fs.BoolVar(&o.config.EnableProfiling, "profiling", o.config.EnableProfiling, "If true enables profiling via web interface on /debug/pprof handler. This parameter is ignored if a config file is specified by --config.")
   168  	fs.StringVar(&o.config.ShowHiddenMetricsForVersion, "show-hidden-metrics-for-version", o.config.ShowHiddenMetricsForVersion,
   169  		"The previous version for which you want to show hidden metrics. "+
   170  			"Only the previous minor version is meaningful, other values will not be allowed. "+
   171  			"The format is <major>.<minor>, e.g.: '1.16'. "+
   172  			"The purpose of this format is make sure you have the opportunity to notice if the next release hides additional metrics, "+
   173  			"rather than being surprised when they are permanently removed in the release after that. "+
   174  			"This parameter is ignored if a config file is specified by --config.")
   175  	fs.BoolVar(&o.InitAndExit, "init-only", o.InitAndExit, "If true, perform any initialization steps that must be done with full root privileges, and then exit. After doing this, you can run kube-proxy again with only the CAP_NET_ADMIN capability.")
   176  	fs.Var(&o.config.Mode, "proxy-mode", "Which proxy mode to use: on Linux this can be 'iptables' (default) or 'ipvs'. On Windows the only supported value is 'kernelspace'."+
   177  		"This parameter is ignored if a config file is specified by --config.")
   178  
   179  	fs.Int32Var(o.config.IPTables.MasqueradeBit, "iptables-masquerade-bit", ptr.Deref(o.config.IPTables.MasqueradeBit, 14), "If using the iptables or ipvs proxy mode, the bit of the fwmark space to mark packets requiring SNAT with.  Must be within the range [0, 31].")
   180  	fs.BoolVar(&o.config.IPTables.MasqueradeAll, "masquerade-all", o.config.IPTables.MasqueradeAll, "If using the iptables or ipvs proxy mode, SNAT all traffic sent via Service cluster IPs. This may be required with some CNI plugins.")
   181  	fs.BoolVar(o.config.IPTables.LocalhostNodePorts, "iptables-localhost-nodeports", ptr.Deref(o.config.IPTables.LocalhostNodePorts, true), "If false, kube-proxy will disable the legacy behavior of allowing NodePort services to be accessed via localhost. (Applies only to iptables mode and IPv4; localhost NodePorts are never allowed with other proxy modes or with IPv6.)")
   182  	fs.DurationVar(&o.config.IPTables.SyncPeriod.Duration, "iptables-sync-period", o.config.IPTables.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.")
   183  	fs.DurationVar(&o.config.IPTables.MinSyncPeriod.Duration, "iptables-min-sync-period", o.config.IPTables.MinSyncPeriod.Duration, "The minimum period between iptables rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate iptables resync.")
   184  
   185  	fs.DurationVar(&o.config.IPVS.SyncPeriod.Duration, "ipvs-sync-period", o.config.IPVS.SyncPeriod.Duration, "An interval (e.g. '5s', '1m', '2h22m') indicating how frequently various re-synchronizing and cleanup operations are performed. Must be greater than 0.")
   186  	fs.DurationVar(&o.config.IPVS.MinSyncPeriod.Duration, "ipvs-min-sync-period", o.config.IPVS.MinSyncPeriod.Duration, "The minimum period between IPVS rule resyncs (e.g. '5s', '1m', '2h22m'). A value of 0 means every Service or EndpointSlice change will result in an immediate IPVS resync.")
   187  	fs.StringVar(&o.config.IPVS.Scheduler, "ipvs-scheduler", o.config.IPVS.Scheduler, "The ipvs scheduler type when proxy mode is ipvs")
   188  	fs.StringSliceVar(&o.config.IPVS.ExcludeCIDRs, "ipvs-exclude-cidrs", o.config.IPVS.ExcludeCIDRs, "A comma-separated list of CIDRs which the ipvs proxier should not touch when cleaning up IPVS rules.")
   189  	fs.BoolVar(&o.config.IPVS.StrictARP, "ipvs-strict-arp", o.config.IPVS.StrictARP, "Enable strict ARP by setting arp_ignore to 1 and arp_announce to 2")
   190  	fs.DurationVar(&o.config.IPVS.TCPTimeout.Duration, "ipvs-tcp-timeout", o.config.IPVS.TCPTimeout.Duration, "The timeout for idle IPVS TCP connections, 0 to leave as-is. (e.g. '5s', '1m', '2h22m').")
   191  	fs.DurationVar(&o.config.IPVS.TCPFinTimeout.Duration, "ipvs-tcpfin-timeout", o.config.IPVS.TCPFinTimeout.Duration, "The timeout for IPVS TCP connections after receiving a FIN packet, 0 to leave as-is. (e.g. '5s', '1m', '2h22m').")
   192  	fs.DurationVar(&o.config.IPVS.UDPTimeout.Duration, "ipvs-udp-timeout", o.config.IPVS.UDPTimeout.Duration, "The timeout for IPVS UDP packets, 0 to leave as-is. (e.g. '5s', '1m', '2h22m').")
   193  
   194  	fs.Var(&o.config.DetectLocalMode, "detect-local-mode", "Mode to use to detect local traffic. This parameter is ignored if a config file is specified by --config.")
   195  	fs.StringVar(&o.config.DetectLocal.BridgeInterface, "pod-bridge-interface", o.config.DetectLocal.BridgeInterface, "A bridge interface name. When --detect-local-mode is set to BridgeInterface, kube-proxy will consider traffic to be local if it originates from this bridge.")
   196  	fs.StringVar(&o.config.DetectLocal.InterfaceNamePrefix, "pod-interface-name-prefix", o.config.DetectLocal.InterfaceNamePrefix, "An interface name prefix. When --detect-local-mode is set to InterfaceNamePrefix, kube-proxy will consider traffic to be local if it originates from any interface whose name begins with this prefix.")
   197  	fs.StringVar(&o.config.ClusterCIDR, "cluster-cidr", o.config.ClusterCIDR, "The CIDR range of the pods in the cluster. (For dual-stack clusters, this can be a comma-separated dual-stack pair of CIDR ranges.). When --detect-local-mode is set to ClusterCIDR, kube-proxy will consider traffic to be local if its source IP is in this range. (Otherwise it is not used.) "+
   198  		"This parameter is ignored if a config file is specified by --config.")
   199  
   200  	fs.StringSliceVar(&o.config.NodePortAddresses, "nodeport-addresses", o.config.NodePortAddresses,
   201  		"A list of CIDR ranges that contain valid node IPs, or alternatively, the single string 'primary'. If set to a list of CIDRs, connections to NodePort services will only be accepted on node IPs in one of the indicated ranges. If set to 'primary', NodePort services will only be accepted on the node's primary IP(s) according to the Node object. If unset, NodePort connections will be accepted on all local IPs. This parameter is ignored if a config file is specified by --config.")
   202  
   203  	fs.Int32Var(o.config.OOMScoreAdj, "oom-score-adj", ptr.Deref(o.config.OOMScoreAdj, int32(qos.KubeProxyOOMScoreAdj)), "The oom-score-adj value for kube-proxy process. Values must be within the range [-1000, 1000]. This parameter is ignored if a config file is specified by --config.")
   204  	fs.Int32Var(o.config.Conntrack.MaxPerCore, "conntrack-max-per-core", *o.config.Conntrack.MaxPerCore,
   205  		"Maximum number of NAT connections to track per CPU core (0 to leave the limit as-is and ignore conntrack-min).")
   206  	fs.Int32Var(o.config.Conntrack.Min, "conntrack-min", *o.config.Conntrack.Min,
   207  		"Minimum number of conntrack entries to allocate, regardless of conntrack-max-per-core (set conntrack-max-per-core=0 to leave the limit as-is).")
   208  
   209  	fs.DurationVar(&o.config.Conntrack.TCPEstablishedTimeout.Duration, "conntrack-tcp-timeout-established", o.config.Conntrack.TCPEstablishedTimeout.Duration, "Idle timeout for established TCP connections (0 to leave as-is)")
   210  	fs.DurationVar(
   211  		&o.config.Conntrack.TCPCloseWaitTimeout.Duration, "conntrack-tcp-timeout-close-wait",
   212  		o.config.Conntrack.TCPCloseWaitTimeout.Duration,
   213  		"NAT timeout for TCP connections in the CLOSE_WAIT state")
   214  	fs.BoolVar(&o.config.Conntrack.TCPBeLiberal, "conntrack-tcp-be-liberal", o.config.Conntrack.TCPBeLiberal, "Enable liberal mode for tracking TCP packets by setting nf_conntrack_tcp_be_liberal to 1")
   215  	fs.DurationVar(&o.config.Conntrack.UDPTimeout.Duration, "conntrack-udp-timeout", o.config.Conntrack.UDPTimeout.Duration, "Idle timeout for UNREPLIED UDP connections (0 to leave as-is)")
   216  	fs.DurationVar(&o.config.Conntrack.UDPStreamTimeout.Duration, "conntrack-udp-timeout-stream", o.config.Conntrack.UDPStreamTimeout.Duration, "Idle timeout for ASSURED UDP connections (0 to leave as-is)")
   217  
   218  	fs.DurationVar(&o.config.ConfigSyncPeriod.Duration, "config-sync-period", o.config.ConfigSyncPeriod.Duration, "How often configuration from the apiserver is refreshed.  Must be greater than 0.")
   219  
   220  	fs.Int32Var(&o.healthzPort, "healthz-port", o.healthzPort, "The port to bind the health check server. Use 0 to disable.")
   221  	_ = fs.MarkDeprecated("healthz-port", "This flag is deprecated and will be removed in a future release. Please use --healthz-bind-address instead.")
   222  	fs.Int32Var(&o.metricsPort, "metrics-port", o.metricsPort, "The port to bind the metrics server. Use 0 to disable.")
   223  	_ = fs.MarkDeprecated("metrics-port", "This flag is deprecated and will be removed in a future release. Please use --metrics-bind-address instead.")
   224  	fs.Var(utilflag.PortRangeVar{Val: &o.config.PortRange}, "proxy-port-range", "This was previously used to configure the userspace proxy, but is now unused.")
   225  	_ = fs.MarkDeprecated("proxy-port-range", "This flag has no effect and will be removed in a future release.")
   226  
   227  	logsapi.AddFlags(&o.config.Logging, fs)
   228  }
   229  
   230  // newKubeProxyConfiguration returns a KubeProxyConfiguration with default values
   231  func newKubeProxyConfiguration() *kubeproxyconfig.KubeProxyConfiguration {
   232  	versionedConfig := &v1alpha1.KubeProxyConfiguration{}
   233  	proxyconfigscheme.Scheme.Default(versionedConfig)
   234  	internalConfig, err := proxyconfigscheme.Scheme.ConvertToVersion(versionedConfig, kubeproxyconfig.SchemeGroupVersion)
   235  	if err != nil {
   236  		panic(fmt.Sprintf("Unable to create default config: %v", err))
   237  	}
   238  
   239  	return internalConfig.(*kubeproxyconfig.KubeProxyConfiguration)
   240  }
   241  
   242  // NewOptions returns initialized Options
   243  func NewOptions() *Options {
   244  	return &Options{
   245  		config:      newKubeProxyConfiguration(),
   246  		healthzPort: ports.ProxyHealthzPort,
   247  		metricsPort: ports.ProxyStatusPort,
   248  		errCh:       make(chan error),
   249  		logger:      klog.FromContext(context.Background()),
   250  	}
   251  }
   252  
   253  // Complete completes all the required options.
   254  func (o *Options) Complete(fs *pflag.FlagSet) error {
   255  	if len(o.ConfigFile) == 0 && len(o.WriteConfigTo) == 0 {
   256  		o.config.HealthzBindAddress = addressFromDeprecatedFlags(o.config.HealthzBindAddress, o.healthzPort)
   257  		o.config.MetricsBindAddress = addressFromDeprecatedFlags(o.config.MetricsBindAddress, o.metricsPort)
   258  	}
   259  
   260  	// Load the config file here in Complete, so that Validate validates the fully-resolved config.
   261  	if len(o.ConfigFile) > 0 {
   262  		c, err := o.loadConfigFromFile(o.ConfigFile)
   263  		if err != nil {
   264  			return err
   265  		}
   266  
   267  		// Before we overwrite the config which holds the parsed
   268  		// command line parameters, we need to copy all modified
   269  		// logging settings over to the loaded config (i.e.  logging
   270  		// command line flags have priority). Otherwise `--config
   271  		// ... -v=5` doesn't work (config resets verbosity even
   272  		// when it contains no logging settings).
   273  		copyLogsFromFlags(fs, &c.Logging)
   274  		o.config = c
   275  
   276  		if err := o.initWatcher(); err != nil {
   277  			return err
   278  		}
   279  	}
   280  
   281  	o.platformApplyDefaults(o.config)
   282  
   283  	if err := o.processHostnameOverrideFlag(); err != nil {
   284  		return err
   285  	}
   286  
   287  	return utilfeature.DefaultMutableFeatureGate.SetFromMap(o.config.FeatureGates)
   288  }
   289  
   290  // copyLogsFromFlags applies the logging flags from the given flag set to the given
   291  // configuration. Fields for which the corresponding flag was not used are left
   292  // unmodified. For fields that have multiple values (like vmodule), the values from
   293  // the flags get joined so that the command line flags have priority.
   294  //
   295  // TODO (pohly): move this to logsapi
   296  func copyLogsFromFlags(from *pflag.FlagSet, to *logsapi.LoggingConfiguration) error {
   297  	var cloneFS pflag.FlagSet
   298  	logsapi.AddFlags(to, &cloneFS)
   299  	vmodule := to.VModule
   300  	to.VModule = nil
   301  	var err error
   302  	cloneFS.VisitAll(func(f *pflag.Flag) {
   303  		if err != nil {
   304  			return
   305  		}
   306  		fsFlag := from.Lookup(f.Name)
   307  		if fsFlag == nil {
   308  			err = fmt.Errorf("logging flag %s not found in flag set", f.Name)
   309  			return
   310  		}
   311  		if !fsFlag.Changed {
   312  			return
   313  		}
   314  		if setErr := f.Value.Set(fsFlag.Value.String()); setErr != nil {
   315  			err = fmt.Errorf("copying flag %s value: %v", f.Name, setErr)
   316  			return
   317  		}
   318  	})
   319  	to.VModule = append(to.VModule, vmodule...)
   320  	return err
   321  }
   322  
   323  // Creates a new filesystem watcher and adds watches for the config file.
   324  func (o *Options) initWatcher() error {
   325  	fswatcher := filesystem.NewFsnotifyWatcher()
   326  	err := fswatcher.Init(o.eventHandler, o.errorHandler)
   327  	if err != nil {
   328  		return err
   329  	}
   330  	err = fswatcher.AddWatch(o.ConfigFile)
   331  	if err != nil {
   332  		return err
   333  	}
   334  	o.watcher = fswatcher
   335  	return nil
   336  }
   337  
   338  func (o *Options) eventHandler(ent fsnotify.Event) {
   339  	if ent.Has(fsnotify.Write) || ent.Has(fsnotify.Rename) {
   340  		// error out when ConfigFile is updated
   341  		o.errCh <- fmt.Errorf("content of the proxy server's configuration file was updated")
   342  		return
   343  	}
   344  	o.errCh <- nil
   345  }
   346  
   347  func (o *Options) errorHandler(err error) {
   348  	o.errCh <- err
   349  }
   350  
   351  // processHostnameOverrideFlag processes hostname-override flag
   352  func (o *Options) processHostnameOverrideFlag() error {
   353  	// Check if hostname-override flag is set and use value since configFile always overrides
   354  	if len(o.hostnameOverride) > 0 {
   355  		hostName := strings.TrimSpace(o.hostnameOverride)
   356  		if len(hostName) == 0 {
   357  			return fmt.Errorf("empty hostname-override is invalid")
   358  		}
   359  		o.config.HostnameOverride = strings.ToLower(hostName)
   360  	}
   361  
   362  	return nil
   363  }
   364  
   365  // Validate validates all the required options.
   366  func (o *Options) Validate() error {
   367  	if errs := validation.Validate(o.config); len(errs) != 0 {
   368  		return errs.ToAggregate()
   369  	}
   370  
   371  	return nil
   372  }
   373  
   374  // Run runs the specified ProxyServer.
   375  func (o *Options) Run(ctx context.Context) error {
   376  	defer close(o.errCh)
   377  	if len(o.WriteConfigTo) > 0 {
   378  		return o.writeConfigFile()
   379  	}
   380  
   381  	err := platformCleanup(ctx, o.config.Mode, o.CleanupAndExit)
   382  	if o.CleanupAndExit {
   383  		return err
   384  	}
   385  	// We ignore err otherwise; the cleanup is best-effort, and the backends will have
   386  	// logged messages if they failed in interesting ways.
   387  
   388  	proxyServer, err := newProxyServer(ctx, o.config, o.master, o.InitAndExit)
   389  	if err != nil {
   390  		return err
   391  	}
   392  	if o.InitAndExit {
   393  		return nil
   394  	}
   395  
   396  	o.proxyServer = proxyServer
   397  	return o.runLoop(ctx)
   398  }
   399  
   400  // runLoop will watch on the update change of the proxy server's configuration file.
   401  // Return an error when updated
   402  func (o *Options) runLoop(ctx context.Context) error {
   403  	if o.watcher != nil {
   404  		o.watcher.Run()
   405  	}
   406  
   407  	// run the proxy in goroutine
   408  	go func() {
   409  		err := o.proxyServer.Run(ctx)
   410  		o.errCh <- err
   411  	}()
   412  
   413  	for {
   414  		err := <-o.errCh
   415  		if err != nil {
   416  			return err
   417  		}
   418  	}
   419  }
   420  
   421  func (o *Options) writeConfigFile() (err error) {
   422  	const mediaType = runtime.ContentTypeYAML
   423  	info, ok := runtime.SerializerInfoForMediaType(proxyconfigscheme.Codecs.SupportedMediaTypes(), mediaType)
   424  	if !ok {
   425  		return fmt.Errorf("unable to locate encoder -- %q is not a supported media type", mediaType)
   426  	}
   427  
   428  	encoder := proxyconfigscheme.Codecs.EncoderForVersion(info.Serializer, v1alpha1.SchemeGroupVersion)
   429  
   430  	configFile, err := os.Create(o.WriteConfigTo)
   431  	if err != nil {
   432  		return err
   433  	}
   434  
   435  	defer func() {
   436  		ferr := configFile.Close()
   437  		if ferr != nil && err == nil {
   438  			err = ferr
   439  		}
   440  	}()
   441  
   442  	if err = encoder.Encode(o.config, configFile); err != nil {
   443  		return err
   444  	}
   445  
   446  	o.logger.Info("Wrote configuration", "file", o.WriteConfigTo)
   447  
   448  	return nil
   449  }
   450  
   451  // addressFromDeprecatedFlags returns server address from flags
   452  // passed on the command line based on the following rules:
   453  // 1. If port is 0, disable the server (e.g. set address to empty).
   454  // 2. Otherwise, set the port portion of the config accordingly.
   455  func addressFromDeprecatedFlags(addr string, port int32) string {
   456  	if port == 0 {
   457  		return ""
   458  	}
   459  	return proxyutil.AppendPortIfNeeded(addr, port)
   460  }
   461  
   462  // newLenientSchemeAndCodecs returns a scheme that has only v1alpha1 registered into
   463  // it and a CodecFactory with strict decoding disabled.
   464  func newLenientSchemeAndCodecs() (*runtime.Scheme, *serializer.CodecFactory, error) {
   465  	lenientScheme := runtime.NewScheme()
   466  	if err := kubeproxyconfig.AddToScheme(lenientScheme); err != nil {
   467  		return nil, nil, fmt.Errorf("failed to add kube-proxy config API to lenient scheme: %v", err)
   468  	}
   469  	if err := kubeproxyconfigv1alpha1.AddToScheme(lenientScheme); err != nil {
   470  		return nil, nil, fmt.Errorf("failed to add kube-proxy config v1alpha1 API to lenient scheme: %v", err)
   471  	}
   472  	lenientCodecs := serializer.NewCodecFactory(lenientScheme, serializer.DisableStrict)
   473  	return lenientScheme, &lenientCodecs, nil
   474  }
   475  
   476  // loadConfigFromFile loads the contents of file and decodes it as a
   477  // KubeProxyConfiguration object.
   478  func (o *Options) loadConfigFromFile(file string) (*kubeproxyconfig.KubeProxyConfiguration, error) {
   479  	data, err := os.ReadFile(file)
   480  	if err != nil {
   481  		return nil, err
   482  	}
   483  
   484  	return o.loadConfig(data)
   485  }
   486  
   487  // loadConfig decodes a serialized KubeProxyConfiguration to the internal type.
   488  func (o *Options) loadConfig(data []byte) (*kubeproxyconfig.KubeProxyConfiguration, error) {
   489  
   490  	configObj, gvk, err := proxyconfigscheme.Codecs.UniversalDecoder().Decode(data, nil, nil)
   491  	if err != nil {
   492  		// Try strict decoding first. If that fails decode with a lenient
   493  		// decoder, which has only v1alpha1 registered, and log a warning.
   494  		// The lenient path is to be dropped when support for v1alpha1 is dropped.
   495  		if !runtime.IsStrictDecodingError(err) {
   496  			return nil, fmt.Errorf("failed to decode: %w", err)
   497  		}
   498  
   499  		_, lenientCodecs, lenientErr := newLenientSchemeAndCodecs()
   500  		if lenientErr != nil {
   501  			return nil, lenientErr
   502  		}
   503  
   504  		configObj, gvk, lenientErr = lenientCodecs.UniversalDecoder().Decode(data, nil, nil)
   505  		if lenientErr != nil {
   506  			// Lenient decoding failed with the current version, return the
   507  			// original strict error.
   508  			return nil, fmt.Errorf("failed lenient decoding: %v", err)
   509  		}
   510  
   511  		// Continue with the v1alpha1 object that was decoded leniently, but emit a warning.
   512  		o.logger.Info("Using lenient decoding as strict decoding failed", "err", err)
   513  	}
   514  
   515  	proxyConfig, ok := configObj.(*kubeproxyconfig.KubeProxyConfiguration)
   516  	if !ok {
   517  		return nil, fmt.Errorf("got unexpected config type: %v", gvk)
   518  	}
   519  	return proxyConfig, nil
   520  }
   521  
   522  // NewProxyCommand creates a *cobra.Command object with default parameters
   523  func NewProxyCommand() *cobra.Command {
   524  	opts := NewOptions()
   525  
   526  	cmd := &cobra.Command{
   527  		Use: "kube-proxy",
   528  		Long: `The Kubernetes network proxy runs on each node. This
   529  reflects services as defined in the Kubernetes API on each node and can do simple
   530  TCP, UDP, and SCTP stream forwarding or round robin TCP, UDP, and SCTP forwarding across a set of backends.
   531  Service cluster IPs and ports are currently found through Docker-links-compatible
   532  environment variables specifying ports opened by the service proxy. There is an optional
   533  addon that provides cluster DNS for these cluster IPs. The user must create a service
   534  with the apiserver API to configure the proxy.`,
   535  		RunE: func(cmd *cobra.Command, args []string) error {
   536  			verflag.PrintAndExitIfRequested()
   537  
   538  			if err := initForOS(opts.WindowsService); err != nil {
   539  				return fmt.Errorf("failed os init: %w", err)
   540  			}
   541  
   542  			if err := opts.Complete(cmd.Flags()); err != nil {
   543  				return fmt.Errorf("failed complete: %w", err)
   544  			}
   545  
   546  			logs.InitLogs()
   547  			if err := logsapi.ValidateAndApplyAsField(&opts.config.Logging, utilfeature.DefaultFeatureGate, field.NewPath("logging")); err != nil {
   548  				return fmt.Errorf("initialize logging: %v", err)
   549  			}
   550  
   551  			cliflag.PrintFlags(cmd.Flags())
   552  
   553  			if err := opts.Validate(); err != nil {
   554  				return fmt.Errorf("failed validate: %w", err)
   555  			}
   556  			// add feature enablement metrics
   557  			utilfeature.DefaultMutableFeatureGate.AddMetrics()
   558  			if err := opts.Run(context.Background()); err != nil {
   559  				opts.logger.Error(err, "Error running ProxyServer")
   560  				return err
   561  			}
   562  
   563  			return nil
   564  		},
   565  		Args: func(cmd *cobra.Command, args []string) error {
   566  			for _, arg := range args {
   567  				if len(arg) > 0 {
   568  					return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
   569  				}
   570  			}
   571  			return nil
   572  		},
   573  	}
   574  
   575  	fs := cmd.Flags()
   576  	opts.AddFlags(fs)
   577  	fs.AddGoFlagSet(goflag.CommandLine) // for --boot-id-file and --machine-id-file
   578  
   579  	_ = cmd.MarkFlagFilename("config", "yaml", "yml", "json")
   580  
   581  	return cmd
   582  }
   583  
   584  // ProxyServer represents all the parameters required to start the Kubernetes proxy server. All
   585  // fields are required.
   586  type ProxyServer struct {
   587  	Config *kubeproxyconfig.KubeProxyConfiguration
   588  
   589  	Client          clientset.Interface
   590  	Broadcaster     events.EventBroadcaster
   591  	Recorder        events.EventRecorder
   592  	NodeRef         *v1.ObjectReference
   593  	HealthzServer   *healthcheck.ProxierHealthServer
   594  	Hostname        string
   595  	PrimaryIPFamily v1.IPFamily
   596  	NodeIPs         map[v1.IPFamily]net.IP
   597  
   598  	podCIDRs []string // only used for LocalModeNodeCIDR
   599  
   600  	Proxier proxy.Provider
   601  }
   602  
   603  // newProxyServer creates a ProxyServer based on the given config
   604  func newProxyServer(ctx context.Context, config *kubeproxyconfig.KubeProxyConfiguration, master string, initOnly bool) (*ProxyServer, error) {
   605  	logger := klog.FromContext(ctx)
   606  
   607  	s := &ProxyServer{
   608  		Config: config,
   609  	}
   610  
   611  	cz, err := configz.New(kubeproxyconfig.GroupName)
   612  	if err != nil {
   613  		return nil, fmt.Errorf("unable to register configz: %s", err)
   614  	}
   615  	cz.Set(config)
   616  
   617  	if len(config.ShowHiddenMetricsForVersion) > 0 {
   618  		metrics.SetShowHidden()
   619  	}
   620  
   621  	s.Hostname, err = nodeutil.GetHostname(config.HostnameOverride)
   622  	if err != nil {
   623  		return nil, err
   624  	}
   625  
   626  	s.Client, err = createClient(ctx, config.ClientConnection, master)
   627  	if err != nil {
   628  		return nil, err
   629  	}
   630  
   631  	rawNodeIPs := getNodeIPs(ctx, s.Client, s.Hostname)
   632  	s.PrimaryIPFamily, s.NodeIPs = detectNodeIPs(ctx, rawNodeIPs, config.BindAddress)
   633  
   634  	if len(config.NodePortAddresses) == 1 && config.NodePortAddresses[0] == kubeproxyconfig.NodePortAddressesPrimary {
   635  		var nodePortAddresses []string
   636  		if nodeIP := s.NodeIPs[v1.IPv4Protocol]; nodeIP != nil && !nodeIP.IsLoopback() {
   637  			nodePortAddresses = append(nodePortAddresses, fmt.Sprintf("%s/32", nodeIP.String()))
   638  		}
   639  		if nodeIP := s.NodeIPs[v1.IPv6Protocol]; nodeIP != nil && !nodeIP.IsLoopback() {
   640  			nodePortAddresses = append(nodePortAddresses, fmt.Sprintf("%s/128", nodeIP.String()))
   641  		}
   642  		config.NodePortAddresses = nodePortAddresses
   643  	}
   644  
   645  	s.Broadcaster = events.NewBroadcaster(&events.EventSinkImpl{Interface: s.Client.EventsV1()})
   646  	s.Recorder = s.Broadcaster.NewRecorder(proxyconfigscheme.Scheme, "kube-proxy")
   647  
   648  	s.NodeRef = &v1.ObjectReference{
   649  		Kind:      "Node",
   650  		Name:      s.Hostname,
   651  		UID:       types.UID(s.Hostname),
   652  		Namespace: "",
   653  	}
   654  
   655  	if len(config.HealthzBindAddress) > 0 {
   656  		s.HealthzServer = healthcheck.NewProxierHealthServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration)
   657  	}
   658  
   659  	err = s.platformSetup(ctx)
   660  	if err != nil {
   661  		return nil, err
   662  	}
   663  
   664  	err = checkBadConfig(s)
   665  	if err != nil {
   666  		logger.Error(err, "Kube-proxy configuration may be incomplete or incorrect")
   667  	}
   668  
   669  	ipv4Supported, ipv6Supported, dualStackSupported, err := s.platformCheckSupported(ctx)
   670  	if err != nil {
   671  		return nil, err
   672  	} else if (s.PrimaryIPFamily == v1.IPv4Protocol && !ipv4Supported) || (s.PrimaryIPFamily == v1.IPv6Protocol && !ipv6Supported) {
   673  		return nil, fmt.Errorf("no support for primary IP family %q", s.PrimaryIPFamily)
   674  	} else if dualStackSupported {
   675  		logger.Info("kube-proxy running in dual-stack mode", "primary ipFamily", s.PrimaryIPFamily)
   676  	} else {
   677  		logger.Info("kube-proxy running in single-stack mode", "ipFamily", s.PrimaryIPFamily)
   678  	}
   679  
   680  	err, fatal := checkBadIPConfig(s, dualStackSupported)
   681  	if err != nil {
   682  		if fatal {
   683  			return nil, fmt.Errorf("kube-proxy configuration is incorrect: %v", err)
   684  		}
   685  		logger.Error(err, "Kube-proxy configuration may be incomplete or incorrect")
   686  	}
   687  
   688  	s.Proxier, err = s.createProxier(ctx, config, dualStackSupported, initOnly)
   689  	if err != nil {
   690  		return nil, err
   691  	}
   692  
   693  	return s, nil
   694  }
   695  
   696  // checkBadConfig checks for bad/deprecated configuation
   697  func checkBadConfig(s *ProxyServer) error {
   698  	var errors []error
   699  
   700  	// At this point we haven't seen any actual Services or EndpointSlices, so we
   701  	// don't really know if the cluster is expected to be single- or dual-stack. But
   702  	// we can at least take note of whether there is any explicitly-dual-stack
   703  	// configuration.
   704  	anyDualStackConfig := false
   705  	clusterCIDRs := strings.Split(s.Config.ClusterCIDR, ",")
   706  	for _, config := range [][]string{clusterCIDRs, s.Config.NodePortAddresses, s.Config.IPVS.ExcludeCIDRs, s.podCIDRs} {
   707  		if dual, _ := netutils.IsDualStackCIDRStrings(config); dual {
   708  			anyDualStackConfig = true
   709  			break
   710  		}
   711  	}
   712  
   713  	// Warn if NodePortAddresses does not limit connections on all IP families that
   714  	// seem to be in use.
   715  	cidrsByFamily := proxyutil.MapCIDRsByIPFamily(s.Config.NodePortAddresses)
   716  	if len(s.Config.NodePortAddresses) == 0 {
   717  		errors = append(errors, fmt.Errorf("nodePortAddresses is unset; NodePort connections will be accepted on all local IPs. Consider using `--nodeport-addresses primary`"))
   718  	} else if anyDualStackConfig && len(cidrsByFamily[s.PrimaryIPFamily]) == len(s.Config.NodePortAddresses) {
   719  		errors = append(errors, fmt.Errorf("cluster appears to be dual-stack but nodePortAddresses contains only %s addresses; NodePort connections will be accepted on all local %s IPs", s.PrimaryIPFamily, proxyutil.OtherIPFamily(s.PrimaryIPFamily)))
   720  	} else if len(cidrsByFamily[s.PrimaryIPFamily]) == 0 {
   721  		errors = append(errors, fmt.Errorf("cluster appears to be %s-primary but nodePortAddresses contains only %s addresses; NodePort connections will be accepted on all local %s IPs", s.PrimaryIPFamily, proxyutil.OtherIPFamily(s.PrimaryIPFamily), s.PrimaryIPFamily))
   722  	}
   723  
   724  	return utilerrors.NewAggregate(errors)
   725  }
   726  
   727  // checkBadIPConfig checks for bad configuration relative to s.PrimaryIPFamily.
   728  // Historically, we did not check most of the config options, so we cannot retroactively
   729  // make IP family mismatches in those options be fatal. When we add new options to check
   730  // here, we should make problems with those options be fatal.
   731  func checkBadIPConfig(s *ProxyServer, dualStackSupported bool) (err error, fatal bool) {
   732  	var errors []error
   733  	var badFamily netutils.IPFamily
   734  
   735  	if s.PrimaryIPFamily == v1.IPv4Protocol {
   736  		badFamily = netutils.IPv6
   737  	} else {
   738  		badFamily = netutils.IPv4
   739  	}
   740  
   741  	var clusterType string
   742  	if dualStackSupported {
   743  		clusterType = fmt.Sprintf("%s-primary", s.PrimaryIPFamily)
   744  	} else {
   745  		clusterType = fmt.Sprintf("%s-only", s.PrimaryIPFamily)
   746  	}
   747  
   748  	if s.Config.ClusterCIDR != "" {
   749  		clusterCIDRs := strings.Split(s.Config.ClusterCIDR, ",")
   750  		if badCIDRs(clusterCIDRs, badFamily) {
   751  			errors = append(errors, fmt.Errorf("cluster is %s but clusterCIDRs contains only IPv%s addresses", clusterType, badFamily))
   752  			if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeClusterCIDR && !dualStackSupported {
   753  				// This has always been a fatal error
   754  				fatal = true
   755  			}
   756  		}
   757  	}
   758  
   759  	if badCIDRs(s.podCIDRs, badFamily) {
   760  		errors = append(errors, fmt.Errorf("cluster is %s but node.spec.podCIDRs contains only IPv%s addresses", clusterType, badFamily))
   761  		if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeNodeCIDR {
   762  			// This has always been a fatal error
   763  			fatal = true
   764  		}
   765  	}
   766  
   767  	if netutils.IPFamilyOfString(s.Config.Winkernel.SourceVip) == badFamily {
   768  		errors = append(errors, fmt.Errorf("cluster is %s but winkernel.sourceVip is IPv%s", clusterType, badFamily))
   769  	}
   770  
   771  	// In some cases, wrong-IP-family is only a problem when the secondary IP family
   772  	// isn't present at all.
   773  	if !dualStackSupported {
   774  		if badCIDRs(s.Config.IPVS.ExcludeCIDRs, badFamily) {
   775  			errors = append(errors, fmt.Errorf("cluster is %s but ipvs.excludeCIDRs contains only IPv%s addresses", clusterType, badFamily))
   776  		}
   777  
   778  		if badBindAddress(s.Config.HealthzBindAddress, badFamily) {
   779  			errors = append(errors, fmt.Errorf("cluster is %s but healthzBindAddress is IPv%s", clusterType, badFamily))
   780  		}
   781  		if badBindAddress(s.Config.MetricsBindAddress, badFamily) {
   782  			errors = append(errors, fmt.Errorf("cluster is %s but metricsBindAddress is IPv%s", clusterType, badFamily))
   783  		}
   784  	}
   785  
   786  	// Note that s.Config.NodePortAddresses gets checked as part of checkBadConfig()
   787  	// so it doesn't need to be checked here.
   788  
   789  	return utilerrors.NewAggregate(errors), fatal
   790  }
   791  
   792  // badCIDRs returns true if cidrs is a non-empty list of CIDRs, all of wrongFamily.
   793  func badCIDRs(cidrs []string, wrongFamily netutils.IPFamily) bool {
   794  	if len(cidrs) == 0 {
   795  		return false
   796  	}
   797  	for _, cidr := range cidrs {
   798  		if netutils.IPFamilyOfCIDRString(cidr) != wrongFamily {
   799  			return false
   800  		}
   801  	}
   802  	return true
   803  }
   804  
   805  // badBindAddress returns true if bindAddress is an "IP:port" string where IP is a
   806  // non-zero IP of wrongFamily.
   807  func badBindAddress(bindAddress string, wrongFamily netutils.IPFamily) bool {
   808  	if host, _, _ := net.SplitHostPort(bindAddress); host != "" {
   809  		ip := netutils.ParseIPSloppy(host)
   810  		if ip != nil && netutils.IPFamilyOf(ip) == wrongFamily && !ip.IsUnspecified() {
   811  			return true
   812  		}
   813  	}
   814  	return false
   815  }
   816  
   817  // createClient creates a kube client from the given config and masterOverride.
   818  // TODO remove masterOverride when CLI flags are removed.
   819  func createClient(ctx context.Context, config componentbaseconfig.ClientConnectionConfiguration, masterOverride string) (clientset.Interface, error) {
   820  	logger := klog.FromContext(ctx)
   821  	var kubeConfig *rest.Config
   822  	var err error
   823  
   824  	if len(config.Kubeconfig) == 0 && len(masterOverride) == 0 {
   825  		logger.Info("Neither kubeconfig file nor master URL was specified, falling back to in-cluster config")
   826  		kubeConfig, err = rest.InClusterConfig()
   827  	} else {
   828  		// This creates a client, first loading any specified kubeconfig
   829  		// file, and then overriding the Master flag, if non-empty.
   830  		kubeConfig, err = clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
   831  			&clientcmd.ClientConfigLoadingRules{ExplicitPath: config.Kubeconfig},
   832  			&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: masterOverride}}).ClientConfig()
   833  	}
   834  	if err != nil {
   835  		return nil, err
   836  	}
   837  
   838  	kubeConfig.AcceptContentTypes = config.AcceptContentTypes
   839  	kubeConfig.ContentType = config.ContentType
   840  	kubeConfig.QPS = config.QPS
   841  	kubeConfig.Burst = int(config.Burst)
   842  
   843  	client, err := clientset.NewForConfig(kubeConfig)
   844  	if err != nil {
   845  		return nil, err
   846  	}
   847  
   848  	return client, nil
   849  }
   850  
   851  func serveHealthz(ctx context.Context, hz *healthcheck.ProxierHealthServer, errCh chan error) {
   852  	logger := klog.FromContext(ctx)
   853  	if hz == nil {
   854  		return
   855  	}
   856  
   857  	fn := func() {
   858  		err := hz.Run()
   859  		if err != nil {
   860  			logger.Error(err, "Healthz server failed")
   861  			if errCh != nil {
   862  				errCh <- fmt.Errorf("healthz server failed: %v", err)
   863  				// if in hardfail mode, never retry again
   864  				blockCh := make(chan error)
   865  				<-blockCh
   866  			}
   867  		} else {
   868  			logger.Error(nil, "Healthz server returned without error")
   869  		}
   870  	}
   871  	go wait.Until(fn, 5*time.Second, ctx.Done())
   872  }
   873  
   874  func serveMetrics(bindAddress string, proxyMode kubeproxyconfig.ProxyMode, enableProfiling bool, errCh chan error) {
   875  	if len(bindAddress) == 0 {
   876  		return
   877  	}
   878  
   879  	proxyMux := mux.NewPathRecorderMux("kube-proxy")
   880  	healthz.InstallHandler(proxyMux)
   881  	slis.SLIMetricsWithReset{}.Install(proxyMux)
   882  
   883  	proxyMux.HandleFunc("/proxyMode", func(w http.ResponseWriter, r *http.Request) {
   884  		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
   885  		w.Header().Set("X-Content-Type-Options", "nosniff")
   886  		fmt.Fprintf(w, "%s", proxyMode)
   887  	})
   888  
   889  	proxyMux.Handle("/metrics", legacyregistry.Handler())
   890  
   891  	if enableProfiling {
   892  		routes.Profiling{}.Install(proxyMux)
   893  		routes.DebugFlags{}.Install(proxyMux, "v", routes.StringFlagPutHandler(logs.GlogSetter))
   894  	}
   895  
   896  	configz.InstallHandler(proxyMux)
   897  
   898  	fn := func() {
   899  		err := http.ListenAndServe(bindAddress, proxyMux)
   900  		if err != nil {
   901  			err = fmt.Errorf("starting metrics server failed: %v", err)
   902  			utilruntime.HandleError(err)
   903  			if errCh != nil {
   904  				errCh <- err
   905  				// if in hardfail mode, never retry again
   906  				blockCh := make(chan error)
   907  				<-blockCh
   908  			}
   909  		}
   910  	}
   911  	go wait.Until(fn, 5*time.Second, wait.NeverStop)
   912  }
   913  
   914  // Run runs the specified ProxyServer.  This should never exit (unless CleanupAndExit is set).
   915  // TODO: At the moment, Run() cannot return a nil error, otherwise it's caller will never exit. Update callers of Run to handle nil errors.
   916  func (s *ProxyServer) Run(ctx context.Context) error {
   917  	logger := klog.FromContext(ctx)
   918  	// To help debugging, immediately log version
   919  	logger.Info("Version info", "version", version.Get())
   920  
   921  	logger.Info("Golang settings", "GOGC", os.Getenv("GOGC"), "GOMAXPROCS", os.Getenv("GOMAXPROCS"), "GOTRACEBACK", os.Getenv("GOTRACEBACK"))
   922  
   923  	proxymetrics.RegisterMetrics(s.Config.Mode)
   924  
   925  	// TODO(vmarmol): Use container config for this.
   926  	var oomAdjuster *oom.OOMAdjuster
   927  	if s.Config.OOMScoreAdj != nil {
   928  		oomAdjuster = oom.NewOOMAdjuster()
   929  		if err := oomAdjuster.ApplyOOMScoreAdj(0, int(*s.Config.OOMScoreAdj)); err != nil {
   930  			logger.V(2).Info("Failed to apply OOMScore", "err", err)
   931  		}
   932  	}
   933  
   934  	if s.Broadcaster != nil {
   935  		stopCh := make(chan struct{})
   936  		s.Broadcaster.StartRecordingToSink(stopCh)
   937  	}
   938  
   939  	// TODO(thockin): make it possible for healthz and metrics to be on the same port.
   940  
   941  	var healthzErrCh, metricsErrCh chan error
   942  	if s.Config.BindAddressHardFail {
   943  		healthzErrCh = make(chan error)
   944  		metricsErrCh = make(chan error)
   945  	}
   946  
   947  	// Start up a healthz server if requested
   948  	serveHealthz(ctx, s.HealthzServer, healthzErrCh)
   949  
   950  	// Start up a metrics server if requested
   951  	serveMetrics(s.Config.MetricsBindAddress, s.Config.Mode, s.Config.EnableProfiling, metricsErrCh)
   952  
   953  	noProxyName, err := labels.NewRequirement(apis.LabelServiceProxyName, selection.DoesNotExist, nil)
   954  	if err != nil {
   955  		return err
   956  	}
   957  
   958  	noHeadlessEndpoints, err := labels.NewRequirement(v1.IsHeadlessService, selection.DoesNotExist, nil)
   959  	if err != nil {
   960  		return err
   961  	}
   962  
   963  	labelSelector := labels.NewSelector()
   964  	labelSelector = labelSelector.Add(*noProxyName, *noHeadlessEndpoints)
   965  
   966  	// Make informers that filter out objects that want a non-default service proxy.
   967  	informerFactory := informers.NewSharedInformerFactoryWithOptions(s.Client, s.Config.ConfigSyncPeriod.Duration,
   968  		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
   969  			options.LabelSelector = labelSelector.String()
   970  		}))
   971  
   972  	// Create configs (i.e. Watches for Services, EndpointSlices and ServiceCIDRs)
   973  	// Note: RegisterHandler() calls need to happen before creation of Sources because sources
   974  	// only notify on changes, and the initial update (on process start) may be lost if no handlers
   975  	// are registered yet.
   976  	serviceConfig := config.NewServiceConfig(ctx, informerFactory.Core().V1().Services(), s.Config.ConfigSyncPeriod.Duration)
   977  	serviceConfig.RegisterEventHandler(s.Proxier)
   978  	go serviceConfig.Run(ctx.Done())
   979  
   980  	endpointSliceConfig := config.NewEndpointSliceConfig(ctx, informerFactory.Discovery().V1().EndpointSlices(), s.Config.ConfigSyncPeriod.Duration)
   981  	endpointSliceConfig.RegisterEventHandler(s.Proxier)
   982  	go endpointSliceConfig.Run(ctx.Done())
   983  
   984  	if utilfeature.DefaultFeatureGate.Enabled(features.MultiCIDRServiceAllocator) {
   985  		serviceCIDRConfig := config.NewServiceCIDRConfig(ctx, informerFactory.Networking().V1alpha1().ServiceCIDRs(), s.Config.ConfigSyncPeriod.Duration)
   986  		serviceCIDRConfig.RegisterEventHandler(s.Proxier)
   987  		go serviceCIDRConfig.Run(wait.NeverStop)
   988  	}
   989  	// This has to start after the calls to NewServiceConfig because that
   990  	// function must configure its shared informer event handlers first.
   991  	informerFactory.Start(wait.NeverStop)
   992  
   993  	// Make an informer that selects for our nodename.
   994  	currentNodeInformerFactory := informers.NewSharedInformerFactoryWithOptions(s.Client, s.Config.ConfigSyncPeriod.Duration,
   995  		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
   996  			options.FieldSelector = fields.OneTermEqualSelector("metadata.name", s.NodeRef.Name).String()
   997  		}))
   998  	nodeConfig := config.NewNodeConfig(ctx, currentNodeInformerFactory.Core().V1().Nodes(), s.Config.ConfigSyncPeriod.Duration)
   999  	// https://issues.k8s.io/111321
  1000  	if s.Config.DetectLocalMode == kubeproxyconfig.LocalModeNodeCIDR {
  1001  		nodeConfig.RegisterEventHandler(proxy.NewNodePodCIDRHandler(ctx, s.podCIDRs))
  1002  	}
  1003  	if utilfeature.DefaultFeatureGate.Enabled(features.KubeProxyDrainingTerminatingNodes) {
  1004  		nodeConfig.RegisterEventHandler(&proxy.NodeEligibleHandler{
  1005  			HealthServer: s.HealthzServer,
  1006  		})
  1007  	}
  1008  	nodeConfig.RegisterEventHandler(s.Proxier)
  1009  
  1010  	go nodeConfig.Run(wait.NeverStop)
  1011  
  1012  	// This has to start after the calls to NewNodeConfig because that must
  1013  	// configure the shared informer event handler first.
  1014  	currentNodeInformerFactory.Start(wait.NeverStop)
  1015  
  1016  	// Birth Cry after the birth is successful
  1017  	s.birthCry()
  1018  
  1019  	go s.Proxier.SyncLoop()
  1020  
  1021  	select {
  1022  	case err = <-healthzErrCh:
  1023  		s.Recorder.Eventf(s.NodeRef, nil, api.EventTypeWarning, "FailedToStartProxierHealthcheck", "StartKubeProxy", err.Error())
  1024  	case err = <-metricsErrCh:
  1025  		s.Recorder.Eventf(s.NodeRef, nil, api.EventTypeWarning, "FailedToStartMetricServer", "StartKubeProxy", err.Error())
  1026  	}
  1027  	return err
  1028  }
  1029  
  1030  func (s *ProxyServer) birthCry() {
  1031  	s.Recorder.Eventf(s.NodeRef, nil, api.EventTypeNormal, "Starting", "StartKubeProxy", "")
  1032  }
  1033  
  1034  // detectNodeIPs returns the proxier's "node IP" or IPs, and the IP family to use if the
  1035  // node turns out to be incapable of dual-stack. (Note that kube-proxy normally runs as
  1036  // dual-stack if the backend is capable of supporting both IP families, regardless of
  1037  // whether the node is *actually* configured as dual-stack or not.)
  1038  
  1039  // (Note that on Linux, the node IPs are used only to determine whether a given
  1040  // LoadBalancerSourceRanges value matches the node or not. In particular, they are *not*
  1041  // used for NodePort handling.)
  1042  //
  1043  // The order of precedence is:
  1044  //  1. if bindAddress is not 0.0.0.0 or ::, then it is used as the primary IP.
  1045  //  2. if rawNodeIPs is not empty, then its address(es) is/are used
  1046  //  3. otherwise the node IPs are 127.0.0.1 and ::1
  1047  func detectNodeIPs(ctx context.Context, rawNodeIPs []net.IP, bindAddress string) (v1.IPFamily, map[v1.IPFamily]net.IP) {
  1048  	logger := klog.FromContext(ctx)
  1049  	primaryFamily := v1.IPv4Protocol
  1050  	nodeIPs := map[v1.IPFamily]net.IP{
  1051  		v1.IPv4Protocol: net.IPv4(127, 0, 0, 1),
  1052  		v1.IPv6Protocol: net.IPv6loopback,
  1053  	}
  1054  
  1055  	if len(rawNodeIPs) > 0 {
  1056  		if !netutils.IsIPv4(rawNodeIPs[0]) {
  1057  			primaryFamily = v1.IPv6Protocol
  1058  		}
  1059  		nodeIPs[primaryFamily] = rawNodeIPs[0]
  1060  		if len(rawNodeIPs) > 1 {
  1061  			// If more than one address is returned, they are guaranteed to be of different families
  1062  			family := v1.IPv4Protocol
  1063  			if !netutils.IsIPv4(rawNodeIPs[1]) {
  1064  				family = v1.IPv6Protocol
  1065  			}
  1066  			nodeIPs[family] = rawNodeIPs[1]
  1067  		}
  1068  	}
  1069  
  1070  	// If a bindAddress is passed, override the primary IP
  1071  	bindIP := netutils.ParseIPSloppy(bindAddress)
  1072  	if bindIP != nil && !bindIP.IsUnspecified() {
  1073  		if netutils.IsIPv4(bindIP) {
  1074  			primaryFamily = v1.IPv4Protocol
  1075  		} else {
  1076  			primaryFamily = v1.IPv6Protocol
  1077  		}
  1078  		nodeIPs[primaryFamily] = bindIP
  1079  	}
  1080  
  1081  	if nodeIPs[primaryFamily].IsLoopback() {
  1082  		logger.Info("Can't determine this node's IP, assuming loopback; if this is incorrect, please set the --bind-address flag")
  1083  	}
  1084  	return primaryFamily, nodeIPs
  1085  }
  1086  
  1087  // getNodeIP returns IPs for the node with the provided name.  If
  1088  // required, it will wait for the node to be created.
  1089  func getNodeIPs(ctx context.Context, client clientset.Interface, name string) []net.IP {
  1090  	logger := klog.FromContext(ctx)
  1091  	var nodeIPs []net.IP
  1092  	backoff := wait.Backoff{
  1093  		Steps:    6,
  1094  		Duration: 1 * time.Second,
  1095  		Factor:   2.0,
  1096  		Jitter:   0.2,
  1097  	}
  1098  
  1099  	err := wait.ExponentialBackoff(backoff, func() (bool, error) {
  1100  		node, err := client.CoreV1().Nodes().Get(ctx, name, metav1.GetOptions{})
  1101  		if err != nil {
  1102  			logger.Error(err, "Failed to retrieve node info")
  1103  			return false, nil
  1104  		}
  1105  		nodeIPs, err = utilnode.GetNodeHostIPs(node)
  1106  		if err != nil {
  1107  			logger.Error(err, "Failed to retrieve node IPs")
  1108  			return false, nil
  1109  		}
  1110  		return true, nil
  1111  	})
  1112  	if err == nil {
  1113  		logger.Info("Successfully retrieved node IP(s)", "IPs", nodeIPs)
  1114  	}
  1115  	return nodeIPs
  1116  }