kube-proxy源码阅读(iptables实现)

Reference

文章目录

  • 1 入口
  • 2 ProxyServer创建及调用
  • 3 ProxyServer 核心调用流程
    • 3.1 func (o *Options) Run() err
    • 3.2 func (o *Options) runLoop() error
    • 3.3 func (s *ProxyServer) Run() error
    • 3.4 func (proxier *Proxier) SyncLoop()
  • 4 资源事件处理流程
    • 4.1 Service事件
    • 4.2 Endpoints事件
    • 4.3 Nodes事件
    • 4.4 func (proxier *Proxier) Sync()
  • 5 代理规则同步处理流程
  • 6 数据包路径及链位置
    • 6.1 PREROUTING
      • 6.1.1 PREROUTING ->KUBE-SERVICES
      • 6.1.2 KUBE-SERVICES
        • 6.1.2.1 ClusterIP
          • 6.1.2.1.1 KUBE-SERVICES->KUBE-MARK-MASQ
          • 6.1.2.1.2 KUBE-SERVICES->KUBE-SVC-HASH
        • 6.1.2.2 External IP
          • 6.1.2.2.1 KUBE-SERVICES->KUBE-MARK-MASQ
          • 6.1.2.2.2 KUBE-SERVICES->KUBE-SVC-HASH
        • 6.1.2.3 LB IP
          • 6.1.2.3.1 KUBE-SERVICES->KUBE-FW-HASH
          • 6.1.2.3.2 KUBE-FW-HASH->KUBE-MARK-MASQ
          • 6.1.2.3.3 KUBE-FW-HASH->KUBE-SVC-HASH
          • 6.1.2.3.4 KUBE-FW-HASH->KUBE-MARK-DROP
        • 6.1.2.4 NodePort
          • 6.1.2.4.1 KUBE-SERVICES->KUBE-NODEPORTS
          • 6.1.2.4.2 KUBE-NODEPORTS->KUBE-MARK-MASQ
          • 6.1.2.4.3 KUBE-NODEPORTS->KUBE-SVC-HASH
        • 6.1.2.5 KUBE-SVC-HASH -> KUBE-SEP-HASH
        • 6.1.2.6 KUBE-SEP-HASH
    • 6.2 INPUT
      • 6.2.1 FILTER INPUT ->KUBE-SERVICES
      • 6.2.2 FILTER INPUT ->KUBE-EXTERNAL-SERVICES
    • 6.3 FORWARD
      • 6.3.1 FORWARD-> KUBE-FORWARD
      • 6.3.2 FORWARD-> KUBE-SERVICES
    • 6.4 OUTPUT
      • 6.4.1 NAT OUTPUT-> KUBE-SERVICES
      • 6.4.2 NAT OUTPUT-> KUBE-SERVICES
    • 6.5 POSTROUTING
      • 6.5.1 NAT POSTROUTING -> KUBE-POSTROUTING
  • 7 总结

1 入口

cmd目录下的proxy.go

 利用Cobra构建CLI接口,并对proxy server进行调用。

kubernetes/cmd/kube-proxy/proxy.gofunc main() {rand.Seed(time.Now().UnixNano())// 核心调用command := app.NewProxyCommand()// TODO: once we switch everything over to Cobra commands, we can go back to calling// utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the// normalize func and add the go flag set by hand.pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)// utilflag.InitFlags()logs.InitLogs()defer logs.FlushLogs()if err := command.Execute(); err != nil {os.Exit(1)}
}

2 ProxyServer创建及调用

kubernetes/cmd/kube-proxy/app/server.gofunc NewProxyCommand() *cobra.Command {.....cmd := &cobra.Command{......Run:func(cmd *cobra.Command, args []string) {......opts.Run()}}.....opts.config, err = opts.ApplyDefaults(opts.config).....
}

ApplyDefaults中会配置默认的参数。/pkg/proxy/apis中的init方法内,会向SchemeBuilder注册添加默认参数的方法。这里面对于Porxy会注册SetObjectDefaults_KubeProxyConfiguration,最后调用了SetDefaults_KubeProxyConfiguration其中IPTables.SyncPeriod.Duration,默认值为30S(该值为失败后的尝试retry间隔,可以使用–iptables-sync-period配置,其指定了iptables重刷新的最大间隔)

kubernetes/cmd/kube-proxy/app/server.gofunc (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}if o.CleanupAndExit {return proxyServer.CleanupAndExit()}o.proxyServer = proxyServerreturn o.runLoop()
}
注意:这里BounedFrequencyRunner的同步方法为proxier.syncProxyRules,最小时间间隔为minSyncPeriod(可以使用参数--iptables-min-sync-period配置,未配置时,应该就是0),最大时间间隔为1小时,突发数为2,失败重试间隔为proxier.syncPeriod(默认为30秒,可以用参数--iptables-sync-period配置,其指定了iptables重刷新的最大间隔,不允许为0)

3 ProxyServer 核心调用流程

opts.Run()->

o.runLoop()->

o.proxyServer.Run()->

s.Proxier.SyncLoop()

3.1 func (o *Options) Run() err

在构建ProxyCommand时,会在其Run方法内调用该方法

  • (1)如kube-proxy命令调用时,传入了–write-config-to参数,则会将kube-proxy的默认配置打印到指定文件,然后退出。
  • (2)调用NewProxyServer方法,构建proxyServer
  • (3)如果kube-proxy命令调用时传入了–cleanup参数,则会清理iptables及ipvs配置,然后退出
  • (4)调用o.runLoop方法。

3.2 func (o *Options) runLoop() error

  • (1)如果o.Watcher(用于监听ConfigFile的更新变化)不为空,则调用o.watcher.Run()(这里如果监听到配置文件的写或者rename事件,会导致kube-proxy的退出)
  • (2)调用o.proxyServer.Run()

