前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >kube-proxy源码分析

kube-proxy源码分析

作者头像
编程黑洞
发布于 2024-01-19 06:41:30
发布于 2024-01-19 06:41:30
30600
代码可运行
举报
文章被收录于专栏:编程黑洞编程黑洞
运行总次数:0
代码可运行

# kube-proxy源码分析

# 简介

本文主要是对kube-proxy的源码分析,了解其代码结构和实现原理。这里是根据kubernetes1.23.9 (opens new window)版本来进行分析的。在下面贴上的代码会一定裁剪,主要用于理解主流程。

# 初始化

kube-proxy入口文件在cmd/kube-proxy/proxy.go

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main() {
	command := app.NewProxyCommand()
	code := cli.Run(command)
	os.Exit(code)
}

查看app.NewProxyCommand()方法,使用的cobra命令行解析库来作为程序入口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func NewProxyCommand() *cobra.Command {
	opts := NewOptions()

	cmd := &cobra.Command{
		Use: "kube-proxy",
		Long: `The Kubernetes network proxy runs on each node. This
reflects services as defined in the Kubernetes API on each node and can do simple
TCP, UDP, and SCTP stream forwarding or round robin TCP, UDP, and SCTP forwarding across a set of backends.
Service cluster IPs and ports are currently found through Docker-links-compatible
environment variables specifying ports opened by the service proxy. There is an optional
addon that provides cluster DNS for these cluster IPs. The user must create a service
with the apiserver API to configure the proxy.`,
		RunE: func(cmd *cobra.Command, args []string) error {
			verflag.PrintAndExitIfRequested()
			cliflag.PrintFlags(cmd.Flags())

			if err := initForOS(opts.WindowsService); err != nil {
				return fmt.Errorf("failed os init: %w", err)
			}

			// 1. 加载配置文件kubeproxyconfig.KubeProxyConfiguration
			// 2. 监控文件变化
			if err := opts.Complete(); err != nil {
				return fmt.Errorf("failed complete: %w", err)
			}

			// 配置参数的校验
			if err := opts.Validate(); err != nil {
				return fmt.Errorf("failed validate: %w", err)
			}

			// 运行服务
			if err := opts.Run(); err != nil {
				klog.ErrorS(err, "Error running ProxyServer")
				return err
			}

			return nil
		},
		Args: func(cmd *cobra.Command, args []string) error {
			for _, arg := range args {
				if len(arg) > 0 {
					return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
				}
			}
			return nil
		},
	}

	var err error
    // 填充一些默认配置
	opts.config, err = opts.ApplyDefaults(opts.config)
	if err != nil {
		klog.ErrorS(err, "Unable to create flag defaults")
		// ACTION REQUIRED: Exit code changed from 255 to 1
		os.Exit(1)
	}

	fs := cmd.Flags()
	opts.AddFlags(fs)
	// 将go的命令行参数也加到命令行参数中
	fs.AddGoFlagSet(goflag.CommandLine) // for --boot-id-file and --machine-id-file

	_ = cmd.MarkFlagFilename("config", "yaml", "yml", "json")

	return cmd
}
  1. 读取配置文件KubeProxyConfiguration,并监听变化收到对应的事件
  2. 对配置KubeProxyConfiguration进行校验
  3. 启动服务

再来看opts.Run()​服务启动的实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (o *Options) Run() error {
	defer close(o.errCh)

    // 如果配置了该字段,将配置文件写入指定位置,然后退出
	if len(o.WriteConfigTo) > 0 {
		return o.writeConfigFile()
	}

    // 创建代理服务
	proxyServer, err := NewProxyServer(o)
	if err != nil {
		return err
	}

	// 清除所有的iptables规则
	if o.CleanupAndExit {
		return proxyServer.CleanupAndExit()
	}

	// 启动代理服务
	o.proxyServer = proxyServer
	return o.runLoop()
}

