123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- // +build !windows
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- // Package app does all of the work necessary to configure and run a
- // Kubernetes app process.
- package app
- import (
- "errors"
- "fmt"
- "net"
- "strings"
- v1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
- utilnet "k8s.io/apimachinery/pkg/util/net"
- utilruntime "k8s.io/apimachinery/pkg/util/runtime"
- utilfeature "k8s.io/apiserver/pkg/util/feature"
- "k8s.io/client-go/tools/record"
- "k8s.io/component-base/metrics"
- "k8s.io/kubernetes/pkg/features"
- "k8s.io/kubernetes/pkg/proxy"
- proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
- proxyconfigscheme "k8s.io/kubernetes/pkg/proxy/apis/config/scheme"
- "k8s.io/kubernetes/pkg/proxy/healthcheck"
- "k8s.io/kubernetes/pkg/proxy/iptables"
- "k8s.io/kubernetes/pkg/proxy/ipvs"
- proxymetrics "k8s.io/kubernetes/pkg/proxy/metrics"
- "k8s.io/kubernetes/pkg/proxy/userspace"
- proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables"
- "k8s.io/kubernetes/pkg/util/configz"
- utilipset "k8s.io/kubernetes/pkg/util/ipset"
- utiliptables "k8s.io/kubernetes/pkg/util/iptables"
- utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
- utilnode "k8s.io/kubernetes/pkg/util/node"
- utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
- "k8s.io/utils/exec"
- utilsnet "k8s.io/utils/net"
- "k8s.io/klog"
- )
- // NewProxyServer returns a new ProxyServer.
- func NewProxyServer(o *Options) (*ProxyServer, error) {
- return newProxyServer(o.config, o.CleanupAndExit, o.master)
- }
- func newProxyServer(
- config *proxyconfigapi.KubeProxyConfiguration,
- cleanupAndExit bool,
- master string) (*ProxyServer, error) {
- if config == nil {
- return nil, errors.New("config is required")
- }
- if c, err := configz.New(proxyconfigapi.GroupName); err == nil {
- c.Set(config)
- } else {
- return nil, fmt.Errorf("unable to register configz: %s", err)
- }
- protocol := utiliptables.ProtocolIpv4
- if net.ParseIP(config.BindAddress).To4() == nil {
- klog.V(0).Infof("IPv6 bind address (%s), assume IPv6 operation", config.BindAddress)
- protocol = utiliptables.ProtocolIpv6
- }
- var iptInterface utiliptables.Interface
- var ipvsInterface utilipvs.Interface
- var kernelHandler ipvs.KernelHandler
- var ipsetInterface utilipset.Interface
- // Create a iptables utils.
- execer := exec.New()
- iptInterface = utiliptables.New(execer, protocol)
- kernelHandler = ipvs.NewLinuxKernelHandler()
- ipsetInterface = utilipset.New(execer)
- canUseIPVS, _ := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface)
- if canUseIPVS {
- ipvsInterface = utilipvs.New(execer)
- }
- // We omit creation of pretty much everything if we run in cleanup mode
- if cleanupAndExit {
- return &ProxyServer{
- execer: execer,
- IptInterface: iptInterface,
- IpvsInterface: ipvsInterface,
- IpsetInterface: ipsetInterface,
- }, nil
- }
- if len(config.ShowHiddenMetricsForVersion) > 0 {
- metrics.SetShowHidden()
- }
- client, eventClient, err := createClients(config.ClientConnection, master)
- if err != nil {
- return nil, err
- }
- // Create event recorder
- hostname, err := utilnode.GetHostname(config.HostnameOverride)
- if err != nil {
- return nil, err
- }
- eventBroadcaster := record.NewBroadcaster()
- recorder := eventBroadcaster.NewRecorder(proxyconfigscheme.Scheme, v1.EventSource{Component: "kube-proxy", Host: hostname})
- nodeRef := &v1.ObjectReference{
- Kind: "Node",
- Name: hostname,
- UID: types.UID(hostname),
- Namespace: "",
- }
- var healthzServer healthcheck.ProxierHealthUpdater
- if len(config.HealthzBindAddress) > 0 {
- healthzServer = healthcheck.NewProxierHealthServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
- }
- var proxier proxy.Provider
- var detectLocalMode proxyconfigapi.LocalMode
- proxyMode := getProxyMode(string(config.Mode), kernelHandler, ipsetInterface, iptables.LinuxKernelCompatTester{})
- detectLocalMode, err = getDetectLocalMode(config)
- if err != nil {
- return nil, fmt.Errorf("cannot determine detect-local-mode: %v", err)
- }
- nodeIP := net.ParseIP(config.BindAddress)
- if nodeIP.IsUnspecified() {
- nodeIP = utilnode.GetNodeIP(client, hostname)
- if nodeIP == nil {
- klog.V(0).Infof("can't determine this node's IP, assuming 127.0.0.1; if this is incorrect, please set the --bind-address flag")
- nodeIP = net.ParseIP("127.0.0.1")
- }
- }
- klog.V(2).Info("DetectLocalMode: '", string(detectLocalMode), "'")
- if proxyMode == proxyModeIPTables {
- klog.V(0).Info("Using iptables Proxier.")
- if config.IPTables.MasqueradeBit == nil {
- // MasqueradeBit must be specified or defaulted.
- return nil, fmt.Errorf("unable to read IPTables MasqueradeBit from config")
- }
- if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
- klog.V(0).Info("creating dualStackProxier for iptables.")
- // Create iptables handlers for both families, one is already created
- // Always ordered as IPv4, IPv6
- var ipt [2]utiliptables.Interface
- if iptInterface.IsIpv6() {
- ipt[1] = iptInterface
- ipt[0] = utiliptables.New(execer, utiliptables.ProtocolIpv4)
- } else {
- ipt[0] = iptInterface
- ipt[1] = utiliptables.New(execer, utiliptables.ProtocolIpv6)
- }
- // Always ordered to match []ipt
- var localDetectors [2]proxyutiliptables.LocalTrafficDetector
- localDetectors, err = getDualStackLocalDetectorTuple(detectLocalMode, config, ipt)
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- // TODO this has side effects that should only happen when Run() is invoked.
- proxier, err = iptables.NewDualStackProxier(
- ipt,
- utilsysctl.New(),
- execer,
- config.IPTables.SyncPeriod.Duration,
- config.IPTables.MinSyncPeriod.Duration,
- config.IPTables.MasqueradeAll,
- int(*config.IPTables.MasqueradeBit),
- localDetectors,
- hostname,
- nodeIPTuple(config.BindAddress),
- recorder,
- healthzServer,
- config.NodePortAddresses,
- )
- } else { // Create a single-stack proxier.
- var localDetector proxyutiliptables.LocalTrafficDetector
- localDetector, err = getLocalDetector(detectLocalMode, config, iptInterface)
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- // TODO this has side effects that should only happen when Run() is invoked.
- proxier, err = iptables.NewProxier(
- iptInterface,
- utilsysctl.New(),
- execer,
- config.IPTables.SyncPeriod.Duration,
- config.IPTables.MinSyncPeriod.Duration,
- config.IPTables.MasqueradeAll,
- int(*config.IPTables.MasqueradeBit),
- localDetector,
- hostname,
- nodeIP,
- recorder,
- healthzServer,
- config.NodePortAddresses,
- )
- }
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- proxymetrics.RegisterMetrics()
- } else if proxyMode == proxyModeIPVS {
- klog.V(0).Info("Using ipvs Proxier.")
- if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
- klog.V(0).Info("creating dualStackProxier for ipvs.")
- // Create iptables handlers for both families, one is already created
- // Always ordered as IPv4, IPv6
- var ipt [2]utiliptables.Interface
- if iptInterface.IsIpv6() {
- ipt[1] = iptInterface
- ipt[0] = utiliptables.New(execer, utiliptables.ProtocolIpv4)
- } else {
- ipt[0] = iptInterface
- ipt[1] = utiliptables.New(execer, utiliptables.ProtocolIpv6)
- }
- nodeIPs := nodeIPTuple(config.BindAddress)
- // Always ordered to match []ipt
- var localDetectors [2]proxyutiliptables.LocalTrafficDetector
- localDetectors, err = getDualStackLocalDetectorTuple(detectLocalMode, config, ipt)
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- proxier, err = ipvs.NewDualStackProxier(
- ipt,
- ipvsInterface,
- ipsetInterface,
- utilsysctl.New(),
- execer,
- config.IPVS.SyncPeriod.Duration,
- config.IPVS.MinSyncPeriod.Duration,
- config.IPVS.ExcludeCIDRs,
- config.IPVS.StrictARP,
- config.IPVS.TCPTimeout.Duration,
- config.IPVS.TCPFinTimeout.Duration,
- config.IPVS.UDPTimeout.Duration,
- config.IPTables.MasqueradeAll,
- int(*config.IPTables.MasqueradeBit),
- localDetectors,
- hostname,
- nodeIPs,
- recorder,
- healthzServer,
- config.IPVS.Scheduler,
- config.NodePortAddresses,
- )
- } else {
- var localDetector proxyutiliptables.LocalTrafficDetector
- localDetector, err = getLocalDetector(detectLocalMode, config, iptInterface)
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- proxier, err = ipvs.NewProxier(
- iptInterface,
- ipvsInterface,
- ipsetInterface,
- utilsysctl.New(),
- execer,
- config.IPVS.SyncPeriod.Duration,
- config.IPVS.MinSyncPeriod.Duration,
- config.IPVS.ExcludeCIDRs,
- config.IPVS.StrictARP,
- config.IPVS.TCPTimeout.Duration,
- config.IPVS.TCPFinTimeout.Duration,
- config.IPVS.UDPTimeout.Duration,
- config.IPTables.MasqueradeAll,
- int(*config.IPTables.MasqueradeBit),
- localDetector,
- hostname,
- nodeIP,
- recorder,
- healthzServer,
- config.IPVS.Scheduler,
- config.NodePortAddresses,
- )
- }
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- proxymetrics.RegisterMetrics()
- } else {
- klog.V(0).Info("Using userspace Proxier.")
- // TODO this has side effects that should only happen when Run() is invoked.
- proxier, err = userspace.NewProxier(
- userspace.NewLoadBalancerRR(),
- net.ParseIP(config.BindAddress),
- iptInterface,
- execer,
- *utilnet.ParsePortRangeOrDie(config.PortRange),
- config.IPTables.SyncPeriod.Duration,
- config.IPTables.MinSyncPeriod.Duration,
- config.UDPIdleTimeout.Duration,
- config.NodePortAddresses,
- )
- if err != nil {
- return nil, fmt.Errorf("unable to create proxier: %v", err)
- }
- }
- return &ProxyServer{
- Client: client,
- EventClient: eventClient,
- IptInterface: iptInterface,
- IpvsInterface: ipvsInterface,
- IpsetInterface: ipsetInterface,
- execer: execer,
- Proxier: proxier,
- Broadcaster: eventBroadcaster,
- Recorder: recorder,
- ConntrackConfiguration: config.Conntrack,
- Conntracker: &realConntracker{},
- ProxyMode: proxyMode,
- NodeRef: nodeRef,
- MetricsBindAddress: config.MetricsBindAddress,
- EnableProfiling: config.EnableProfiling,
- OOMScoreAdj: config.OOMScoreAdj,
- ConfigSyncPeriod: config.ConfigSyncPeriod.Duration,
- HealthzServer: healthzServer,
- UseEndpointSlices: utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceProxying),
- }, nil
- }
- func getDetectLocalMode(config *proxyconfigapi.KubeProxyConfiguration) (proxyconfigapi.LocalMode, error) {
- mode := config.DetectLocalMode
- switch mode {
- case proxyconfigapi.LocalModeClusterCIDR:
- return mode, nil
- default:
- if strings.TrimSpace(mode.String()) != "" {
- return mode, fmt.Errorf("unknown detect-local-mode: %v", mode)
- }
- klog.V(4).Info("Defaulting detect-local-mode to ", string(proxyconfigapi.LocalModeClusterCIDR))
- return proxyconfigapi.LocalModeClusterCIDR, nil
- }
- }
- func getLocalDetector(mode proxyconfigapi.LocalMode, config *proxyconfigapi.KubeProxyConfiguration, ipt utiliptables.Interface) (proxyutiliptables.LocalTrafficDetector, error) {
- switch mode {
- case proxyconfigapi.LocalModeClusterCIDR:
- if len(strings.TrimSpace(config.ClusterCIDR)) == 0 {
- klog.Warning("detect-local-mode set to ClusterCIDR, but no cluster CIDR defined")
- break
- }
- return proxyutiliptables.NewDetectLocalByCIDR(config.ClusterCIDR, ipt)
- }
- klog.V(0).Info("detect-local-mode: ", string(mode), " , defaulting to no-op detect-local")
- return proxyutiliptables.NewNoOpLocalDetector(), nil
- }
- func getDualStackLocalDetectorTuple(mode proxyconfigapi.LocalMode, config *proxyconfigapi.KubeProxyConfiguration, ipt [2]utiliptables.Interface) ([2]proxyutiliptables.LocalTrafficDetector, error) {
- var err error
- localDetectors := [2]proxyutiliptables.LocalTrafficDetector{proxyutiliptables.NewNoOpLocalDetector(), proxyutiliptables.NewNoOpLocalDetector()}
- switch mode {
- case proxyconfigapi.LocalModeClusterCIDR:
- if len(strings.TrimSpace(config.ClusterCIDR)) == 0 {
- klog.Warning("detect-local-mode set to ClusterCIDR, but no cluster CIDR defined")
- break
- }
- clusterCIDRs := cidrTuple(config.ClusterCIDR)
- if len(strings.TrimSpace(clusterCIDRs[0])) == 0 {
- klog.Warning("detect-local-mode set to ClusterCIDR, but no IPv4 cluster CIDR defined, defaulting to no-op detect-local for IPv4")
- } else {
- localDetectors[0], err = proxyutiliptables.NewDetectLocalByCIDR(clusterCIDRs[0], ipt[0])
- if err != nil { // don't loose the original error
- return localDetectors, err
- }
- }
- if len(strings.TrimSpace(clusterCIDRs[1])) == 0 {
- klog.Warning("detect-local-mode set to ClusterCIDR, but no IPv6 cluster CIDR defined, , defaulting to no-op detect-local for IPv6")
- } else {
- localDetectors[1], err = proxyutiliptables.NewDetectLocalByCIDR(clusterCIDRs[1], ipt[1])
- }
- return localDetectors, err
- default:
- klog.Warningf("unknown detect-local-mode: %v", mode)
- }
- klog.Warning("detect-local-mode: ", string(mode), " , defaulting to no-op detect-local")
- return localDetectors, nil
- }
- // cidrTuple takes a comma separated list of CIDRs and return a tuple (ipv4cidr,ipv6cidr)
- // The returned tuple is guaranteed to have the order (ipv4,ipv6) and if no cidr from a family is found an
- // empty string "" is inserted.
- func cidrTuple(cidrList string) [2]string {
- cidrs := [2]string{"", ""}
- foundIPv4 := false
- foundIPv6 := false
- for _, cidr := range strings.Split(cidrList, ",") {
- if utilsnet.IsIPv6CIDRString(cidr) && !foundIPv6 {
- cidrs[1] = cidr
- foundIPv6 = true
- } else if !foundIPv4 {
- cidrs[0] = cidr
- foundIPv4 = true
- }
- if foundIPv6 && foundIPv4 {
- break
- }
- }
- return cidrs
- }
- // nodeIPTuple takes an addresses and return a tuple (ipv4,ipv6)
- // The returned tuple is guaranteed to have the order (ipv4,ipv6). The address NOT of the passed address
- // will have "any" address (0.0.0.0 or ::) inserted.
- func nodeIPTuple(bindAddress string) [2]net.IP {
- nodes := [2]net.IP{net.IPv4zero, net.IPv6zero}
- adr := net.ParseIP(bindAddress)
- if utilsnet.IsIPv6(adr) {
- nodes[1] = adr
- } else {
- nodes[0] = adr
- }
- return nodes
- }
- func getProxyMode(proxyMode string, khandle ipvs.KernelHandler, ipsetver ipvs.IPSetVersioner, kcompat iptables.KernelCompatTester) string {
- switch proxyMode {
- case proxyModeUserspace:
- return proxyModeUserspace
- case proxyModeIPTables:
- return tryIPTablesProxy(kcompat)
- case proxyModeIPVS:
- return tryIPVSProxy(khandle, ipsetver, kcompat)
- }
- klog.Warningf("Unknown proxy mode %q, assuming iptables proxy", proxyMode)
- return tryIPTablesProxy(kcompat)
- }
- func tryIPVSProxy(khandle ipvs.KernelHandler, ipsetver ipvs.IPSetVersioner, kcompat iptables.KernelCompatTester) string {
- // guaranteed false on error, error only necessary for debugging
- // IPVS Proxier relies on ip_vs_* kernel modules and ipset
- useIPVSProxy, err := ipvs.CanUseIPVSProxier(khandle, ipsetver)
- if err != nil {
- // Try to fallback to iptables before falling back to userspace
- utilruntime.HandleError(fmt.Errorf("can't determine whether to use ipvs proxy, error: %v", err))
- }
- if useIPVSProxy {
- return proxyModeIPVS
- }
- // Try to fallback to iptables before falling back to userspace
- klog.V(1).Infof("Can't use ipvs proxier, trying iptables proxier")
- return tryIPTablesProxy(kcompat)
- }
- func tryIPTablesProxy(kcompat iptables.KernelCompatTester) string {
- // guaranteed false on error, error only necessary for debugging
- useIPTablesProxy, err := iptables.CanUseIPTablesProxier(kcompat)
- if err != nil {
- utilruntime.HandleError(fmt.Errorf("can't determine whether to use iptables proxy, using userspace proxier: %v", err))
- return proxyModeUserspace
- }
- if useIPTablesProxy {
- return proxyModeIPTables
- }
- // Fallback.
- klog.V(1).Infof("Can't use iptables proxy, using userspace proxier")
- return proxyModeUserspace
- }
|