3.3 func (s *ProxyServer) Run() error

  • (1)如果启动参数中配置了–oom-score-adj(oom打分调整,OOM killer 会给进程打分,把 oom_score 最大的进程先杀死,如果这个值设置成负数,则表明不优先级杀死它,如果位正数则优先杀死,如果设置为0表明与用户不调整)。则为kube-proxy配置该值
  • (2)如果Broadcaster及EventClient不为空,则开启事件记录服务
  • (3)如果健康检查服务不会空,则启动
  • (4)如果指标绑定地址大于0,则启动服务
    • 1)curl 10.19.188.3:10249/proxyMode, 可以获得proxyMode运行模式
    • 2)curl curl 10.19.188.3:10249/metrics, 可以获得运行指标信息
  • (5)如过contracker会为空,则根据启动参数,配置系统contracker配置。(这里我们会把所有的contracker相关配置设置为0, 即不修改系统原先的conntrack配置)
    • 1)首先调用getConntrackMax,如果–conntrack-max-per-core参数不为空,且值大于0(不配置时,默认值为32768),则用其乘以cpu数,获取上限值,如果该值大于配置中的–conntrack-min,则返回该值,否则返回–conntrack-min。否则返回0
    • 2)如果max值大于0,则更新系统配置
    • 3)如果配置了–conntrack-tcp-timeout-close-wait duration,且其值大于0, 则更新系统值
    • 4)如果配置了–conntrack-tcp-timeout-established,且其值大于0,则更新系统中的该值。
  • (6)构建kube-proxy监听的server的选择器,及Informer(对于具有service.kubernetes.io/service-proxy-name及service.kubernetes.io/headless label的service不处理),注册service事件处理器,并启动
  • (7)如果使用EndpointSlices,则构建endpointsSlice事件处理器,并启动。否则构建endpoints事件处理器,并启动。
  • (8)启动informer
  • (9)如果使用了ServiceTopology门特性,则增加nodeInformer,及相关事件处理器,并启动
  • (10)记录启动事件
  • (11)调用s.Proxier.SyncLoop

3.4 func (proxier *Proxier) SyncLoop()

  • (1)如果proxier的健康检查服务不为空,则调用其update函数
  • (2)调用proxier.syncRunner.Loop(wait.NeverStop)

4 资源事件处理流程

在NewProxier时,会为其构建syncRunner,其绑定的处理函数为syncProxyRules。同时,调用ipt.Monitor(Monitor通过创建canary chain和轮询来检测给定的iptables表是否已被外部工具(例如,重新加载防火墙)刷新。 (具体来说,它每隔一段时间轮询[0]表,直到canary chain从表中删除,然后再等待一段额外的时间,以便从其余的表中也删除canary chain。 您可以通过在表[0]中列出一个相对空的表来优化轮询。 当检测到刷新时,将调用reloadFunc,以便调用者可以重新加载自己的iptables规则。 如果它无法创建检测链(无论是最初还是重新加载后),它将记录一个错误并停止监视。 (这个函数应该从goroutine中调用。))

4.1 Service事件

service Add\Update\Delete事件,会记录service变化,加入到proxier的serviceChanges中,并会调用proxier.Sync()方法

4.2 Endpoints事件

Endpoints Add\Update\Delete事件,会记录endpoints变化,加入到proxier的endpointsChanges中,会调用proxier.Sync()方法

4.3 Nodes事件

Nodes的Add\Update\Delete事件, 会调用proxier.syncProxyRules()

4.4 func (proxier *Proxier) Sync()

  • (1)如果proxier.healthzServer 不为空,则调用QueuedUpdate方法。会存储,事件时间。
  • (2)调用proxier.syncRunner.Run(),该方法会导致尝试调用syncProxyRules

5 代理规则同步处理流程

service/endpoints/node事件,最后都会导致syncProxyRules函数的调用

  • (1)如果proxier还没有初始化,则直接打印日志信息,返回.即只有在informer收到services和endpoints以后,才会进行真正的配置同步。
  • (2)构建defer func,记录其观察到的指标信息
  • (3)调用UpdateServiceMap,基于给定的ServiceChangeTracker,返回更新结果UpdateServiceMapResult,其包含了HCServiceNodePorts(HCServiceNodePorts是服务名称到节点端口号的映射,该映射指示该节点上该服务的健康状况)和UDPStaleClusterIP(持有UDP端口的过期的(不再分配给服务)Service IPs.调用者可以使用此信息中止超时等待或清除连接跟踪信息。)
    • 1)构建空Set集合赋值给UDPStaleClusterIP
    • 2)将ServiceChangeTracker中每个change的Current ServiceMap merge到proxier.ServiceMap中。用Curent ServiceMap 过滤change的Previous ServiceMap(即change的Previous ServiceMap中移除svcPortName中还在Curent中的项,剩下的就是无效的port),从proxier.ServiceMap中unmerge这些变化,同时将这些port中协议类型为TCP的ClusterIP加入到UDPStaleClusterIP集合中(svcPortName对象由ns,servicePort.Name,servicePort.Protocol组成。只有LB类型和NoePort类型Service才有可能会有HealthCheckNodePort–我们没有使用到这个字段)
    • 构建空HCServiceNodePorts集合
    • 遍历Merge以后的ServiceMap,如果其健康检查端口不为空,则将其加入到HCServiceNodePorts中。
  • (4)调用endpointsMap,基于endpoints变化,更新proxy.EndpointsMap,返回UpdateEndpointMapResult(包含HCEndpointsLocalIPSize–与kube-proxy同节点的endpoints的集合,StaleEndpoints–过期的endpoint service对,StaleServiceNames过期的service名字集合,LastChangeTriggerTimes所有endpoints变化的触发时间)
    • 1)构建空StaleEndpoints、StaleServiceNames、LastChangeTriggerTimes map
    • 2)调用apply方法,更新EndpointsMap,并用staleEndpoints存储不新鲜的 udp endpoints,用staleServiceNames 用于存储不新鲜的udp service .
    • 3)基于合并后的endpointsMap,获取本地的endpoints,填充HCEndpointsLocalIPSize。
  • (5)将endpointUpdateResult中的StaleServiceNames和serviceUpdateResult中的UDPStaleClusterIP进行合并,存入到staleServices中(里面记录了clusterIP以及ExternalIP)
  • (6)遍历iptablesJumpChains(kube-proxy在iptables原有链上,新建的Jump链)。确保每条目标Jump链,在表上存在(尝试去创建,如果创建失败,则根据返回值判断是否已经存在,如果创建失败,直接return).确保在源链上插入Jump规则,即kube-chanin(首先判断规则是否存在,如果不存在,则插入,这里应该是插入到表头位置)
  • (7)构建existingFilterChains map,清理proxier的existingFilterChainsData。
  • (8)调用SaveInto方法,将Filter表内的信息写入到proxier的existingFilterChainsData。(底层调用的命令:iptables-save -t filter)