再看NewProxyServer()​的实现,主要是用来创建proxyServer对象,并且在其中根据当前的网络模式,通过iptables.NewProxier来创建proxier对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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) {

	// 执行本地命令的控制器
	execer := exec.New()

	kernelHandler = ipvs.NewLinuxKernelHandler() 
    // 创建ipset命令的执行器
	ipsetInterface = utilipset.New(execer)
    // 判断是否支持ipvs
	canUseIPVS, err := ipvs.CanUseIPVSProxier(kernelHandler, ipsetInterface, config.IPVS.Scheduler)
	if string(config.Mode) == proxyModeIPVS && err != nil {
		klog.ErrorS(err, "Can't use the IPVS proxier")
	}

	if canUseIPVS {
        // 如果支持的话,创建ipvs执行器
		ipvsInterface = utilipvs.New()
	}

	// 创建事件记录器
	eventBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1()})
	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, "kube-proxy")

	// 创建健康检查服务
	var healthzServer healthcheck.ProxierHealthUpdater
	if len(config.HealthzBindAddress) > 0 {
		healthzServer = healthcheck.NewProxierHealthServer(config.HealthzBindAddress, 2*config.IPTables.SyncPeriod.Duration, recorder, nodeRef)
	}

    // 获取当前的代理模式
	proxyMode := getProxyMode(string(config.Mode), canUseIPVS, iptables.LinuxKernelCompatTester{})
	
    // 获取当前的主要的IP协议
	primaryProtocol := utiliptables.ProtocolIPv4
	if netutils.IsIPv6(nodeIP) {
		primaryProtocol = utiliptables.ProtocolIPv6
	}

	// 创建iptables执行器
	iptInterface = utiliptables.New(execer, primaryProtocol)

	// 可能支持ipv4和ipv6两种执行器
	var ipt [2]utiliptables.Interface
	dualStack := true // While we assume that node supports, we do further checks below

	// 如果支持的是iptables模式
	if proxyMode == proxyModeIPTables {

		// 双端模式,支持IP4和IPV6
		if dualStack {
			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 {
			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 {
		...
	}

	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,
		BindAddressHardFail:    config.BindAddressHardFail,
		EnableProfiling:        config.EnableProfiling,
		OOMScoreAdj:            config.OOMScoreAdj,
		ConfigSyncPeriod:       config.ConfigSyncPeriod.Duration,
		HealthzServer:          healthzServer,
		UseEndpointSlices:      useEndpointSlices,
	}, nil
}

再来看iptables.NewProxier()​方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func NewProxier(ipt utiliptables.Interface,
	sysctl utilsysctl.Interface,
	exec utilexec.Interface,
	syncPeriod time.Duration,
	minSyncPeriod time.Duration,
	masqueradeAll bool,
	masqueradeBit int,
	localDetector proxyutiliptables.LocalTrafficDetector,
	hostname string,
	nodeIP net.IP,
	recorder events.EventRecorder,
	healthzServer healthcheck.ProxierHealthUpdater,
	nodePortAddresses []string,
) (*Proxier, error) {

	// 这个就是0x4000,也就是给数据包打上标记,在出主机的时候会进行SNAT
	masqueradeValue := 1 << uint(masqueradeBit)
	masqueradeMark := fmt.Sprintf("%#08x", masqueradeValue)

    // 创建健康检查服务
	serviceHealthServer := healthcheck.NewServiceHealthServer(hostname, recorder, nodePortAddresses)

	proxier := &Proxier{
		serviceMap:               make(proxy.ServiceMap),
		serviceChanges:           proxy.NewServiceChangeTracker(newServiceInfo, ipFamily, recorder, nil),
		endpointsMap:             make(proxy.EndpointsMap),
		endpointsChanges:         proxy.NewEndpointChangeTracker(hostname, newEndpointInfo, ipFamily, recorder, nil),
		syncPeriod:               syncPeriod,
		iptables:                 ipt,
		masqueradeAll:            masqueradeAll,
		masqueradeMark:           masqueradeMark,
		exec:                     exec,
		localDetector:            localDetector,
		hostname:                 hostname,
		nodeIP:                   nodeIP,
		recorder:                 recorder,
		serviceHealthServer:      serviceHealthServer,
		healthzServer:            healthzServer,
		precomputedProbabilities: make([]string, 0, 1001),
		iptablesData:             bytes.NewBuffer(nil),
		existingFilterChainsData: bytes.NewBuffer(nil),
		filterChains:             utilproxy.LineBuffer{},
		filterRules:              utilproxy.LineBuffer{},
		natChains:                utilproxy.LineBuffer{},
		natRules:                 utilproxy.LineBuffer{},
		nodePortAddresses:        nodePortAddresses,
		networkInterfacer:        utilproxy.RealNetwork{},
	}

	burstSyncs := 2
    // syncRunner是用来控制刷新iptables规则频率的运行器,proxier.syncProxyRules方法就是真正刷新iptables规则的方法
   	proxier.syncRunner = async.NewBoundedFrequencyRunner("sync-runner", proxier.syncProxyRules, minSyncPeriod, time.Hour, burstSyncs)

	// 这里启用一个goroutine。在三个表中都创建一个KUBE-PROXY-CANARY子链,通过子链是否存在来判断iptables是否被刷掉。
	// 如果该链不存在,说明iptables被刷掉了,再次执行syncProxyRules方法刷回来。
	go ipt.Monitor(kubeProxyCanaryChain, []utiliptables.Table{utiliptables.TableMangle, utiliptables.TableNAT, utiliptables.TableFilter},
		proxier.syncProxyRules, syncPeriod, wait.NeverStop)
	return proxier, nil
}

以上主要的对象已经初始化完成了。

# Run

回到o.Run()​方法中,先是创建ProxyServer对象,然后在其中又创建proxier对象,做了一系列初始化动作,接下来就是运行代理服务了,现在看向runLoop​方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (o *Options) runLoop() error {
	// 开启文件监听
	if o.watcher != nil {
		o.watcher.Run()
	}

	// run the proxy in goroutine
	go func() {
		err := o.proxyServer.Run()
		o.errCh <- err
	}()

    // 如果接受到errCh则停止服务
	for {
		err := <-o.errCh
		if err != nil {
			return err
		}
	}
}

再看向o.proxyServer.Run()​方法,运行代理服务的主流程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (s *ProxyServer) Run() error {
	// 设置当前进程的OOM参数,资源紧张时,不优先kill掉kube-proxy
	var oomAdjuster *oom.OOMAdjuster
	if s.OOMScoreAdj != nil {
		oomAdjuster = oom.NewOOMAdjuster()
		if err := oomAdjuster.ApplyOOMScoreAdj(0, int(*s.OOMScoreAdj)); err != nil {
			klog.V(2).InfoS("Failed to apply OOMScore", "err", err)
		}
	}

	// 开启健康检查服务
	serveHealthz(s.HealthzServer, errCh)

	// 开启指标上报服务
	serveMetrics(s.MetricsBindAddress, s.ProxyMode, s.EnableProfiling, errCh)

	// 创建informer
	informerFactory := informers.NewSharedInformerFactoryWithOptions(s.Client, s.ConfigSyncPeriod,
		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
			options.LabelSelector = labelSelector.String()
		}))

	// 监听service和endpoint并注册事件,当发生变化时,则会进行刷新iptables规则
	serviceConfig := config.NewServiceConfig(informerFactory.Core().V1().Services(), s.ConfigSyncPeriod)
	serviceConfig.RegisterEventHandler(s.Proxier)
	go serviceConfig.Run(wait.NeverStop)

	if endpointsHandler, ok := s.Proxier.(config.EndpointsHandler); ok && !s.UseEndpointSlices {
		endpointsConfig := config.NewEndpointsConfig(informerFactory.Core().V1().Endpoints(), s.ConfigSyncPeriod)
		endpointsConfig.RegisterEventHandler(endpointsHandler)
		go endpointsConfig.Run(wait.NeverStop)
	} else {
		endpointSliceConfig := config.NewEndpointSliceConfig(informerFactory.Discovery().V1().EndpointSlices(), s.ConfigSyncPeriod)
		endpointSliceConfig.RegisterEventHandler(s.Proxier)
		go endpointSliceConfig.Run(wait.NeverStop)
	}

	informerFactory.Start(wait.NeverStop)

	// 发送启动事件
	s.birthCry()

	go s.Proxier.SyncLoop()

	return <-errCh
}

# service 和 endpointslice 变更事件

程序中是通过informer来实现对service和endpoint发生变化的监听,感知变化,并触发事件并进行相应的处理。

先看一下NewServiceConfig()​方法,其中注册了当service发生增、删、改事件时,分别执行result.handleAddService​、result.handleUpdateService​、result.handleDeleteService​方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func NewServiceConfig(serviceInformer coreinformers.ServiceInformer, resyncPeriod time.Duration) *ServiceConfig {
	result := &ServiceConfig{
		listerSynced: serviceInformer.Informer().HasSynced,
	}

	// 注册变更事件
	serviceInformer.Informer().AddEventHandlerWithResyncPeriod(
		cache.ResourceEventHandlerFuncs{
			AddFunc:    result.handleAddService,
			UpdateFunc: result.handleUpdateService,
			DeleteFunc: result.handleDeleteService,
		},
		resyncPeriod,
	)

	return result
}

再看看其中的handleAddService()​方法,传入的参数obj就是新增的service对象,然后传入eventHandler.OnServiceAdd()方法进行处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (c *ServiceConfig) handleAddService(obj interface{}) {
	service, ok := obj.(*v1.Service)
	if !ok {
		utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj))
		return
	}
	for i := range c.eventHandlers {
		klog.V(4).InfoS("Calling handler.OnServiceAdd")
		c.eventHandlers[i].OnServiceAdd(service)
	}
}