# iptables-save -t filter 查询得到的结果中间省略了部分
*filter
:INPUT ACCEPT [272947:113632328]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [269953:157912430]
:KUBE-EXTERNAL-SERVICES - [0:0]
:KUBE-FIREWALL - [0:0]
:KUBE-FORWARD - [0:0]
:KUBE-KUBELET-CANARY - [0:0]
:KUBE-PROXY-CANARY - [0:0]
:KUBE-SERVICES - [0:0]
-A INPUT -j KUBE-FIREWALL
  • (9)如果获取失败则打印日志信息。如果获取成功,则从proxier.existingFilterChainsData中获取ChainLine,存入到existingFilterChains中,其中key值为Chain名字,value为该行的值(比如:KUBE-SERVICES - [0:0])
  • (10)构建existingNATChains map,清理proxier的iptablesData。
  • (11)调用SaveInto方法,将NAT表内的信息写入到proxier的iptablesData。(底层调用的命令:iptables-save -t nat)
  • (12)如果获取失败则打印日志信息。如果获取成功,则从proxier.iptablesData中获取ChainLine,存入到existingNATChains中,其中key值为Chain名字,value为该行的值(比如:KUBE-SERVICES - [0:0])
  • (13)清理proxier.filterChains、proxier.filterRules、proxier.natChains及natRules.
  • (14)往proxier.filterChains写入表头即*filter
  • (15)往proxier.natChains写入表头即*nat
  • (16)遍历filter表中的Jump链名字(KUBE-SERVICES、KUBE-EXTERNAL-SERVICES、KUBE-FORWARD),如果existingFilterChains中存在该名字,则将其对应的行信息写入到proxier.filterChains,如果不存在(考虑获取proxier.existingFilterChainsData失败),则构建对应的ChainLine写入到proxier.filterChains中。(此时,proxier.filterChains包含了KUBE-SERVICES、KUBE-EXTERNAL-SERVICES以及KUBE-FORWARD链行信息)
  • (17)遍历nat表中的Jump链名字(KUBE-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING、KUBE-MARK-MASQ),如果existingNatChains中存在,则将其对应的行信息写入到proxier.natChains,如果不存在(考虑获取proxier.existingNatChainsData失败),则构建对应的ChainLine写入到proxier.natChains中。(此时,proxier.natChains包含了KUBE-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING以及KUBE-MARK-MASQ链信息)
  • (18)构建masqRule(该规则负责匹配带有0x4000/0x4000 mark的数据包,将其交给MASQUERADE处理)
masqRule := []string{"-A", string(kubePostroutingChain),"-m", "comment", "--comment", `"kubernetes service traffic requiring SNAT"`,"-m", "mark", "--mark", proxier.masqueradeMark,"-j", "MASQUERADE",}
# 其中:
# kubePostroutingChain:KUBE-POSTROUTING
# masqueradeMark:由--iptables-masquerade-bit决定,
masqueradeValue = 1 << uint(14)
masqueradeMark = fmt.Printf("%#08x/%#08x", masqueradeValue, masqueradeValue)
--iptables-masquerade-bit默认为14,这则masqueradeMark默认为0x4000/0x4000# iptables nat表中对应的规则
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
# 可以通过该命令查看 
iptables -t nat -L KUBE-POSTROUTING 
  • (19)如果iptables支持RandomFully(iptables版本大于1.6.2,参考iptables.go)。则在masqRule中添加–random-fully参数(避免linux内核问题,多个流映射到相同的IP:PORT)
  • (20)将masqRule加入到proxier.natRules中。
  • (21)向proxier.natRules中,加入set-xmark规则