这里c.eventHanlders其实就是proxier对象,在RegisterEventHandler()方法中将其添加进去的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
serviceConfig.RegisterEventHandler(s.Proxier)

也就是说,proxier.OnServiceAdd()才是需要触发的处理方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxier *Proxier) OnServiceAdd(service *v1.Service) {
	proxier.OnServiceUpdate(nil, service)
}

第一个参数为旧的service,第二参数为新的参数。该方法给可以OnServiceAdd​复用,传入的第一个参数为nil,第二个参数不为nil,就是新增的操作。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxier *Proxier) OnServiceUpdate(oldService, service *v1.Service) {
	if proxier.serviceChanges.Update(oldService, service) && proxier.isInitialized() {
		proxier.Sync()
	}
}

还可以看到删除操作也能复用,有旧的service,而新service为nil代表删除。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// OnServiceDelete is called whenever deletion of an existing service
// object is observed.
func (proxier *Proxier) OnServiceDelete(service *v1.Service) {
	proxier.OnServiceUpdate(service, nil)
}

无论是增、删、改都会执行到proxier.Sync()方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxier *Proxier) Sync() {
	if proxier.healthzServer != nil {
		proxier.healthzServer.QueuedUpdate()
	}
	metrics.SyncProxyRulesLastQueuedTimestamp.SetToCurrentTime()
	proxier.syncRunner.Run()
}

最终到proxier.syncRunner.Run()​方法,可以看出它会发送一个信号到bfr.run管道中。该方法除了是service发生事件执行操作的终点外,endpoint发生事件后最终也会执行到这里。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (bfr *BoundedFrequencyRunner) Run() {
	// If it takes a lot of time to run the underlying function, noone is really
	// processing elements from <run> channel. So to avoid blocking here on the
	// putting element to it, we simply skip it if there is already an element
	// in it.
	select {
	case bfr.run <- struct{}{}:
	default:
	}
}

# BoundedFrequencyRunner

我们再回到代理服务的ProxyServe.Run​方法,最后执行了s.Proxier.SyncLoop()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxier *Proxier) SyncLoop() {
	// Update healthz timestamp at beginning in case Sync() never succeeds.
	if proxier.healthzServer != nil {
		proxier.healthzServer.Updated()
	}

	// synthesize "last change queued" time as the informers are syncing.
	metrics.SyncProxyRulesLastQueuedTimestamp.SetToCurrentTime()
	proxier.syncRunner.Loop(wait.NeverStop)
}

然后再执行proxier.syncRunner.Loop()​方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (bfr *BoundedFrequencyRunner) Loop(stop <-chan struct{}) {
	klog.V(3).Infof("%s Loop running", bfr.name)
	bfr.timer.Reset(bfr.maxInterval)
	for {
		select {
		case <-stop:
			bfr.stop()
			klog.V(3).Infof("%s Loop stopping", bfr.name)
			return
		case <-bfr.timer.C():
			bfr.tryRun()
		case <-bfr.run:
			bfr.tryRun()
		case <-bfr.retry:
			bfr.doRetry()
		}
	}
}

可以看到如果bfr.run管道接收到了信号,会执行brf.tryRun()​方法,在这个方法中会执行proxier.syncProxyRules()​进行刷新iptables规则。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// assumes the lock is not held
func (bfr *BoundedFrequencyRunner) tryRun() {
	bfr.mu.Lock()
	defer bfr.mu.Unlock()

    // 这里会限制访问速率,看是否可以执行。
	if bfr.limiter.TryAccept() {
        // 这里的fn就是proxier.syncProxyRules方法
		bfr.fn()
		bfr.lastRun = bfr.timer.Now()
		bfr.timer.Stop()
		bfr.timer.Reset(bfr.maxInterval)
		klog.V(3).Infof("%s: ran, next possible in %v, periodic in %v", bfr.name, bfr.minInterval, bfr.maxInterval)
		return
	}

	// It can't run right now, figure out when it can run next.
	elapsed := bfr.timer.Since(bfr.lastRun)   // how long since last run
	nextPossible := bfr.minInterval - elapsed // time to next possible run
	nextScheduled := bfr.timer.Remaining()    // time to next scheduled run
	klog.V(4).Infof("%s: %v since last run, possible in %v, scheduled in %v", bfr.name, elapsed, nextPossible, nextScheduled)

	// It's hard to avoid race conditions in the unit tests unless we always reset
	// the timer here, even when it's unchanged
	if nextPossible < nextScheduled {
		nextScheduled = nextPossible
	}
	bfr.timer.Stop()
	bfr.timer.Reset(nextScheduled)
}