writeLine(proxier.natRules, []string{"-A", string(KubeMarkMasqChain),"-j", "MARK", "--set-xmark", proxier.masqueradeMark,}...)
其中:
KubeMarkMasqChain:KUBE-MARK-MASQ
proxier.masqueradeMark:默认为0x4000/0x4000
# 可以通过该命令查询
iptables -t nat -L KUBE-MARK-MASQ
  • (22)构建activeNATChains map,其累积需要保存的NAT链
  • (23)构建replacementPortsMap,累积一旦更新完成,我们将保持打开的本地端口集
  • (24)构建空endpoints信息及endpointChains slice。
  • (25)置proxier.endpointChainsNumber为0, 通过遍历proxier.serviceMap,累加所有serviceName对应的endpointsMap长度,获取proxier.endpointChainsNumber值
  • (26)遍历service,为每个service构建规则
    • 1)获取svcInfo(包括了svc的基础信息,以及serviceNameString、servicePortChainName、serviceFirewallChainName、serviceLBChainName )
      • a)servicePortChainName: KUBE-SVC-svc端口名字(namespace + name + portname)及协议Hash
      • b)serviceFirewallChainName:KUBE-FW-svc端口名字及协议Hash
      • c)serviceLBChainName: KUBE-XLB–svc端口名字及协议Hash
    • 2)判读clusterIP类型
    • 3)获取svcInfo协议类型(TCP or UDP or SCP)
    • 4)获取svcName对应的endpoints,记为allEndpoints
    • 5)基于allEndpoings,获取hasEndpoints属性
    • 6)如果有endpoints,则判断当前svcInfo对应的svcChain是否在existingNATChains中,如果时,将对应行信息写入到proxier.natChains中。否则构建对应svcChainLine.并在activeNATChains中记录该chain( existingNATChains中的行信息基于iptables-save -t nat生成,比如:KUBE-SVC-5SLFW5ITLOQQHB35 - [0:0])
    • 7)如果service是LB或NodePort类型Service,且service.Spec.ExternalTrafficPolicy为Local,即转发时,只允许转发给本地容器,保证源IP地址不变,则判断svcInfo对应serviceLBChainName是否已经存在,如果存在则将行信息写入到proxier.natChains,否则构建新的写入到proxier.natChains,同时在activeNATChains中记录该chain。
    • 8)如果有endpoints,构建该svc的masquerad规则(追加到KUBE-SERVICES链,匹配规则为目的IP为ClusterIP,协议为svc协议,端口为svc端口,查询命令iptables -t nat -L KUBE-SERVICES)及跳转SVC链规则.
      • a) 如果proxier.masqueradeAll为真,则在proxier.natRules中加入该svc的masquerad规则,目的链为KUBE-MARK-MASQ.
      • b) 如果不为真,且kube-proxy在启动时配置了启动参数–cluster-cidr(cluster-cidr主要用于帮助 kube-proxy 区分内外流量。当值为空时,kube-proxy认为所有流量都是内部流量,不做SNAT(MASQ)即c情况。当值非空时,来自 cluster-cidr 网络(即 Pod网络)的流量被当成内部流量,访问 Service 时不做 SNAT(MASQ),来自其他网络的流量被当成外部流量,访问 Service 时需要做 SNAT(MASQ),如果配置了masqueradeAll,则所有流量都要做SNAT),则在匹配规则中额外添加源地址不允许是proxier.clusterCIDR(该规则将非cluster IP流量masquerades到一个service VIP。这么做可以通过为Sevice Ranage建立静态路由,将流量路由到任意节点,而该节点将会为你连接到Service内。因为可能会跳离节点,因此需要在这里masquerade。当我们支持"Local"策略时,应该更新它)。目的链为KUBE-MARK-MASQ**
      • c)往proxier.natRules追加KUBE-SVC-HASH(hash值基于NamespacedSVCName、PortName、Protocol计算得到)
      • d)如果不为真,且kube-proxy在启动时没有配置启动参数–cluster-cidr,则目的链为svcChain(这种情况认为所有的流量都是内部流量,不做MASQ)
    • 9)如果没有endpoints,则往proxier.filterRules的KUBE-SERVICES链中追加REJECT规则
    • 10)遍历svcInfo中的外部IP地址。(目前我们没有使用这个字段)
      • A)如果该IP地址不是本地系统设备上的某个地址,则打印日志信息。
      • B)如果该IP地址是本地系统设备上的某个地址,且协议类型不为SCTP。
        • a)构建LocalPort lb(IP、Port、Protocol)
        • b)如果proxier.portsMap中存在该端口,更新replacementPortsMap[lb] = proxier.portsMap[lp]
        • c)如果不存在,则在本地打开端口,返回得到socket,replacementPortsMap[lb] = socket
      • C)如果有endpoints。则构建nat规则,追加到KUBE-SERVICES链表,匹配协议为svc协议,目的端口为svc端口,目的链为KUBE-MARK-MASQ。该规则负责SNAT到external IPs。构建externalTrafficOnly规则,其在上一个规则基础上增加了匹配规则,其允许非来自bridge或本地进程的流量z转发到service,即外部来的流量。构建dstLocalOnlyArgs规则,其在第一个规则基础上,增加匹配规则,允许被识别为本地ip的外部ip绑定的流量留在本地。
      • D)如果没有,则往proxier.filterRules的KUBE-SERVICES链中追加REJECT规则。
    • 11)遍历svcInfo中的LoadBalancerIPStrings,对ingress不为空的svcInfo做处理。
      • A)如果有后端。则判断对应FirewallChain名字是否在existingNATChains中存在,如果存在则写入到proxier.natChains中。否则则新建后写入(:KUBE-FW-5SQY75UPE7NMO5UB - [0:0]).并更新activeNATChains[fwChain] = true
        • b)构建nat规则,在KUBE-SERVICE链表中,追加匹配LB协议、目的IP、目的端口时,跳转入fwChain的规则。
        • c)chosenChain := svcXlbChain
        • d)构建nat规则,在fwChain中追加。如果svcInfo不是OnlyNodeLocalEndpoints,则目标链为KUBE-MARK-MASQ。chosenChain = svcChain。
        • e)如果svcInfo.LoadBalancerSourceRanges长度为0(该字段确定了可以访问LB的客户端IP),则目标链为choseChine
        • f)如果svcInfo.LoadBalancerSourceRanges长度不为0,则匹配规则为源来自oadBalancerSourceRanges,目标地址为chosenChain.
        • g)添加默认丢弃规则,KUBE-MARK-DROP
      • B)如果没有,则往proxier.filterRules的KUBE-SERVICES链中追加REJECT规则。
      1. 如果svc的NodePort不为0
      • A)基于配置,在本机设备上找到所有在proxier.nodePortAddresses(–nodeport-addresses启动参数决定)内的address。
      • B)遍历address,基于每个Address生成LocalPort对象(IP=address,Port=svcInfo.NodePort,protocol=svcInfo.protocol)。
      • C)遍历这些LocalPort对象,
        • a)如果其存在与proxier.portsMap[lp],则replacementPortsMap[lp] = proxier.portsMap[lp]。
        • b)否则当协议类型不是ProtocolSCTP时,构建对应socket,同时对于udp清理链接状态.更新replacementPortsMap[lp] = socket
        • c)如果具有endpoints,则往KUBE-NODEPORTS链添加规则。如果svcInfo不是OnlyNodeLocalEndpoints,则往proxier.natRules添加跳转到KUBE-MARK-MASQ及svcChain.否则对于源IP地址为回环地址的数据包,配置JUMP为KUBE-MARK-MASQ,其它jump到svcXlbChain.
        • c)如果没有,则往proxier.filterRules的KUBE-SERVICES链中追加REJECT规则。
      • 13)如果没有endpoints,则处理下一个svcInfo
      • 14)刷新endpoints及endpointChain链表
      • 15)遍历当前svcInfo对应的endpoints
        • A)获取epInfo(协议,chainName=KUBE-SEP-svcName+protocol+endpoint的哈希值)
        • B)将epInfo加入到endpoints slice中
        • C)构建endpointChain,并将其加入到endpointChains slice中
        • D)如果它已经存在于existingNATChains中则将其对应行信息写入到proxier.natChains中,否则构建新Chain,写入其中(:KUBE-SEP-ZM2K5WAG2QZ6VDLK - [0:0]).置activeNATChains[endpointChain] = true
      • 16)如果svcInfo.SessionAffinityType == ServiceAffinityClientIP(基于客户端源IP的亲和性)。遍历endpointChains slice,为每个endpointsChain在svcChain中添加会话保持规则。
      • 17)遍历endpointChains
        • A) 如果svcInfo.OnlyNodeLocalEndpoints为true,且当前endpoint在本机器上。则将其加入到localEndpoints,并将对应endpoinChain加入到localEndpointChains
        • B)获取EP.IP, 如果IP不存在,则跳过处理
        • C)基于endpointChain当前索引,计算其概率,构建nat规则,加入到endpointChain中(-A KUBE-SVC-PRPXIF4GQR5KDAOQ -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-N66C6CFW2S6AAC7V)。如果是最后一个endpoint,则不需要-m statistic --mode random --probability 0.50000000000配置。
        • D)往endpointChain中添加nat规则,对于源IP地址是epIP地址的数据包,跳转进入KUBE-MARK-MASQ。其用于用SNAT处理返回到发起者的通讯
        • E)如果具有客户端亲和性,则更新参数,加入亲和性配置
        • F)更新参数加入DNAT动作,往endpointChain中加入该DNAT规则(如果有客户端IP亲和性,相当于在这个规则里多加了-m recent --name endpointChain --set参数。不加情况下,规则可能为DNAT tcp – anywhere anywhere tcp to:172.20.0.22:8443)。
        • G)如果!svcInfo.OnlyNodeLocalEndpoints(),则处理下一个svcInfo
        • H)clusterCIDR大于0时,svcXlbChain中加入nat规则,对于源来自clusterCIDR的,跳入svcChain处理。(重定向尝试访问LB IP的pod,访问ClusterIP)
        • I)构建并添加重定向规则,对于externalTrafficPolicy=Local的svc,将所有src-type=Local->LB IP的数据包重顶下到svcChain.
        • J)如果本地的localEndpointChains等于0,则往svcXlbChain中添加规则,跳转到KUBE-MARK-DROP,即该机器上没有这个svc的pod,而这个pod又不允许转发到别的节点,因此就丢弃了。
        • K)否则,在svcXlbChain 为local endpoints添加robability filter rules
  • 27)遍历existingNATChains,对于非激活链,且由kube-proxy构建的,往proxier.natRules中添加删除规则
  • 28)如果在本机设备存在NodePort地址,则为这些地址在KUBE-SERVICES链中添加nat规则,对于目的地址类型为本地的地址,跳入KUBE-NODEPORTS处理。
  • 29)构建filter规则,往KUBE-FORWARD链中增加状态为INALID的数据包的丢包处理规则
  • 30)构建filter规则,往KUBE-FORWARD链中增加mark为proxier.masqueradeMark的数据包的接收处理规则。
  • 31)如果proxier.clusterCIDR长度大于0。
    • A)构建filter规则,往KUBE-FORWARD链中添加,对于源IP是proxier.clusterCIDR,或者与其相关的,数据包Accept规则。
    • B)构建filter规则,往KUBE-FORWARD链中添加,对于目的IP是proixer.clusterCIDR,或者与其相关的,数据包Accept规则。
  • 32)清理proxier.iptablesData,往其中写入proxier.filterChains.Bytes()、proxier.filterRules.Bytes()、proxier.natChains.Bytes()、proxier.natRules.Bytes()。
  • 33)重新存储iptables data
  • 34)更新指标及健康检查信息
  • 35)清理无效UDP链接信息。