# syncProxyRules

该方法主要是更新节点上的iptables规则。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func (proxier *Proxier) syncProxyRules() {

	// 获取service和endpoint发生变化的数据
	serviceUpdateResult := proxier.serviceMap.Update(proxier.serviceChanges)
	endpointUpdateResult := proxier.endpointsMap.Update(proxier.endpointsChanges)


	// 创建一些必要的iptables链
	for _, jump := range iptablesJumpChains {
		if _, err := proxier.iptables.EnsureChain(jump.table, jump.dstChain); err != nil {
			klog.ErrorS(err, "Failed to ensure chain exists", "table", jump.table, "chain", jump.dstChain)
			return
		}
		args := append(jump.extraArgs,
			"-m", "comment", "--comment", jump.comment,
			"-j", string(jump.dstChain),
		)
		if _, err := proxier.iptables.EnsureRule(utiliptables.Prepend, jump.table, jump.srcChain, args...); err != nil {
			klog.ErrorS(err, "Failed to ensure chain jumps", "table", jump.table, "srcChain", jump.srcChain, "dstChain", jump.dstChain)
			return
		}
	}

	for _, ch := range iptablesEnsureChains {
		if _, err := proxier.iptables.EnsureChain(ch.table, ch.chain); err != nil {
			klog.ErrorS(err, "Failed to ensure chain exists", "table", ch.table, "chain", ch.chain)
			return
		}
	}

	// 将当前filter表中所有存在的规则写入existingFilterChainsData中
	proxier.existingFilterChainsData.Reset()
	err := proxier.iptables.SaveInto(utiliptables.TableFilter, proxier.existingFilterChainsData)

	// 将nat表中所有存在的规则写入iptablesData中
	proxier.iptablesData.Reset()
	err = proxier.iptables.SaveInto(utiliptables.TableNAT, proxier.iptablesData)

	// 将filter和nat链中必要添加的子链,通过字符串拼接的方式写入变量filterChains和natChains中
	for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeExternalServicesChain, kubeForwardChain, kubeNodePortsChain} {
		if chain, ok := existingFilterChains[chainName]; ok {
			proxier.filterChains.WriteBytes(chain)
		} else {
			proxier.filterChains.Write(utiliptables.MakeChainLine(chainName))
		}
	}
	for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, KubeMarkMasqChain} {
		if chain, ok := existingNATChains[chainName]; ok {
			proxier.natChains.WriteBytes(chain)
		} else {
			proxier.natChains.Write(utiliptables.MakeChainLine(chainName))
		}
	}

	// 后面就是将各种的iptables规则通过字符串拼接起来
    ...

	// 将所有链和规则的iptables全部集成到一起iptablesData,然后再通过iptables-restore命令刷新到节点中。
	proxier.iptablesData.Reset()
	proxier.iptablesData.Write(proxier.filterChains.Bytes())
	proxier.iptablesData.Write(proxier.filterRules.Bytes())
	proxier.iptablesData.Write(proxier.natChains.Bytes())
	proxier.iptablesData.Write(proxier.natRules.Bytes())
	err = proxier.iptables.RestoreAll(proxier.iptablesData.Bytes(), utiliptables.NoFlushTables, utiliptables.RestoreCounters)
	if err != nil {
		klog.ErrorS(err, "Failed to execute iptables-restore")
		metrics.IptablesRestoreFailuresTotal.Inc()
		return
	}

总结

  1. 获取发生变更的 service 和 endpoint 信息
  2. 创建一些必要的链
  3. 使用 iptables-save 命令,将当前环境中 nat 和 filter 表中的 iptables 规则全部加载到程序中。
  4. 通过拼接字符串,构造出需要创建的 iptables 规则字符串。
  5. 通过 iptables-restore 命令,将构造的 iptables 规则字符串全部再刷新到节点上

思考