6 数据包路径及链位置

在这里插入图片描述

 kube-proxy在开始下发svc\ep相关规则前,会现往filter表追加KUBE-SERVICES、KUBE-EXTERNAL-SERVICES、KUBE-FORWARD链跳转规则,会往nat表追加入KUBE-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING、KUBE-MARK-MASQ链跳转规则。并为KUBE-POSTROUTING及KUBE-MARK-MASQ链添加默认规则。

# KUBE-POSTROUTING
# Add Rule
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING# Show Rule
iptables -t nat -L KUBE-POSTROUTING# Show Result
Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere             /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000-----------------------------------------------------------------------------------# KUBE-MARK-MASQ
# Add Rule
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE# Show Rule
iptables -t nat -L KUBE-MARK-MASQ# Show Result
Chain KUBE-MARK-MASQ (63 references)
target     prot opt source               destination         
MARK       all  --  anywhere             anywhere             MARK or 0x4000

6.1 PREROUTING

6.1.1 PREROUTING ->KUBE-SERVICES

NAT表的PREROUTING链中加入了,KUBE-SERVICES链跳转规则。对于所有的数据包,跳转入KUBE-SERVICES链处理

# Add Rule
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES# Show Rule
iptables -t nat -L PREROUTING# Show Result 
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
KUBE-SERVICES  all  --  anywhere             anywhere             /* kubernetes service portals */

6.1.2 KUBE-SERVICES

数据包经过NAT表PREROUTING链中规则匹配,进入KUBE-SERVICE链处理

6.1.2.1 ClusterIP

6.1.2.1.1 KUBE-SERVICES->KUBE-MARK-MASQ

kube-proxy会遍历每个svcInfo,根据clusterIP、启动参数–cluster-cidr及–masquerade-all来配置, jump到KUBE-MARK-MASQ链的匹配规则。

  • (1) 配置了–masquerade-all,认为所有流量都是外部流量,都要打标签
# Add Rule
-A KUBE-SERVICES -d 10.68.81.30/32 -p tcp -m comment --comment "demo/s-test-mq:tcp-5672 cluster IP" -m tcp --dport 5672 -j KUBE-MARK-MASQ
  • (2)–cluster-cidr不为空,认为–cluster-cidr指定网段为内部网段不需要打标签,其它流量为外部流量需要打标签
# Add Rule
-A KUBE-SERVICES ! -s 172.20.0.0/16 -d 10.68.81.30/32 -p tcp -m comment --comment "demo/s-test-mq:tcp-5672 cluster IP" -m tcp --dport 5672 -j KUBE-MARK-MASQ
  • (3)–cluster-cidr为空,认为所有流量都是内部流量,都不打标签,在POSTROUTING时,不需要SNAT

KUBE-MARK-MASQ链内规则会为进入链的所有数据包打上0x4000/0x4000标签(进行完此处理动作后,将会继续比对其它规则)

# Show Rule
iptables -t nat -L KUBE-MARK-MASQ# Show Result
Chain KUBE-MARK-MASQ (63 references)
target     prot opt source               destination         
MARK       all  --  anywhere             anywhere             MARK or 0x4000
6.1.2.1.2 KUBE-SERVICES->KUBE-SVC-HASH

kube-proxy会在KUBE-SERVICES中为每个具有clusterIP的 svcPort构建KUBE-SVC-HASH跳转规则,将访问svcPort的数据包,导入到KUBE-SVC-HASH链中

# Add Rule
-A KUBE-SERVICES -d 10.68.249.16/32 -p tcp -m comment --comment "demo/netutil-2:tcp-8081 cluster IP" -m tcp --dport 8081 -j KUBE-SVC-QUZXUNUIPD3MZETI# Show Rule
KUBE-SVC-QUZXUNUIPD3MZETI  tcp  --  anywhere             10.68.249.16         /* demo/netutil-2:tcp-8081 cluster IP */ tcp dpt:tproxy

6.1.2.2 External IP

对于External IP,只有当前物理机上设备有这个地址时,kube-proxy才会下发规则.kube-proxy首先在本地使用External IP及svcPort、Protocol打开一个端口,然后下发规则。

6.1.2.2.1 KUBE-SERVICES->KUBE-MARK-MASQ

kube-proxy会在KUBE-SERVICES内,为每个External IP添加KUBE-MARK-MASQ跳转规则,对于目的地址为External IP的数据包丢入KUBE-MARK-MASQ打mark

# 查询
iptables-save -t nat | grep external # Add rule
-A KUBE-SERVICES -d 公网IP地址 /32 -p tcp -m comment --comment "demo/hk-nginx-hello:tcp-80 external IP" -m tcp --dport 80 -j KUBE-MARK-MASQ# 查询
iptables -t nat  -L KUBE-SERVICES | grep "external IP" | grep MARK# 结果
KUBE-MARK-MASQ  tcp  --  anywhere  地址这里显示的主机名  /* demo/hk-nginx-hello:tcp-80 external IP */ tcp dpt:http
6.1.2.2.2 KUBE-SERVICES->KUBE-SVC-HASH