因为每一次都会将当前所有的iptables规则全部刷新到节点上,如果规则量过大的话,性能会受到影响,所以才有ipvs模式。

# 总结

整体代码流程如下:

  1. 首先是各种对象套娃式的初始化,Options->ProxyServier->proxier->syncRunner
  2. 然后是向informer中注册service和endpoint事件,当发生改动时,会给bfr.run发送信号
  3. syncRunner收到信号会去执行proxier.syncProxyRules()方法,刷新主机的iptables规则

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
星际迷航最迷人女上校去世了,享年89岁
---- 新智元报道   编辑:Aeneas 【新智元导读】在原版《星际迷航》系列中扮演 Nyota Uhura的Nichelle Nichols去世了,享年89岁。 尼切尔·尼克斯(Nichelle Nichols)去世了。 Nichelle Nichols因在原版《星际迷航》系列中扮演Nyota Uhura而闻名,她于昨日去世,享年89岁。 当地时间7月31日,她的儿子凯尔·约翰逊(Kyle Johnson)在Nichols的Ins上宣告了这一消息。 「昨晚,我的母亲Nichelle Nicho
新智元
2022/08/26
2050
星际迷航最迷人女上校去世了,享年89岁
NASA 传奇数学家去世,她曾笔算了登月轨道
内容概览:曾经在 NASA 航天计划中,着手飞行器轨道设计的传奇人物,数学家凯瑟琳·约翰逊,于昨日走完了她 101 岁的生命。这位杰出的非裔女性,靠着自己的计算天赋,完成了多项杰出的创举,甚至连阿波罗登月计划的路线计算,都有她的功劳。
HyperAI超神经
2020/02/27
8140
NASA 传奇数学家去世,她曾笔算了登月轨道
NASA登月背后的女数学家去世:计算登月轨道,奥巴马授自由勋章,经历被拍成电影
上周一,凯瑟琳·约翰逊与世长辞,享年101岁,她的一生可谓是传奇的一生:生于种族歧视的年代,10岁上高中,18岁大学毕业,曾完成水星计划和阿波罗计划飞行轨道的计算,二十世纪福克斯还以她为原型拍摄了电影《隐藏人物》。
大数据文摘
2020/03/10
8240
NASA登月背后的女数学家去世:计算登月轨道,奥巴马授自由勋章,经历被拍成电影
拯救阿波罗14号!那些伟大太空计划背后的计算机工程师们
外太空旅行近一周后的凌晨,回程中的阿波罗14号突然面临一个严峻的问题:它可能没办法正常降落了。
大数据文摘
2018/07/31
5660
拯救阿波罗14号!那些伟大太空计划背后的计算机工程师们
阿波罗计划50年后,美国重启载人登月!准备常驻,建立月球基地
经历了几个月的等待,美东时间周三凌晨1点47分,美国国家航空航天局(NASA)巨大的新型火箭从佛罗里达州肯尼迪航天中心发射升空,完成了NASA将宇航员送回月球计划的一个重要里程碑。
新智元
2023/01/07
3800
阿波罗计划50年后,美国重启载人登月!准备常驻,建立月球基地
这个美女程序员写的代码,带人类成功登月
玛格丽特·汉密尔顿在 MIT 博物馆 玛格丽特·汉密尔顿(Margaret Hamilton)没有想着要发明现代软件的概念,并且还让人类登陆月球。那是1960 年,还是一个不鼓励女性从事高技术工作的年代。 汉密尔顿是一个24岁的数学学士,她在 MIT 找到一份程序员的工作,本来的计划是支持她丈夫哈佛法学院 3 年学业,然后就轮到她去读一个数学研究生学位。 但是阿波罗空间项目开始了。汉密尔顿在实验室开创了工程技术方面的史诗壮举,帮助改变了人类 —— 和数字技术 —— 能力所及的未来。 玛格丽特·汉密尔
企鹅号小编
2018/01/19
1.1K0
这个美女程序员写的代码,带人类成功登月
86岁「最会赚钱的数学家」Jim Simons去世,量化投资一代传奇落幕!
当地时间5月10日,数学和量化交易领域的传奇人物Jim Simons在纽约市曼哈顿的家中去世,享年86岁。
新智元
2024/05/14
1500
86岁「最会赚钱的数学家」Jim Simons去世,量化投资一代传奇落幕!
提出量子计算机的俄罗斯数学家去世了,享年85岁,门下2位菲尔兹奖得主
羿阁 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 最早提出量子计算机的人,离世了。 85岁的俄罗斯数学家尤里·曼宁(Yuri Manin)的人生故事,永远终止在了2023年1月7日这天。 这一消息震动数学界。罗格斯大学教授Alex Kontorovich表示悲痛:“他是20~21世纪数学界的巨人”。 UC伯克利数学教授Edward Frenkel将其形容为“给数学和物理领域带来巨大影响的杰出数学家”: 当我还是个十几岁的孩子时,他的作品就已经在影响我了。 对于外界来说,尤里·曼宁这个名字似乎
量子位
2023/02/28
4120
提出量子计算机的俄罗斯数学家去世了,享年85岁,门下2位菲尔兹奖得主
这位乌克兰女数学家刚拿到菲尔兹奖,战争就开始了!
---- 新智元报道   编辑:Aeneas 【新智元导读】史上第二位获得菲尔兹奖女数学家Maryna Viazovska接受了《自然》杂志的采访,讲述了菲尔兹奖的意义,自己的研究成果,以及数学领域正在发生的变化。 今年2月,乌克兰数学家Maryna Viazovska获得了数学界「诺贝尔奖」。 在颁奖的典礼上,四位获奖人中,她是唯一一位获得菲尔兹奖的女性。 值得注意的是, Viazovska还是史上第二位获得如此殊誉的女性。 数学理论家Maryna Viazovska因为解决了8维空间中的装球问题
新智元
2022/07/26
7030
这位乌克兰女数学家刚拿到菲尔兹奖,战争就开始了!
AI也脸盲 |黑人遭人脸识别技术“误判”概率竟高出白人5至10倍!
法国有一家名叫Idemia的公司,它的人脸识别软件已经在为美国、澳大利亚和法国的警方提供服务。
新智元
2019/07/30
8690
60岁华裔数学家将在美接受审判,被指控7项重罪,可能面临最高20年监禁
大数据文摘出品 Science官网新闻19日报道,60岁的华裔应用数学家Xiao Mingqing(下面简称肖)将于下周进入本顿(Benton)的联邦法庭,面临欺骗美国政府的指控,涉嫌未及时披露其与支持他研究的中国大学的关系。 从2000年开始,肖就开始在南伊利诺伊斯大学 (SIU)工作,到现在已经是第22个年头。 作为学校的老教师,肖的几位同事也计划在4月25日开庭审理时到场,他们身上的徽章上写着:“我们与肖并肩作战。” 根据报道,肖的事件仍然是2018年特朗普发起的“中国行动计划”(China Ini
大数据文摘
2022/04/22
3040
60岁华裔数学家将在美接受审判,被指控7项重罪,可能面临最高20年监禁
百岁汇编语言之母逝世!71岁时她还在和儿子合写神经网络论文
2022年9月,汇编语言之母Kathleen Booth,在加拿大去世,享年100岁。
新智元
2023/01/07
3840
百岁汇编语言之母逝世!71岁时她还在和儿子合写神经网络论文
台积电CEO、贝佐斯前妻、DeepMind 创始人上榜,《财富》公布2021伟大领袖TOP50
近日,财富杂志2021年世界最伟大领袖50强发布,DeepMind 创始人兼CEO Demis Hassabis、前谷歌AI伦理科学家Timnit Gebru、贝佐斯前妻MacKenzie Scott、台积电CEO魏哲家等人上榜。
新智元
2021/05/28
6020
台积电CEO、贝佐斯前妻、DeepMind 创始人上榜,《财富》公布2021伟大领袖TOP50
手机GPS背后的隐形人物:用纸质图手算出冥王星轨道的女数学家
GPS技术无疑已经成为了我们生活的一部分:在手机上使用行车导航,还能为Ins的照片标记位置。
大数据文摘
2020/06/01
3680
纽约时报 | 专访数学家Hannah Fry:算法的时代,人类从未如此重要
算法时代,似乎一切都可以有新的组织方式:有的算法能告诉我们读什么书、跟谁约会,甚至告诉警察应该逮捕哪个人。
大数据文摘
2018/12/18
8090
同等科研力,STEM顶尖女科学家比男性一年少挣6000美元
---- 新智元报道   编辑:桃子 武穆 【新智元导读】在STEM领域,两性在薪酬方面依然存在差别,但趋势正在向平等方向发展。|2022 IEEE北京国际女工程师领导力峰会重磅来袭,点击
新智元
2022/09/27
4080
同等科研力,STEM顶尖女科学家比男性一年少挣6000美元
黑人女性报错率比白人高20%,面部识别系统为何不能一视同仁?
面部识别系统流行于九十年代早期,当时美国国防部希望发明一种可以发现偷渡边境的不法分子的识别技术,为此投入了大量研究。为此,美国国防部为著名的大学科学家和面部识别领域的专家提供了研究经费。为此,美国国防部为著名的大学科学家和面部识别领域的专家提供了研究经费。
大数据文摘
2019/08/20
5600
黑人女性报错率比白人高20%,面部识别系统为何不能一视同仁?
奖金575万!81岁拓扑数学家摘得数学界诺奖「阿贝尔奖」
---- 新智元报道   编辑:David 拉燕 【新智元导读】3月30日(周三)下午,新智元首期元宇宙论坛「元宇宙 新人类」即将上线!详情请看今日3条~ 3月23日,「数学界的诺奖」之一——2022年阿贝尔奖揭晓! 美国纽约州立大学石溪分校教授丹尼斯·沙利文(Dennis P. Sullivan)因「在最广泛意义上的拓扑学,特别是其代数、几何和动力学方面的开创性贡献」而获奖。 位于奥斯陆的挪威科学与文学院在颁奖词中表示: 「沙利文通过引入新概念、证明标志性定理、回答旧猜想和提出新问题,一再改变了
新智元
2022/03/24
4570
「她」力量:致敬世界第一位自由女程序员,「万维网的祖母」Berners-Lee
当提到计算机编程史上的杰出女性时,你可能会想到历史第一位女性程序员 Ada Lovelace。
新智元
2021/03/10
4360
「她」力量:致敬世界第一位自由女程序员,「万维网的祖母」Berners-Lee
更偏好白人男性?Science新研究证明人工智能也能学会偏见
选自Science 机器之心编译 参与:吴攀、晏奇 至少从口号上来说,我们一直在追求「人人平等」,但我们也都清楚我们离这一目标还相去甚远,部分原因是因为世界并不是平的,还有一部分原因是我们的头脑里都还存在着偏见。现在随着人工智能技术的发展,机器已经开始具备了学习能力,那么它们在学习各种技能的同时也会学会人类的偏见吗?于本周发行的新一期 Science 期刊上就刊登了一项有关的研究结果,其表明人工智能也能习得人类的种族和性别偏见。机器之心在这里编译了 Science 网站上对于该研究的介绍以及该报告的摘要和部
机器之心
2018/05/07
6970
更偏好白人男性?Science新研究证明人工智能也能学会偏见
推荐阅读
星际迷航最迷人女上校去世了,享年89岁
2050
NASA 传奇数学家去世,她曾笔算了登月轨道
8140
NASA登月背后的女数学家去世:计算登月轨道,奥巴马授自由勋章,经历被拍成电影
8240
拯救阿波罗14号!那些伟大太空计划背后的计算机工程师们
5660
阿波罗计划50年后,美国重启载人登月!准备常驻,建立月球基地
3800
这个美女程序员写的代码,带人类成功登月
1.1K0
86岁「最会赚钱的数学家」Jim Simons去世,量化投资一代传奇落幕!
1500
提出量子计算机的俄罗斯数学家去世了,享年85岁,门下2位菲尔兹奖得主
4120
这位乌克兰女数学家刚拿到菲尔兹奖,战争就开始了!
7030
AI也脸盲 |黑人遭人脸识别技术“误判”概率竟高出白人5至10倍!
8690
60岁华裔数学家将在美接受审判,被指控7项重罪,可能面临最高20年监禁
3040
百岁汇编语言之母逝世!71岁时她还在和儿子合写神经网络论文
3840
台积电CEO、贝佐斯前妻、DeepMind 创始人上榜,《财富》公布2021伟大领袖TOP50
6020
手机GPS背后的隐形人物:用纸质图手算出冥王星轨道的女数学家
3680
纽约时报 | 专访数学家Hannah Fry:算法的时代,人类从未如此重要
8090
同等科研力,STEM顶尖女科学家比男性一年少挣6000美元
4080
黑人女性报错率比白人高20%,面部识别系统为何不能一视同仁?
5600
奖金575万!81岁拓扑数学家摘得数学界诺奖「阿贝尔奖」
4570
「她」力量:致敬世界第一位自由女程序员,「万维网的祖母」Berners-Lee
4360
更偏好白人男性?Science新研究证明人工智能也能学会偏见
6970
相关推荐
星际迷航最迷人女上校去世了,享年89岁
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档