kube-proxy会在KUBE-SERVICES内,为每个External IP添加KUBE-SVC-HASH跳转规则

# Add rule
-A KUBE-SERVICES -d 公网IP地址 /32 -p tcp -m comment --comment "demo/hk-nginx-hello:tcp-80 external IP" -m tcp --dport 80 -m physdev ! --physdev-is-in -m addrtype ! --src-type LOCAL -j KUBE-SVC-UEOQSLEZ4LUM4H7G
-A KUBE-SERVICES -d 公网IP地址 /32 -p tcp -m comment --comment "demo/hk-nginx-hello:tcp-80 external IP" -m tcp --dport 80 -m addrtype --dst-type LOCAL -j KUBE-SVC-UEOQSLEZ4LUM4H7G# show ruleiptables -t nat  -L KUBE-SERVICES | grep "external IP" | grep -v MARK# 非本地请求,转发到svc
KUBE-SVC-UEOQSLEZ4LUM4H7G  tcp  --  anywhere  地址这里显示的主机名  /* demo/hk-nginx-hello:tcp-80 external IP */ tcp dpt:http PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL# 本地请求转发到svc
KUBE-SVC-UEOQSLEZ4LUM4H7G  tcp  --  anywhere  地址这里显示的主机名  /* demo/hk-nginx-hello:tcp-80 external IP */ tcp dpt:http ADDRTYPE match dst-type LOCAL

6.1.2.3 LB IP

6.1.2.3.1 KUBE-SERVICES->KUBE-FW-HASH

kube-proxy会为每个具有LB IP的svcPort构建KUBE-FW-HASH跳转规则,将访问LBIP:svcPort(协议+端口)的数据包,导入到KUBE-FW-HASH链中

# Add Rule
-A KUBE-SERVICES -d 公网IP地址 /32 -p tcp -m comment --comment "demo/netutil-2:tcp-8081 loadbalancer IP" -m tcp --dport 8081 -j KUBE-FW-QUZXUNUIPD3MZETI# Show Rule
KUBE-FW-QUZXUNUIPD3MZETI  tcp  --  anywhere             公网IP地址       /* demo/netutil-2:tcp-8081 loadbalancer IP */ tcp dpt:tproxy
6.1.2.3.2 KUBE-FW-HASH->KUBE-MARK-MASQ

对于进入KUBE-FW-HASH链的所有数据包进入KUBE-MARK-MASQ,打上0x4000/0x4000标记

6.1.2.3.3 KUBE-FW-HASH->KUBE-SVC-HASH

打完MASQ的数据包,进入链表KUBE-SVC-QUZXUNUIPD3MZETI处理(如果这个时候有后端,会把数据包按概率丢给链KUBE-SVC-QUZXUNUIPD3MZETI-HASH处理)

# Show Rule
iptables -t nat -L KUBE-FW-QUZXUNUIPD3MZETI# Show Rule
Chain KUBE-FW-QUZXUNUIPD3MZETI (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  all  --  anywhere             anywhere             /* demo/netutil-2:tcp-8081 loadbalancer IP */
KUBE-SVC-QUZXUNUIPD3MZETI  all  --  anywhere             anywhere             /* demo/netutil-2:tcp-8081 loadbalancer IP */
KUBE-MARK-DROP  all  --  anywhere             anywhere             /* demo/netutil-2:tcp-8081 loadbalancer IP */
6.1.2.3.4 KUBE-FW-HASH->KUBE-MARK-DROP

对于没有endpoint的数据包,不会在KUBE-SVC-HASH中匹配,进入KUBE-MARK-DROP链表处理,会打上0x8000/0x8000标记(这些数据包会在filter被过滤丢弃)

6.1.2.4 NodePort

6.1.2.4.1 KUBE-SERVICES->KUBE-NODEPORTS

kube-proxy会在KUBE-SERVICES链中构建KUBE-NODEPORTS链,将不匹配ClusterIP、LB规则的数据包导入到KUBE-NODEPORTS链中处理

iptables -t nat -L KUBE-SERVICES| grep KUBE-NODEPORTS
6.1.2.4.2 KUBE-NODEPORTS->KUBE-MARK-MASQ

kube-proxy在KUBE-NODEPORTS中添加规则,匹配目标端口是否为NodePort,如果是,将数据包导入KUBE-NODEPORTS,打上MASQ标记

6.1.2.4.3 KUBE-NODEPORTS->KUBE-SVC-HASH

kub-proxy在KUBE-NODEPORTS中添加规则,匹配目标端口是否为NodePort,如果是将数据包导入到KUBE-SVC-HASH链处理

iptables -t nat -L KUBE-NODEPORTS

6.1.2.5 KUBE-SVC-HASH -> KUBE-SEP-HASH

kube-proxy会在KUBE-SVC-HASH链内为svcPort的每个endpoint构建基于概率的 KUBE-SEP-HASH跳转规则,并为每个endpoint构建KUBE-SEP-HASH规则

# Add Rule
-A KUBE-SVC-QUZXUNUIPD3MZETI -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-AMWXJCMBQ4RG26Q5
-A KUBE-SVC-QUZXUNUIPD3MZETI -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2OQUDCMHKG5JUGZU
-A KUBE-SVC-QUZXUNUIPD3MZETI -j KUBE-SEP-Z2UJWNX76VNMX7FW# Rule show 
iptables -t nat -L KUBE-SVC-QUZXUNUIPD3MZETI# Show Result 
Chain KUBE-SVC-QUZXUNUIPD3MZETI (2 references)
target     prot opt source               destination         
KUBE-SEP-AMWXJCMBQ4RG26Q5  all  --  anywhere             anywhere             statistic mode random probability 0.33333333349
KUBE-SEP-2OQUDCMHKG5JUGZU  all  --  anywhere             anywhere             statistic mode random probability 0.50000000000
KUBE-SEP-Z2UJWNX76VNMX7FW  all  --  anywhere             anywhere  

6.1.2.6 KUBE-SEP-HASH

  • (1)对于源IP地址为172.20.4.10的数据包进行MARK。endPoint 访问SVC的情况。
  • (2)对数据包进行DNAT,将目的IP地址从Service CluterIP NAT为Pod IP
# Add Rule
-A KUBE-SEP-AMWXJCMBQ4RG26Q5 -s 172.20.4.10/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-AMWXJCMBQ4RG26Q5 -p tcp -m tcp -j DNAT --to-destination 172.20.4.10:8091# Show Rule
iptables -t nat -L KUBE-SEP-AMWXJCMBQ4RG26Q5# Show Result
Chain KUBE-SEP-AMWXJCMBQ4RG26Q5 (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  all  --  172.20.4.10          anywhere            
DNAT       tcp  --  anywhere             anywhere             tcp to:172.20.4.10:8091

6.2 INPUT

FILTER 表的INPUT链中配置了KUBE-SERVICES, KUBE-EXTERNAL-SERVICES 跳转规则(KUBE-SERVICES未命中,再匹配KUBE-EXTERNAL-SERVICES)。

iptables -t filter -L INPUT

6.2.1 FILTER INPUT ->KUBE-SERVICES

拒绝目的地址为指定IP的数据包(这些IP对应的Service没有endpoints,这里的目的IP可能是Cluter IP、LB IP)

# Show Rules
iptables -t filter -L KUBE-SERVICES# Show Result
Chain KUBE-SERVICES (3 references)
target     prot opt source               destination         
REJECT     tcp  --  anywhere             10.68.236.66         /* default/myservice: has no endpoints */ tcp dpt:ssh reject-with icmp-port-unreachable
REJECT     tcp  --  anywhere             10.68.121.211        /* demo/test-lb:tcp-80 has no endpoints */ tcp dpt:http reject-with icmp-port-unreachable
REJECT     tcp  --  anywhere             公网IP地址      /* demo/test-lb:tcp-80 has no endpoints */ tcp dpt:http reject-with icmp-port-unreachable
REJECT     tcp  --  anywhere             10.68.220.136        /* demo/test3:tcp-80 has no endpoints */ tcp dpt:http reject-with icmp-port-unreachable
REJECT     tcp  --  anywhere             公网IP地址       /* demo/test3:tcp-80 has no endpoints */ tcp dpt:http reject-with icmp-port-unreachable

6.2.2 FILTER INPUT ->KUBE-EXTERNAL-SERVICES

拒绝目的地址为指定External IP的数据包(这些IP对应的Service没有endpoints,这里的IP可能是External IP、Node IP)

iptables -t filter -L KUBE-EXTERNAL-SERVICES

6.3 FORWARD

FILTER 表的FORWARD链中配置了KUBE-FORWARD, KUBE-SERVICES 跳转规则(KUBE-FORWARD未命中,再匹配KUBE-SERVICES)。

iptables -t filter -L FORWARD

6.3.1 FORWARD-> KUBE-FORWARD

  • (1)丢弃处于状态处于INVALID的数据包,因为它可能会潜在导致不期望的链接重置
  • (2)转发所有打了0x4000/0x4000标记的数据包
  • (3)后两条规则确保在“kubernetes kubernetes forwarding rules"”接受的初始数据包之后的流量将被接受,尽可能具体地说,流量必须来源于或指向clusterCIDR(到/从一个pod), 即保证Pod流量可以被转发(该规则再配置了–cluster-cidr时配置)。
# Show Rules
iptables -t filter -L KUBE-FORWARD# Show Result
Chain KUBE-FORWARD (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             ctstate INVALID
ACCEPT     all  --  anywhere             anywhere             /* kubernetes forwarding rules */ mark match 0x4000/0x4000
ACCEPT     all  --  172.20.0.0/16        anywhere             /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             172.20.0.0/16        /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHE

6.3.2 FORWARD-> KUBE-SERVICES

拒绝目的地址为指定IP的数据包(这些IP对应的Service没有endpoints,这里的目的IP可能是Cluter IP、LB IP)

6.4 OUTPUT

NAT 表及Filter表中添加了KUBE-SERVICE链表跳转规则。数据包先过NAT链,再过Filter链。

6.4.1 NAT OUTPUT-> KUBE-SERVICES

所有数据包进入NAT表的KUBE-SERVICES链处理,KUBE-SERVICES链处理流程和6.1从NAT 表PreRouting 链进入NAT表一致。

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
KUBE-SERVICES  all  --  anywhere             anywhere             /* kubernetes service portals */

6.4.2 NAT OUTPUT-> KUBE-SERVICES

数据包进入Filter表的KUBE-SERVICES,KUBE-SERVICES链处理流程和6.2.1 Filter INPUT进入KUBE-SERVICES一致。

6.5 POSTROUTING

kube-proxy在NAT 表的POSTROUTING链中加入了KUBE-POSTROUTING跳转链表规则

-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING

6.5.1 NAT POSTROUTING -> KUBE-POSTROUTING

KUBE-POSTROUTING 链表中对于打了0x4000/0x4000标签的数据包,进行MASQUERADE,进行SNAT。

# Add Rule
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE# Show Rule
iptables -t nat -L KUBE-POSTROUTING# Show Result
Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere             /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000

7 总结

入包处理整体流程(进入主机)

  • (1)Nat表PreRouting、OutPut拦截所有数据包进入KUBE-SERVICE链处理
  • (2)对出包时需要SNAT的数据包打mark
  • (3)对数据包基于目的地址及目的端口进行匹配,进入KUBE-SVC-HASH链处理
  • (4)进入KUBE-SVC-HASH链,基于概率进入KUBE-SEP-HASH链,进行DNAT,将目的地址转换为RIP:RPORT

出包处理整体流程(出主机)

  • (1)Nat表PostRouting拦截所有进入KUBE-POSTROUTING链处理
  • (2)KUBE-POSTROUTING链对于打了标记的数据包,进行SNAT处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/353134.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

windows_删除多余网络适配器(删除/卸载多余网卡)/删除TAP虚拟网卡NIC

文章目录 Device Manager检查所有NIC状态利用资源监视器查看网卡情况接入不同网络对于计算机网络环境造成不同的影响接入传统的wifi接入手机热点的wifi Device Manager 删除指定的Network adapter(网卡又称为网络适配器)完成之后你可能需要重启才可以上网 检查所有NIC状态 包…

值得一阅的Kali系统的使用小技巧

目录 写在最前1.软件安装软件源关于AMD显卡驱动浏览器中文输入法下载工具代理软件QQSteam 2.使用优化ssh服务开启Grub修改Zsh和PowerShell命令标头修改VSCode内置终端字体间距过大问题 Aria2配置文件 写在最前 不定期更新 1.软件安装 软件源 推荐使用中科大源&#xff0c;官…

基于geoserver开发地图发布服务

写在前面&#xff1a;我在github上创建了对应的项目&#xff0c;可点此跳转&#xff0c;本文的所有源码均可在项目里找到&#xff0c;欢迎大家访问交流 一、开发背景 在gis领域&#xff0c;geoserver是后端地图发布的开源项目。目前我们在启动服务后&#xff0c;可通过自带的…

CIPSTAT

AT_TCPIP_CmdFunc_CIPSTART //start up tcpip connection 1&#xff09;if (gCipBearer ! BEARER_WIFI) 承载是GPRS(1)还是WIFI&#xff08;2&#xff09;&#xff0c;若非WIFI&#xff0c;获取SimStatus 2)if ((!cipMux_multiIp && (CIP_INITIALg_uCipContexts.nBeare…

Cloud Computing:云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系

Cloud Computing&#xff1a;云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系 目录 云计算的简介、必要性以及安全上云与企业数字化转型(从陈坤/辛芷蕾主演电视剧《输赢》看云计算的未来)的关系 从陈坤/辛芷蕾主演电…

relation-graph关系图谱组件2.0版本遇到的问题

前提&#xff1a;之前已经写过一篇1.1版本的问题&#xff0c;这里就不过多讲了&#xff08;如果想要解决火狐低版本兼容&#xff0c;看那个就行&#xff09; 这次主要讲的是和1.X版本的区别和一些其它问题 区别 参数名不同&#xff1a;以前的links>lines (虽然现在links也…

高压放大器在微流控技术的应用研究

随着微流控技术的不断发展&#xff0c;其在生物医学、环境监测、化学分析等领域中的应用越来越广泛&#xff0c;也对相关器件的性能提出了更高的要求。其中&#xff0c;高压放大器作为一种电子元器件&#xff0c;在微流控技术中具有重要的作用。下面安泰电子将从高压放大器在微…

仙境传说RO:添加商店物品教程

仙境传说RO&#xff1a;添加商店物品教程 我是艾西&#xff0c;今天跟大家分享下仙境传说RO游戏中我们自己怎么创建商店卖东西装备等&#xff0c;首先看看下图以及自己创建商店时需要在文档里创建的脚本格式 //*------------------shop普通商店------------------ //带坐标的…

Java养成类小游戏

此周是做项目 做一个java的养成类的小游戏 我是用控制台写的小游戏 建了很多的UI地图&#xff0c;部分代码&#xff0c; 然后让我们来看实现的样子&#xff1a; 好啦&#xff0c;部分内容就到这啦 早点洗洗睡叭&#xff01;

Java游戏合集

游戏1&#xff1a;猜数字小游戏&#xff1a; import java.util.Scanner; class GuessNumber{public static void main(String args[]){int number (int)(Math.random()*100)1;System.out.println("请输入一个数据&#xff08;1-100&#xff09;用于猜数字。");whil…

JAVA学习之路-简单的城堡游戏(一)

简单的文字城堡游戏&#xff08;一&#xff09; 最近在学习后台的一些功能&#xff0c;发现自己的基础不是很牢固&#xff0c;所以想写点小程序&#xff0c;巩固一下以前学的知识&#xff0c;融合一下。 之前在慕课上学的课程中就有一个这样的小程序&#xff0c;写一个简单的…

Nginx的优化,安全与防盗链

目录 一、Nginx的页面优化 1&#xff09;Nginx的网页压缩 2&#xff09;配置Nginx的图片缓存 3&#xff09;Nginx的连接超时设置 4&#xff09;Nginx的并发设置 查看cpu的核心数&#xff0c;根据核心数来设置工作进程数 修改工作进程核心数 &#xff1a; 测试结果&…

java做RPG小游戏

题目 java课设&#xff0c;一个游戏中有多种角色(Character)&#xff0c;例如&#xff1a;国王&#xff08;King&#xff09;、皇后&#xff08;Queen&#xff09;、骑士&#xff08;Knight&#xff09;、老怪&#xff08;Troll&#xff09;。 角色之间可能要发生战斗(fight)&…

【Java游戏合集】手把手教你制作游戏

家人们&#xff0c;今天我们来看一下学Java必练的10款游戏项目&#xff01; 大家都知道学习编程必须要做的就是敲代码和做项目练手了&#xff0c;那项目有难有易&#xff0c;很多小伙伴不知道从哪里找项目来练习&#xff0c;今日我们来看一下初级项目中都有哪些能让我们来练手…

Java桌面游戏巡礼——国外Java游戏合集(第一回)

1、 Virus Effect 这是一个2D的Java横板射击游戏&#xff0c;作者在其中融入了很多FPS&#xff08;First Personal Shooting Game&#xff09;要素&#xff0c;角色能够进行换枪、调整射击角度、装弹拆弹等仿真操作&#xff0c;并于游戏内设置有教学关卡&#xff0c;即使是从未…

java保姆级教程—— 1.什么是游戏

引言&#xff1a; Java保姆级教程是笔者在暑假时&#xff0c;为学弟们准备的java游戏教程&#xff0c;今天整理了一下&#xff0c;共享给网友们&#xff0c;笔者也是学生&#xff0c;若有大神发现文中存在误区&#xff0c;还请私信笔者。注&#xff1a;java游戏保姆级教程&…

Java游戏开发——对对碰

游戏介绍&#xff1a; 对对碰游戏在n*n的游戏池中进行&#xff0c;每个格子中有一个图案。鼠标连续选中两个横排或竖排相邻的图案&#xff0c;它们的位置会互换&#xff0c;互换后如果横排或者竖排有3个以上相同的图像&#xff0c;则可以消去该图像&#xff0c;并得分。 游戏…

连连看游戏的设计与实现——基于JAVA语言的小游戏

说明&#xff1a;本篇博客主要讲述练练看游戏的设计与实现。前半部分为分析与类和属性的说明&#xff0c;后半部分为程序的实现与程序代码。第一次写小游戏&#xff0c;仍存在许多问题&#xff0c;也借鉴了CSDN前辈的代码想法&#xff0c;如有不妥&#xff0c;还望多批评指正。…

Java写的第一个小游戏(续)

优化代码(数据维护): 注:此为小游戏最终版本 代码做到最优最简 基于之前发表的文章详情可见 点击查看前文 回顾之前的代码我们可以看到很多的固定常量值或是属性我们都会大量的重复使用,这并不符合我们代码简洁易懂的特点 所以我们可以把重复出现的量或是属性或是方法使用面向…

java小游戏超级玛丽:06.第二关的设计

第二关预览图&#xff1a; 判断是否为第二关 if (sort 2) {} 砖块位置图&#xff1a; 砖块坐标&#xff1a; A(240,390) B(270,360) C(300,330) D(270,360) E(300,360) F(330,390) G(360,360) H(390,390) I(420,390) f1(240,300) 空1&#xff08;420&#xff0c;270&a…