Navigation

    TF中文社区

    • Register
    • Login
    • Search
    • 社区
    • 文档
    • 新闻
    • 博客
    • Recent
    • Tags
    • Popular
    1. Home
    2. bing
    3. Posts
    B
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Posts made by bing

    • 要在数据中心实现快速收敛?你需要一个快速IP Fabric

      先说一句看起来很“傻”,但在我看来并非琐碎的话:如果一切都按预期进行……那么一切就都会顺利进行。

      想象一下这样的网络:你设置链接,配置路由协议,检查端点是否可达。在正常情况下,数据包会如愿以偿地流动,用户也会对自己的体验感到满意。

      但是,如果网络内部出现故障怎么办?我们确实设置了路由协议来交换和传播路由信息,但这还不够。路由协议不一定要简单地提供端点之间的可到达性,它们必须被设计成能够高效地应对网络故障。

      那么“高效”又是什么意思?如果我们是在学校里学习,“高效”的意思就是快,我们确实希望将流量损失降到最低,因为这会导致服务中断,同时我们还希望系统的算法能够快速从故障中恢复。如果我们是在公司工作,“高效”仍然意味着快,压力也会更大,服务中断就意味着“金钱的损失”……

      总之,在这两种情况下,效率都意味着“快”。网络在处理故障的时候,必须要快。我们要尽可能地减少流量损失!

      这就引出了网络设计的一个基本话题:收敛!

      数据中心内部的收敛

      自第一个网络部署以来,网络收敛一直是非常重要的一个方面。

      当然,当你开始学习计算机网络时,一定听说过当一条链路故障时的生成树收敛,OSPF重新计算路径所需的时间,用于实现邻居关系的bgp保持计时器不再活跃等等。

      所有这些考虑因素在创建网络时仍然存在,而且至关重要,现在,我们把它们带到了数据中心里面。

      说到数据中心,我指的是IP Fabric,一个使用BGP作为路由协议的leaf和spine网络,并在leaf层限制L2功能(ERB模型)。有了这些假设,就不难理解很多“老”的快速收敛概念又回来了。

      让我们来看一个示例拓扑:
      16b28aca-a768-4682-a37d-7605c044c8d5-image.png
      我们有一个2×2的IP Fabric(2个leaves,2个spines),一个DC网关连接到两个spine(在真实的网络中,我们很可能有冗余的DC网关)。

      我们有服务器连接到leaves上,这些服务器是多归属连接到Fabric上的(绑定接口,每个leaf上都有一个成员连接)。

      来看看收敛是在哪里成为对话的一部分。

      在服务器和leaf之间,我们有一个LAG,因此,收敛主要是在一个成员故障的情况下,绑定失败的速度。在这里,我们期望亚秒级的故障切换时间,或者最坏的场景下,我们依靠LACP定时器(如果使用快速速率,那么我们期望检测时间为3×1秒)。

      而在IP Fabric内部,事情变得更加复杂……

      VTEPS的可达性取决于底层BGP。这里的收敛,是指BGP收敛。由于直接连接的接口地址之间使用的是eBGP,所以故障转移应该是非常快的。Hold Time不应该出现(除非软件层面的问题);BFD也可以做类似的考虑。

      接下来,对于EVPN驱动的连接,fabric ibgp overlay就变得相关了。在这里,由于在环回地址之间建立了BGP,来自BFD的帮助就成为关键。

      现在,让我来预测一下这个讨论的关键论点吧。2个leaf节点之间有多条路径;这来自于leaf & spine架构在两个leaf节点之间提供的多条ecmp路径。想象一下,从leaf1到leaf2的overlay ibgp数据包穿越spine1。如果leaf1-spine1的链接失效,并不意味着两个leaf不能再连通;它们可以通过spine2的备用路径。

      因此,overlay ibgp bfd定时器的速度不能快于underlay适应故障并提供leaf1和leaf2之间的备用路径所需的时间。由于underlay依赖于直连的接口地址之间配置的eBGP,反应时间应该非常快,因此我们可以设置非常低的BFD定时器。

      此外,由于设备上启用了ecmp,当一条链路发生故障时,leaf和spine已经将替代路径加载到FIB(包转发引擎表)中;这进一步将收敛时间降到最低,因为我们消除了将替代路由从RIB加载到FIB所需的时间(虽然很短,但它仍然存在)。

      这给了我们什么启示呢?

      如果系统A的收敛时间为X,而系统B使用系统A作为传输层,那么系统B的收敛时间不可能比X更快!

      这在后面会很方便。

      出于关闭fabric收敛的考虑,当一个ESI成员失败时,必须发送type 1 withdraw路由,以便让其它leaf知道有些MAC不能再通过发起这些type 1路由的leaf到达。某种程度上,这与ibgp overlay收敛有关。

      最后我们要涉及的部分是DCGW和和spine之间的路径。在这里,我假设了一个设计,有单独的p2p链路连接DCGW和spine(没有ESI LAG),并且eBGP会话通过直连的接口地址建立。在这种情况下,为Fabric eBGP underlay所做的考虑仍然有效,因为我们使用相同的动态路由协议。

      这涵盖了数据中心内部不同的收敛方面。

      南北流量路径收敛场景

      现在,让我们看看当需要在南北流量路径上进行收敛时会发生什么。

      考虑一下下面这个场景:
      5e60bf0b-4ebc-4896-beee-1fa7e94e3ffd-image.png
      我们有一个双归属到两个Leaf节点的VNF虚拟路由器 由于某些原因必须与DCGW对话。这条路径代表了南北流量的一个典型例子。

      现在,想象一下这两个端点通过BGP会话交换路由信息的情形。

      虚拟路由器可能充当DC内部运行的虚拟机的虚拟路由反射器。如果你仔细想想,这种用例并不是虚幻的。设置一个虚拟的RR是有意义的;你可能会通过依靠IP Fabric路由来实现类似的东西,但是很可能的是,你不希望在leaf(或spine)RIB里面带来太多的路由。

      此外,如果考虑到Contrail,Contrail Controller节点将作为路由反射器,并且与DCGW交换路由信息。

      在BGP会话的基础上,我们还配置了BFD,以便有更快的故障检测能力。

      现在,最大的问题是……如何设置BFD定时器?

      让我们看看,在正常情况下,BGP和BFD包可能流向哪里:
      3debfb3d-5c97-43ac-af19-7eab133558c1-image.png
      有四条可能的路径。第一次裂变发生在VNF层,取决于哈希函数的计算来选择一个LAG成员。第二次裂变发生在leaf上,因为DCGW可以通过2条ecmp路径到达。当然,属于同一个流的数据包(相同的5-tuple)将采取相同的路径,因为哈希函数给所有数据包的结果是相同的。

      可能发生的故障推演

      现在,我们来看看可能的故障。

      一个LAG成员可能会发生故障:
      a6652a16-bb4b-4c42-92a1-db93e8683c97-image.png
      如前所述,在这里,收敛时间取决于LAG的反应;假设需要X时间才能收敛。

      另一种可能发生的故障是leaf-spine故障:
      065bdbd8-5a47-4daf-b921-1f47e49f344f-image.png
      在这种情况下,收敛时间取决于underlay BGP(记住,我们是在ERB模型中,所以evpn对端到端路径没有影响)。假设需要Y时间才能收敛。

      回到我们的BFD定时器问题。在这两种故障场景下,BGP端点(虚拟路由器和DCGW)仍然可以通过替代路径到达对方。重要的是,我们必须允许fabric在端到端BGP会话下线之前提供该替代路径。这意味着BFD故障检测时间必须至少是max(X,Y)。

      这告诉我们在谈论数据中心的收敛时一些最基本的东西:每次我们“围绕IP Fabric设计收敛”的时候,都依赖于IP Fabric的收敛时间。

      这对现代架构有很大影响。想一想vEPG的用例:整个移动链将依赖于Fabric收敛。对于任何在数据中心内运行的应用来说,Fabric的恢复速度越快越好。

      虚拟环境下的收敛案例

      让我们简单看一下我们描述的一个例子。

      我在一个虚拟环境中构建了之前展示的拓扑结构。由于是虚拟环境,设备之间并不是通过真实的线缆连接,而是通过中间的虚拟交换机进行连接。
      f8a5012f-1acb-42ef-bae9-669488b7cfc7-image.png
      这就意味着,如果S2接口发生故障,S1接口不会宕机,因为S1-vswitch的链路还在。

      这是我的虚拟实验室环境的一个限制条件。

      这主要意味着两点。第一,如果leaf上的LAG成员被禁用,虚拟路由器会在LACP检测到故障后发现这一情况。第二,fabric BGP underlay必须依赖hold timer。由于这个定时器太长,我把BFD也配置在这些会话上。

      其实,这些虚拟环境给出的限制对我们的目的来说并不坏。由于我们不得不处理以秒为单位的收敛时间,因此将更容易观察到我们感兴趣的事件。

      在fabric内部,我为BGP underlay配置了以下BFD定时器:

      set groups bf_underlay protocols bgp group underlay bfd-liveness-detection minimum-interval 1000
      set groups bf_underlay protocols bgp group underlay bfd-liveness-detection multiplier 5
      

      定时器很大,正如所说,这是选择出来的。

      在虚拟路由器上,我们做如下设置:

      set protocols bgp group dcgw bfd-liveness-detection minimum-interval 300
      set protocols bgp group dcgw bfd-liveness-detection multiplier 3
      

      这些是端到端(虚拟路由器-DCGW)BGP会话的BFD定时器。

      我们有大约1秒与5秒两种情况。

      此时,我们禁用BGP和BFD数据包流动的leaf spine链路。

      大约1秒后,在虚拟路由器上,由于BFD会话关闭,BGP会话被关闭:

      Feb 12 02:14:55  bms bfdd[6205]: BFD Session 1.1.1.1 (IFL 0) state Up -> Down LD/RD(16/17) Up time:00:02:09 Local diag: NbrSignal Remote diag: CtlExpire Reason: Received DOWN from PEER.
      Feb 12 02:14:55  bms bfdd[6205]: BFDD_TRAP_MHOP_STATE_DOWN: local discriminator: 16, new state: down, peer addr: 1.1.1.1
      

      无论如何,虚拟路由器和DCGW仍然可以通过fabric提供的替代路径相连通,我们只需要等待fabric收敛。

      4秒之后发生了什么:

      Feb 12 02:14:59  leaf2 bfdd[1739]: BFDD_STATE_UP_TO_DOWN: BFD Session 192.168.3.1 (IFL 567) state Up -> Down LD/RD(16/17) Up time:00:05:02 Local diag: CtlExpire Remote diag: None Reason: Detect Timer Expiry.
      Feb 12 02:14:59  leaf2 rpd[1728]: bgp_bfd_callback:187: NOTIFICATION sent to 192.168.3.1 (External AS 65511): code 6 (Cease) subcode 9 (Hard Reset), Reason: BFD Session Down
      Feb 12 02:14:59  leaf2 bfdd[1739]: BFDD_TRAP_SHOP_STATE_DOWN: local discriminator: 16, new state: down, interface: xe-0/0/0.0, peer addr: 192.168.3.1
      

      这4秒钟来自于两个BFD会话上配置的检测时间的差异。

      接下来会发生什么?Fabric收敛,端到端BGP会话(虚拟路由器到DCGW)又出现了。结果呢?我们导致了BGP会话flap!

      为了避免这种情况,我们需要在端到端会话上增加BFD定时器的时间;例如增加到3×2.5秒:

      set protocols bgp group dcgw bfd-liveness-detection minimum-interval 2500
      set protocols bgp group dcgw bfd-liveness-detection multiplier 3
      

      在这种情况下,我们给fabric必要的时间来收敛,避免不必要的flapping(考虑到当DCGW将这些路由发送到其它地方,flapping的影响可能会扩展到其它设备,将导致整个网络的不稳定)。

      如果将BGP underlay BFD检测时间降低到2秒呢?在这种情况下,LAG故障切换(LACP 3秒)将成为约束条件,也就是说端到端BFD检测时间应该高于3秒。

      这完美的说明了在数据中心环境中运行的服务,其快速收敛的处理离不开fabric的收敛。

      那么,我的虚拟化服务能快速收敛吗?是的……但可能不会比你的IP Fabric更快!


      原文链接:https://iosonounrouter.wordpress.com/2020/02/13/to-have-fast-convergence-inside-a-dc-you-need-a-fast-ip-fabric/
      作者:Umberto Manferdini 译者:TF编译组


      posted in 博客
      B
      bing
    • TF Analytics指南丨“分析”哪些内容?如何发出“警报”?

      Tungsten Fabric是一个由计算节点、控制节点、配置节点、数据库节点、Web UI节点和分析节点组成的分布式系统。

      分析(Analytics)节点负责收集系统所有节点上所有软件模块的系统状态信息、使用统计和调试信息。分析节点将整个系统收集到的数据存储在数据库中,数据库基于Apache Cassandra开源分布式数据库管理系统。该数据库通过类似SQL的语言和表示状态转移(REST)API进行查询。

      分析节点收集到的系统状态信息将汇总到所有的节点上。

      分析节点收集的调试信息包括以下几种类型。

      • 系统日志(syslog)消息——由系统软件组件产生的信息和调试消息。
      • 对象日志消息——记录对系统对象(如虚拟机、虚拟网络、服务实例、虚拟路由器、BGP对等体、路由实例等)的更改。
      • 追踪消息——软件组件在本地收集的活动记录,仅在需要时才发送给分析节点。

      与流量、CPU和内存使用情况等相关的统计信息也由分析节点收集,并可进行查询以提供历史分析和时间序列信息。查询使用REST APIs进行。

      分析数据会被写入到Tungsten Fabric的数据库。数据将在默认的48小时有效时间(TTL)后过期。这个默认的TTL时间可以根据需要通过改变集群配置中的database_ttl值来改变。

      TF警报流(Alert Streaming)

      TF警报(alert)是在基于每个用户可见实体(UVE)提供的。TF分析(analytics)使用Python编码的规则来触发或解除警报,这些规则将检查UVE的内容和对象的配置。一些规则是内置的,其它规则可以使用Python stevedore插件添加。

      本主题介绍了Tungsten Fabric警报功能。

      警报API格式

      TF警报分析API提供以下内容。

      • 作为UVE GET APIs的一部分,读取对警报的访问。
      • 使用POST请求进行警报确认。
      • 使用服务器发送的事件(SSE)进行UVE和警报流。

      例如:
      GET http:// :8081/analytics/alarms。

      {
          analytics-node: [
              {
                  name: "nodec40",
                  value: {
                      UVEAlarms: {
                          alarms: [
                              {
                                  any_of: [
                                      {
                                          all_of: [
                                              {
                                                  json_operand1_value: ""PROCESS_STATE_STOPPED"",
                                                  rule: {
                                                      oper: "!=",
                                                      operand1: {
                                                          keys: [
                                                              "NodeStatus",
                                                              "process_info",
                                                              "process_state"
                                                          ]
                                                      },
                                                      operand2: {
                                                          json_value: ""PROCESS_STATE_RUNNING""
                                                      }
                                                  },
                                                  json_vars: {
                                                      NodeStatus.process_info.process_name: "contrail-topology"
                                                  }
                                              }
                                          ]
                                      }
                                  ],
                                  severity: 3,
                                  ack: false,
                                  timestamp: 1457395052889182,
                                  token: "eyJ0aW1lc3RhbXAiOiAxNDU3Mzk1MDUyODg5MTgyLCAiaHR0cF9wb3J0I
      ................................... jogNTk5NSwgImhvc3RfaXAiOiAiMTAuMjA0LjIxNy4yNCJ9",
                                  type: "ProcessStatus"
                              }
                          ]
                      }
                  }
              }
          ]
      }
      

      在这个例子中:

      • any_of属性包含以[ [rule1 AND rule2 AND ... AND ruleN] ... OR [rule11 AND rule22 AND ... AND ruleNN] ]格式定义的报警(alarm)规则。
      • 警报是在每个UVE的基础上发出的,可以通过在UVE上的GET来检索。
      • ack表示警报是否已被确认。
      • token用于客户端的请求确认。

      用于警报的分析API

      下面的示例显示了用于显示警报(alert)和报警(alarm),以及确认报警(alarm)的API。

      • 检索对名为aXXsYY的控制节点发出的警报列表。
      GET http://:/analytics/uves/control-node/aXXsYY&cfilt=UVEAlarms
      

      这适用于所有UVE表类型。

      • 检索系统中所有报警(alarm)的列表。
      GET http://:/analytics/alarms
      
      • 确认报警(alarm)。
      POST http://:/analytics/alarms/acknowledge
      Body: {“table”: ,“name”: , “type”: , “token”: }
      

      可以使用以下URL查询参数和前面列出的GET操作具体查询已确认和未确认的报警(alarm)。

      ackFilt=True
      ackFilt=False
      

      SSE流的分析API

      下面的例子展示了用于检索全部或部分SE流的API。

      • 检索基于SSE的UVE更新流,用于控制节点报警(alarm)。
      GET http://: /analytics/uve-stream?tablefilt=control-node
      

      这对所有UVE表类型都可用。如果没有提供tablefilt URL查询参数,则会检索所有UVE。

      • 只检索基于SSE的UVE更新流的警报部分,而不是整个内容。
      GET http://: /analytics/alarm-stream?tablefilt=control-node
      

      这对所有UVE表类型都可用。如果没有提供tablefilt URL查询参数,则会检索所有UVE。

      内置节点警报

      可以使用分析API中列出的API来检索以下内置节点警报。

      control‐node: {
      PartialSysinfoControl: "Basic System Information is absent for this node in BgpRouterState.build_info",
      ProcessStatus: "NodeMgr reports abnormal status for process(es) in NodeStatus.process_info",
      XmppConnectivity: "Not enough XMPP peers are up in BgpRouterState.num_up_bgp_peer",
      BgpConnectivity: "Not enough BGP peers are up in BgpRouterState.num_up_bgp_peer",
      AddressMismatch: “Mismatch between configured IP Address and operational IP Address",
      ProcessConnectivity: "Process(es) are reporting non‐functional components in NodeStatus.process_status"
      },
      
      vrouter: {
      PartialSysinfoCompute: "Basic System Information is absent for this node in VrouterAgent.build_info",
      ProcessStatus: "NodeMgr reports abnormal status for process(es) in NodeStatus.process_info",
      ProcessConnectivity: "Process(es) are reporting non‐functional components in NodeStatus.process_status",
      VrouterInterface: "VrouterAgent has interfaces in error state in VrouterAgent.error_intf_list”,
      VrouterConfigAbsent: “Vrouter is not present in Configuration”,
      },
      
      config‐node: {
      PartialSysinfoConfig: "Basic System Information is absent for this node in ModuleCpuState.build_info",
      ProcessStatus: "NodeMgr reports abnormal status for process(es) in NodeStatus.process_info",
      ProcessConnectivity: "Process(es) are reporting non‐functional components in NodeStatus.process_status"
      },
      
      analytics‐node: {
      ProcessStatus: "NodeMgr reports abnormal status for process(es) in NodeStatus.process_info"
      PartialSysinfoAnalytics: "Basic System Information is absent for this node in CollectorState.build_info",
      ProcessConnectivity: "Process(es) are reporting non‐functional components in NodeStatus.process_status"
      },
      
      database‐node: {
      ProcessStatus: "NodeMgr reports abnormal status for process(es) in NodeStatus.process_info",
      ProcessConnectivity: "Process(es) are reporting non‐functional components in NodeStatus.process_status"
      },
      

      分析API服务器和Client服务器之间的加密

      Tungsten Fabric 1910版本支持SSL加密,用于分析(Analytics)API服务器和Client服务器之间的连接。Client服务器是Service Monitor和Contrail Command,后者通过REST API端口连接到分析API服务器。在1910版之前的版本中,分析API服务器和Client服务器之间的连接没有加密,这可能会造成安全威胁。

      只有当Tungsten Fabric与Red Hat OpenStack Platform(RHOSP)一起部署时,1910版才支持SSL加密。在RHOSP部署中,添加了一个全局标志,它决定了SSL加密的状态。

      如果启用了全局标志:

      • 您不必修改配置文件,因为SSL加密是自动启用的。
      • 如果要禁用SSL加密,必须修改配置文件。

      如果全局标志被禁用:

      • 您不必修改配置文件,因为SSL加密是自动禁用的。
      • 即使修改配置文件,也无法启用SSL加密。由于全局标志被禁用,因此在部署期间不会生成证书。

      配置文件有contrail-analytics-api.conf、contrail-svc-monitor.conf和command_servers.yml。在配置文件中,修改下表中的参数,以启用或禁用基于SSL的加密。

      表1:SSL加密参数

      edc2345a-0244-4b9d-a40b-39a981aadc18-image.png

      配置好这些参数后,分析API服务器就会开始使用SSL证书,从而实现对分析API服务器和Client服务器之间连接的SSL加密支持。

      在下篇文章中,我们将继续“游览”TF Analytics的功能,看看如何使用Analytics进行underlay overlay映射。


      原文链接:
      https://www.juniper.net/documentation/en_US/contrail20/topics/concept/analytics-overview-vnc.html
      https://www.juniper.net/documentation/en_US/contrail20/topics/concept/alerts-overview.html
      https://www.juniper.net/documentation/en_US/contrail20/topics/task/configuration/encrypting-connection-analytics-server-and-client-server.html


      posted in 博客
      B
      bing
    • 为OpenStack和K8s集群提供无缝虚拟网络

      在数据中心里,同时拥有OpenStack和Kubernetes集群的情况正变得越来越普遍。

      一边是由OpenStack管理的虚拟机,另一边是由K8s控制的容器化工作负载。

      现实情况下,可能会发生虚拟机和容器需要相互“交谈”的情况。如果是这样,我们需要以某种方式实现两个独立集群之间的通信。
      51990e6a-23c8-4247-adb1-5d45a227a2e2-image.png
      作为两个不同的集群,每个集群都有自己的网络平面。OpenStack可能会依赖OVS,而Kubernetes则会部署某个可用的CNI。

      由于每个集群都是独立于其它集群的,因此必须在第三个“元素”上启用通信。这第三个元素可以是IP Fabric。

      虚拟机将通过提供商网络退出计算,并在VLAN内的IP Fabric上现身。容器也会做类似的事情。因此,我们可能最终会有两个VLAN,通过配置IP Fabric叶子节点(或spine节点)作为L2/L3 gw来允许它们相互对话。另外,L3 gw的角色可能会被委托给上层设备,比如SDN gw(在这种情况下,IP Fabric叶子节点/spine节点只会是L2 gw)。

      这里的一个关键要点是,虚拟/容器化的工作负载成为underlay的一部分,使得服务平面(工作负载)和网络平面(IP Fabric)相互交错。

      提供服务也需要在IP Fabric underlay进行配置。我们在探索数据中心使用Tungsten Fabric的优势时,谈到过这个概念,请见下面链接:

      https://iosonounrouter.wordpress.com/2020/04/28/which-sdn-solution-is-better-what-i-learned/

      同样的考虑在这里也适用,另外我们不仅需要连接虚拟机,还需要连接容器。

      我们假设需要部署一个应用程序,其构件既有虚拟机又有容器。这意味着我们需要在OpenStack里部署一些对象,在Kubernetes里部署另外一些对象。从网络的角度来看,我们需要对OpenStack、K8s和IP Fabric进行操作。如果能简化这一点就好了。Tungsten Fabric来了!

      TF可以与OpenStack和K8s一起工作(作为CNI)。当然,代码的某些部分是“编排器专用”的。我的意思是,TF一方面需要与Neutron/Nova进行交互,另一方面需要与K8s API和其它K8s组件进行交互。

      总之,除了这些,解决方案的核心还是一样的!虚拟网络也还是VRF。工作负载也还是接口!不管我们的接口后面是虚拟机还是容器,对于Tungsten Fabric来说,它只是放到VRF中的一个接口。对于计算节点之间和通向SDN网关的overlay(MPLSoUDP、MPLSoGRE、VXLAN)也是一样的。

      因此,让虚拟机与容器进行通信,只是在同一个VRF(虚拟网络)中放置接口的问题。这可以通过让一个实体来“控制”OpenStack和Kubernetes集群的虚拟网络来实现。这个实体就是我们最爱的TF Controller。

      我们的数据中心将会是这样的:
      ccc0ee40-e16e-4c6c-9a9f-0c7ff27c3fa8-image.png
      如你所见,从配置的角度来看,集群还是有区别的。Kubernetes master控制容器,而OpenStack controller负责Nova虚拟机。

      这里的关键变化在于Tungsten Fabric控制器(controller)的存在,它将与OpenStack计算节点和Kubernetes worker节点进行交互(仍然使用XMPP)。这样我们就为集群提供了一个单一的网络平面。

      由于TF在overlay层工作,我们不再需要IP Fabric来“看到”虚拟机和容器。工作负载的流量被隐藏在overlay隧道中(无论是在计算节点之间,还是通向SDN网关……就像任何一个TF集群一样)。

      拥有一个单一的网络平面还会带来其它优势。例如,TF将负责IP地址分配。假设我们有一个地址为192.168.1.0/24的虚拟网络。如果我们在该VN上创建一个虚拟机,TF将分配地址192.168.1.3。之后,如果我们在Kubernetes中创建一个容器,并将其连接到同一个VN,TF将分配地址192.168.1.4,因为它知道.3已经在使用。如果有两个不同的集群,实现这个功能需要额外的“工具”(例如配置静态分配池或让更高级别的编排器充当IPAM管理器角色)。Tungsten Fabric则简化了这种网络操作。

      现在,理论已经说得够多了。让我们来看一个实际的例子!

      我在一个虚拟实验室中构建了上述拓扑。为了部署Tungsten Fabric,我使用了Ansible部署器,它允许我们同时配置OpenStack和Kubernetes集群。我不会去详细介绍如何使用Ansible部署器安装TF(这里是一个部署K8s集群的例子);我假设对这个工具有预先的了解。

      大家知道,Ansible部署器的核心是instances.yaml文件。下面是我使用的一个文件:

      ###FILE USED TO DESCRIBE THE CONTRAIL CLOUD THAT ANSIBLE DEPLOYER HAS TO BUILD
      global_configuration:
        CONTAINER_REGISTRY: hub.juniper.net/contrail
        CONTAINER_REGISTRY_USERNAME: xxx
        CONTAINER_REGISTRY_PASSWORD: yyy
      provider_config:
        bms:
          ssh_user: root
          ssh_pwd: Embe1mpls
          ntpserver: 10.102.255.254
          domainsuffix: multiorch.contrail
      instances:
        cnt-control:
          provider: bms
          ip: 10.102.240.183
          roles:
            config:
            config_database:
            control:
            webui:
            analytics:
            analytics_database:
            analytics_alarm:
        os-control:
          provider: bms
          ip: 10.102.240.178
          roles:
            openstack:
        os-compute:
          provider: bms
          ip: 10.102.240.171
          roles:
            vrouter:
              VROUTER_GATEWAY: 192.168.200.1
            openstack_compute:
        k8s-master:
         provider: bms
         roles:
            k8s_master:
            kubemanager:
         ip: 10.102.240.174
        k8s-worker:
         provider: bms
         roles:
           vrouter:
             VROUTER_GATEWAY: 192.168.200.1
           k8s_node:
         ip: 10.102.240.172
      contrail_configuration:
        CLOUD_ORCHESTRATOR: openstack
        CONTRAIL_CONTAINER_TAG: 2008.121
        CONTRAIL_VERSION: 2008.121
        OPENSTACK_VERSION: queens
        ENCAP_PRIORITY: "VXLAN,MPLSoUDP,MPLSoGRE"
        BGP_ASN: 65100
        CONFIG_NODEMGR__DEFAULTS__minimum_diskGB: 2
        DATABASE_NODEMGR__DEFAULTS__minimum_diskGB: 2
        CONFIG_DATABASE_NODEMGR__DEFAULTS__minimum_diskGB: 2
        KUBERNETES_CLUSTER_PROJECT: {}
        KUBERNETES_API_NODES: 192.168.200.12
        KUBERNETES_API_SERVER: 192.168.200.12
        KUBEMANAGER_NODES: 192.168.200.12
        RABBITMQ_NODE_PORT: 5673
        KEYSTONE_AUTH_URL_VERSION: /v3
        VROUTER_GATEWAY: 192.168.200.1
        CONTROLLER_NODES: 10.102.240.183
        CONTROL_NODES: 192.168.200.10
        JVM_EXTRA_OPTS: "-Xms1g -Xmx2g"
        PHYSICAL_INTERFACE: "ens3f1"
      kolla_config:
        kolla_globals:
          enable_haproxy: no
          enable_ironic: no
          enable_swift: no
          enable_barbican: no
        kolla_passwords:
          keystone_admin_password: contrail123
      metadata_secret: meta123
      

      实例部分包括5台服务器:

      • openstack controller
      • kubernetes master
      • contrail controller
      • openstack compute
      • kubernetes worker

      如果你去看“contrail_configuration”部分,就会注意到我们配置TF是为了与openstack controller(KEYSTONE_AUTH_URL_VERSION)和kubernetes master(KUBERNETES_API_NODES)交互。
      一旦所有节点都做好安装准备,从“deployer”节点(可以是contrail controller本身)运行以下命令:

      ansible-playbook -e orchestrator=openstack -i inventory/ playbooks/configure_instances.yml
      ansible-playbook -e orchestrator=openstack -i inventory/ playbooks/install_openstack.yml
      ansible-playbook -e orchestrator=openstack -i inventory/ playbooks/install_k8s.yml
      ansible-playbook -e orchestrator=openstack -i inventory/ playbooks/install_contrail.yml
      

      如果一切顺利的话,我们的集群应该可以运行了。

      让我们连接到Tungsten Fabric GUI:
      f93f1b03-6345-4c45-8705-98245960a45e-image.png

      我们看到两个虚拟路由器:os-compute和k8s-worker!

      我们看一下控制节点:
      c434da04-a779-4028-9c62-4265ec56af9e-image.png

      只有一个控制器!我们“单一网络平面”的关键概念变成了现实。

      接下来,我创建了一个虚拟网络:

      • FQ名称:default-domain:k8s-contrail:seamless
      • CIDR:192.168.1.0/24

      启动一个连接到该VN的虚拟机:

      nova boot --image cirros2 --flavor cirros --nic net-id= vm
      
      (kolla-toolbox)[ansible@os-control /]$ nova list
      +--------------------------------------+------+--------+------------+-------------+------------------------+
      | ID                                   | Name | Status | Task State | Power State | Networks               |
      +--------------------------------------+------+--------+------------+-------------+------------------------+
      | 3cf82185-5261-4b35-87bf-4eaa9de3caaf | vm   | ACTIVE | -          | Running     | seamless=192.168.100.3 |
      +--------------------------------------+------+--------+------------+-------------+------------------------+
      

      接下来,创建一个连接到该VN的容器:

      [root@k8s-master ~]# cat cn.yaml
      ---
      kind: Namespace
      apiVersion: v1
      metadata:
        name: seamless
        annotations:
          'opencontrail.org/network' : '{"domain":"default-domain", "project": "k8s-contrail", "name":"seamless"}'
        labels:
          name: seamless
      ---
      apiVersion: v1
      kind: Pod
      metadata:
        name: cont
        namespace: seamless
      spec:
        containers:
        - name: cont
          image: alpine
          command: ["tail"]
          args: ["-f", "/dev/null"]
      
      kubectl apply -f vn.yaml
      
      [root@k8s-master ~]# kubectl get pod -n seamless -o wide
      NAME   READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
      cont   1/1     Running   0          74s   192.168.100.4   k8s-worker              
      
      [root@k8s-master ~]# kubectl get -f cn.yaml -o wide
      NAME                 STATUS   AGE
      namespace/seamless   Active   31m
      
      NAME       READY   STATUS    RESTARTS   AGE   IP              NODE         NOMINATED NODE   READINESS GATES
      pod/cont   1/1     Running   0          31m   192.168.100.4   k8s-worker              
      

      如你所见,由于192.168.100.3已经被VM占用了,pod被分配了192.168.100.4的IP地址。这也是多个集群使用单一网络平面的优势之一。
      baf8bb04-32e2-49a1-8d2f-5b9f631a0305-image.png
      b5add53a-601e-4d02-94a3-8f6b00f6687d-image.png

      让我们从GUI中查看一下路由表:
      37e5b67e-6f59-4308-b949-51b7905e31c0-image.png
      两个IP都有!我们刚刚把一个虚拟机连接到一个工作负载上……而这对underlay是完全透明的!

      让我们再到worker节点,查看一下vRouter代理:

      (vrouter-agent)[root@k8s-worker /]$ vif --get 3
      Vrouter Interface Table
      
      vif0/3      OS: tapeth0-11ccbe NH: 51
                  Type:Virtual HWaddr:00:00:5e:00:01:00 IPaddr:192.168.100.4
                  Vrf:4 Mcast Vrf:4 Flags:PL3L2DEr QOS:-1 Ref:6
                  RX packets:67  bytes:2814 errors:0
                  TX packets:87  bytes:3654 errors:0
                  Drops:67
      
      (vrouter-agent)[root@k8s-worker /]$ rt --get 192.168.100.3/32 --vrf 4
      Match 192.168.100.3/32 in vRouter inet4 table 0/4/unicast
      
      Flags: L=Label Valid, P=Proxy ARP, T=Trap ARP, F=Flood ARP
      vRouter inet4 routing table 0/4/unicast
      Destination           PPL        Flags        Label         Nexthop    Stitched MAC(Index)
      192.168.100.3/32        0           LP         25             39        2:85:bf:53:6b:67(96024)
      (vrouter-agent)[root@k8s-worker /]$ nh --get 39
      Id:39         Type:Tunnel         Fmly: AF_INET  Rid:0  Ref_cnt:8          Vrf:0
                    Flags:Valid, MPLSoUDP, Etree Root,
                    Oif:0 Len:14 Data:56 68 a6 6f 05 ff 56 68 a6 6f 06 f7 08 00
                    Sip:192.168.200.14 Dip:192.168.200.13
      

      所有的路由信息都在那里!容器可以通过连接Kubernetes worker节点和OpenStack计算节点的MPLSoUPD隧道到达虚拟机。

      这样就可以进行通信了吗?还不行!别忘了安全组还在那里!

      虚拟机属于一个OpenStack项目(这里是管理项目),而容器属于另一个项目(映射到Kubernetes命名空间)。每个项目都有自己的安全组。默认情况下,安全组只允许来自属于同一安全组的入口流量。由于两个工作负载的接口被分配到不同的安全组,因此它们之间不允许对话!

      为了解决这个问题,我们需要对安全组采取行动。

      简单的方法是在两个安全组上都允许来自0.0.0.0/0的入口流量(这是容器安全组,但同样也可以在虚拟机安全组上进行):
      145bb302-b9b3-48ce-a570-888829fd93ff-image.png
      另外,我们也可以在入口方向允许特定的安全组。

      例如,在k8s-seamless-default-sg(容器所属命名空间/项目的安全组)上,我们允许默认安全组(虚拟机所属OpenStack项目的安全组)。
      c629ed30-4733-46ec-9d1d-530fdbf728ae-image.png
      同样地,也可以在分配给虚拟机接口的安全组上进行:
      22418c56-9360-4903-ba85-f3e7bc5a8612-image.png
      现在,让我们访问容器,并且ping一下虚拟机:

      [root@k8s-worker ~]# docker ps | grep seaml
      18c3898a09ac        alpine                                                         "tail -f /dev/null"      9 seconds ago       Up 8 seconds                            k8s_cont_cont_seamless_e4a7ed6d-38e9-11eb-b8fe-5668a66f06f8_0
      6bb1c3b40300        k8s.gcr.io/pause:3.1                                           "/pause"                 17 seconds ago      Up 15 seconds                           k8s_POD_cont_seamless_e4a7ed6d-38e9-11eb-b8fe-5668a66f06f8_0
      [root@k8s-worker ~]# docker exec -it 18c38 sh
      / # ip add
      1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
          link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
          inet 127.0.0.1/8 scope host lo
             valid_lft forever preferred_lft forever
      24: eth0@if25:  mtu 1500 qdisc noqueue state UP
          link/ether 02:e4:e5:52:ce:38 brd ff:ff:ff:ff:ff:ff
          inet 192.168.100.4/24 scope global eth0
             valid_lft forever preferred_lft forever
      / # ping 192.168.100.3
      PING 192.168.100.3 (192.168.100.3): 56 data bytes
      64 bytes from 192.168.100.3: seq=0 ttl=64 time=3.813 ms
      64 bytes from 192.168.100.3: seq=1 ttl=64 time=1.802 ms
      64 bytes from 192.168.100.3: seq=2 ttl=64 time=2.260 ms
      64 bytes from 192.168.100.3: seq=3 ttl=64 time=1.945 ms
      ^C
      --- 192.168.100.3 ping statistics ---
      4 packets transmitted, 4 packets received, 0% packet loss
      round-trip min/avg/max = 1.802/2.455/3.813 ms
      / #
      

      就是这样!虚拟机和容器可以互相对话了!

      无论你的工作负载是虚拟机还是容器……至少从网络的角度来看,一切都是在Tungsten Fabric的机制下进行的。


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https://iosonounrouter.wordpress.com/2020/12/14/contrail-providing-seamless-virtual-networking-to-openstack-and-kubernetes-clusters/


      posted in 博客
      B
      bing
    • 洞察Tungsten Fabric内部的XMPP

      XMPP是一个用于通讯和表示的开放标准协议。从本质上讲,它是一个允许实体交换信息和进行聊天的协议。

      XMPP就在我们身边……比我们想象的要多得多。WhatsApp使用了XMPP的一个变种,Zoom使用XMPP以及一些扩展来实现其聊天功能。XMPP是一些最常用和最著名的应用程序的背后技术。那么,XMPP是如何工作的呢?

      如前所述,它允许实体交换信息和聊天。我说的是实体,因为这种聊天和信息交换可能涉及两个人,也可能是两个服务器/软件之间的对话。

      XMPP利用了TCP。我们可以说XMPP是一个使用TCP作为底层L4协议的L7协议(就像HTTP)。

      到这里为止,XMPP可能看起来就像任何其它协议一样,将消息带入其有效负载。

      围绕XMPP值得注意的是,交换的数据是XML格式的。这就导致了两大优势:第一,XML是一种结构化的标准语言,可以很容易地被编程语言消化/处理;第二,只要用XML来格式化这些信息,就可以很容易地扩展XMPP可以传输哪些信息。

      关于后面一点,请看以下链接,了解这些年发展了多少扩展:

      https://xmpp.org/extensions/

      XMPP与TF如何共同工作

      让我们简单看下XMPP对话是如何工作的吧!详细的解释并不在本文讨论范围内,但我将尝试划出一些相关方面的重点,这将有助于理解Tungsten Fabric中的XMPP是如何工作的。

      访问资源的用户由所谓的JID来识别:

      [ node "@" ] domain [ "/" resource ]

      例如,“iosonounrouter@whatsapp/mobilechat”可能代表我(iosonounrouter)使用whatsapp并访问mobilechat资源。

      资源可以被看成是我想访问的一类聊天室/话题/频道。想象一下,某个软件要从互联网上检索信息,它可能使用XMPP来访问不同的资源:

      • client@infohub/sport

      • client@infohub/finance

      第一个JID可以用来访问资源以查找和检索体育新闻,而第二个JID将相同的功能用于金融数据。

      通常情况下,XMPP遵循客户端-服务器的交互方式(即使p2p也是可能的)。客户端和服务器发送/接收所谓的XMPP节段(stanzas)——节段有不同的用于客户端和服务器的类型。XMPP核心主要有三种类型的节段:

      • 消息(message):顾名思义,它带来消息。采用的是“fire and send”的模式,也就是说,没有可靠的方法来确保消息在另一端被收到。某种程度上,我们可能会把这个节段看作是UDP:发送出去,并希望它能成功!当然,这个节段可以包含XML格式的结构化数据。
      • 表示(presence):用于宣布系统内有某种东西的存在
      • IQ:代表消息(info)/查询(query),允许实现类似于http的请求/响应机制(例如GET)。使用IQ,我们可以获取/设置数据。不同于消息,IQ使用了确认通知,以提供更可靠的通信。

      下图总结了目前为止所看到的概念:
      a1485630-dabf-4530-bcd0-811e97302502-image.png
      比如我们有两个客户(Ivano和Carmela)访问一台服务器(infohub)。服务器上有两个资源(金融和体育)。如前所述,可以将资源看作是聊天室/主题/频道。客户端通过JID访问这两个资源,总共会有四个“对话”。在每一个对话里面,客户端和服务器将使用节段来交换信息,即IQ、MESSAGE、PRESENCE等......

      现在,有一个问题出现了:Tungsten Fabric在这里做了什么?

      如果你有一些Tungsten Fabric的知识,可能知道TF使用XMPP在控制节点和计算节点之间交换数据。控制节点和计算节点会聊天,谈论TF集群内发生的事情。控制节点作为XMPP服务器,而计算节点作为客户端。

      XMPP带来了什么样的信息?大多数时候,我们说XMPP取代BGP进行控制节点-计算节点通信,说明它是用来携带路由信息的。这是事实,但不完全正确。

      XMPP也被用来携带配置信息(我们将在后面看到这意味着什么)。这里的关键概念是,XMPP既是一个信令协议,也是一个配置协议。

      如何转化为XMPP术语呢?很简单,这里有两个资源:一个是配置资源,一个是路由资源。

      把控制节点-计算节点对(pair)看成是两个朋友在互联网上聊天。他们聊的是两个话题:配置和路由。当一个人有关于配置方面的事情要讲时,就会通过配置通道(资源)来讲。另一方面,当有一些路由信息需要沟通时,会使用路由通道。

      下图说明了这种互动关系:
      ebf6e82a-68c2-4df7-bd71-138e6bb2e977-image.png
      节点通过两个不同的通道交换信息,将数据编码成XML格式的负载。

      现在,有关XMPP和Tungsten Fabric如何共同工作所需的最基础知识,我们就都已经掌握了。

      为了学习XMPP,我们将继续进行以下步骤:
      55362672-513e-4cb2-ba74-75f177f6f0d9-image.png

      • 一开始,我们有一个空的计算节点,上面没有虚拟机运行。

      • 接下来,终端用户(通过GUI、Heat……)创建一个虚拟网络和一个连接到该虚拟网络的虚拟机。

      • 因此,控制节点将向虚拟机运行的控制节点发送XMPP消息,以便告诉它配置和路由信息。

      创建虚拟机后,我使用tcpdump捕获计算节点上的XMPP数据包。

      先来看看pcap。首先,我们要告诉Wireshark将5269端口解码为XMPP。
      81c1495d-f269-4e7d-9d17-c1c18a4c1286-image.png
      此时,过滤XMPP数据包,检查信息栏。
      82e97773-549b-4b8c-a3d1-f4981d613a60-image.png
      它们看起来像JID……确实也是!

      • 用户(计算节点)为网络控制(network-control)

      • 服务器(控制节点)为contrailsystems.com

      • 两个资源为:bgp-peer和config

      它们就在这里!就是之前提到的两个通道:一个承载配置信息,一个承载路由信息。

      为什么要两个通道?

      XMPP会带来一些配置信息,因为控制节点要通知vRouter必须创建一些对象:其中包括代表虚拟网络的VRF,以及连接VRF与虚拟机的虚拟机接口。简单地说,config数据包将指示vRouter必须创建的所有这些Tungsten Fabric对象,以便将新的虚拟机整合到虚拟网络生态系统中。

      同时,XMPP也会带来路由信息。新的虚拟机被分配了一个IP地址。关于vnic(虚拟机接口)的IP地址和MAC地址的信息必须传输到计算节点,这样它就可以更新相应的路由表(例如在收到config XMPP消息后刚创建的VRF)。

      正如你所看到的,config和bgp-peer消息经常是相关联的!

      配置信息里都有什么

      现在,让我们来看看这些XMPP信息里面有什么。拿下面这个消息来说:
      86fa3269-9baa-4934-ab9a-47cfc589e56f-image.png
      这是一个IQ“type:set”的消息。使用IQ是很聪明的,因为它需要确认信息;这样Tungsten Fabric可以“验证”计算节点是否真的收到了信息,并且它也避免了计算节点收到路由数据,但没有足够的底层配置对象来使用这些数据的情况。

      IQ数据包应该使用一个ID字段,这样便于跟踪响应。无论如何,Tungsten Fabric不会填充ID属性。

      核心部分已经标蓝。大家可以看到信息是CONFIG UPDATE,意思是“如果存在则更新,否则就创建”。

      接下来,我们有一个要创建的节点和链接列表。可以很容易地发现虚拟网络对象。下面好好观察一下它的内部情况:
      eb44e60e-7bfd-40c3-83f7-d675441d1f9a-image.png
      如果你熟悉Tungsten Fabric,就会发现我们在配置虚拟网络时可以设置的那些设置。例如,VN名称为xmpp_net1,属于juniper-project项目。

      这部分的有效负载基本上是告诉vRouter创建一个新的对象(节点),一个虚拟网络,并告知它的参数和属性。

      对于其它对象(节点)也可以看到类似的输出信息。

      我们看到XMPP数据包中还携带了LINK的信息:
      5829c0be-1c86-457a-aca5-c4319511b47c-image.png
      顾名思义,链接(link)是将两个节点连接起来,以便在配置层代表这些对象之间的“参考”关系。

      例如,在上面的输出内容中,表明要将虚拟路由器与新虚拟机的虚拟机接口“链接”起来。

      这些链接不是随机的,它们与Tungsten Fabric配置模式一致,该模式定义了对象(及其属性)以及对象之间可能的关系,称为链接。这个模式就像Junos XSD模式一样。

      同样,我们希望看到虚拟网络和路由实例对象、实例IP和虚拟网络对象等之间的链接。

      这些信息也可以通过introspect获得。在这里,从Tungsten Fabric GUI中,我“访问”了计算节点introspect web服务器,并请求获得Sandesh Trace Buffer List。
      0ceab37f-7fe6-4a82-813c-d068d0167d61-image.png
      从结果输出中,我们检测到四个相关的轨迹(trace):
      7e2db9c6-9031-4371-a057-8aca556d5ed7-image.png
      其中两个包含接收到的config xmpp消息的信息,其它的是接收到的bgp xmpp消息。每种类型(路由或配置)都有两个轨迹(trace),因为每个计算节点都与两个控制节点进行了XMPP对话(冗余原因)。

      点击“Rx Config Xmpp Message”,选择XSD GRID视图。在那里,我们可以寻找有趣的XMPP消息。
      459522e2-c6b5-4210-a7c6-faa4999656bd-image.png
      例如,这个是指示vRouter必须创建新的虚拟网络对象的消息。如你所见,正文是XML。我们可以将它复制粘贴,并以一种格式友好的方式来查看:
      1f36b68c-232d-40c3-b449-38847169bfa6-image.png
      这些都是我们在Wireshark中看到的信息。

      同样,也可以找到关于链接创建的日志:
      d33d791b-ba31-40ec-b067-ac5fe5be9ed4-image.png
      并提取XML主体:
      28373493-af1c-45ad-88d4-820467417852-image.png
      这是第一个例子,说明XMPP是如何被扩展以携带我们能想到的最多样化的数据集的。鉴于它对XML的原生支持,可以添加想要的信息,只要确保符合XML-syntax即可。同时,作为XML结构的数据,接收端将很容易解析和处理数据。

      扒一扒XMPP路由信息

      接下来进入第二个“通道”:路由。

      虚拟机被分配的地址是172.30.1.3/32。三条XMPP路由消息从控制节点发送到计算节点:
      0aa42e42-692d-429e-8c50-e7d34cff71c9-image.png
      为什么是三条?因为虚拟网络是L3+L2,我们会有一条inet路由,一条evpn mac路由和一条evpn mac:ip路由。
      让我们到内部去看一看:
      064f33b2-d7bc-45f9-a221-1095aaf9b556-image.png
      与以前看到的有一些不同。我们使用的是MESSAGE节段而不是IQ节段。在它里面,BGP路由广告被编码为一个EVENT消息的ENTRY ITEM。

      除了这些方面,上面的输出内容应该是网络工作人员所熟悉的。项目id是路由:172.30.1.3/32。接下来,我们还有NLRI信息。AFI 1 / SAFI 1表示IPv4。然后,是下一跳的信息以及路由所属的虚拟网络名称。

      基本上,我们将BGP UPDATE消息编码成了XMPP有效负载。这又一次证明了XMPP的可扩展性如何使这个协议变得非常灵活。从软件的角度来看,用一个协议(XMPP)就能同时管理配置和路由。除了有些必需的情况(例如与不支持XMPP的SDN网关通信)外,一般不需要有两个协议栈(xmpp和bgp)。

      同样,我们也可以用introspect来提取同样的信息:
      928fe000-7f69-41db-8c4e-a399717e8b3c-image.png
      最后,将虚拟机删除。结果就是,我们又触发了一次XMPP数据包的交换。

      这次它们将不是UPDATE消息,而是DELETE消息:
      f2781451-dd4e-4644-b812-558bea178373-image.png
      因为不再需要,节点和链接都被删除了。

      同样,也会有模仿BGP withdraw消息的routing XMPP消息。我们认识它们是因为RETRACT关键字的存在。这次我们在introspect上看到了这个:
      eb012c7f-7b3c-4c3b-9f5b-3dad24588110-image.png
      2be5fc6a-2d5a-4950-9a6f-02cb46592065-image.png
      就是这样!现在我们知道了XMPP是如何允许Tungsten Fabric节点创建/删除配置对象和路由的。说到底,这就是一个聊天:)


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https://iosonounrouter.wordpress.com/2020/12/07/a-look-inside-xmpp-in-contrail/


      posted in 博客
      B
      bing
    • 通过TF Operator进行统一生命周期管理

      在Linux基金会主办的“LFN技术会议”上,Tungsten Fabric社区进行了一系列演讲,介绍最新的功能和未来发展方向。今天带来第三篇演讲,通过TF Operator实现Tungsten Fabric各方面的部署和生命周期管理。

      嗨,大家好!我是Prabhjot Singh Sethi,做架构师已经第八个年头了,今天的主题围绕使用TF Operator进行统一的生命周期管理,同时将演示集成Airship的应用案例。

      (附注:Airship是一组用于自动化云配置和管理的开源工具,它提供了一个声明性框架,用于定义和管理开放式基础架构工具和底层硬件的生命周期。)

      我们从Tungsten Fabric的发布开始,正如很多人已经知道的,Tungsten Fabric目前是作为一个容器镜像进行打包和发布的,所以基本上在部署它们时,最终会定义为基于docker compose的服务或者Kubernetes的原生对象,来真正推出Tungsten Fabric的各种组件。
      2dd1b9a1-0d93-4894-a638-b95205d61fbb-image.png
      当我们这样做的时候,各种模块的生命周期管理要求就变成了首要问题,任何部署系统都必须满足这些依赖关系。例如某些模块被期望按照预定的顺序部署,然后有一些有状态要素的基础设施组件,比如zookeeper,在部署config模块之前这些组件被期望达到某个状态,而这将取决于zookeeper。

      此外,在升级和其它的方面,我们需要确保执行升级时各模块间关系的匹配,某些时候升级到各个版本需要执行不同的方案,而不是遵循类似的方案。

      最后同样重要的是,作为一个网络提供商,我们还需要处理集群规模问题——当你有新的节点要进入系统,或者当你的Tungsten Fabric需要增加水平扩展的配置节点或控制器节点的时候。

      在进入Tungsten Fabric Operator之前,我简单地介绍一下Operators和围绕它的框架。

      回到最初的概念,Operator实际上就是K8s控制器,它的框架就是围绕K8s API提供Operator SDK的开发工具包,这有助于我们建立一个K8s控制器,然后封装其它组件,如Operator生命周期管理器——与Operator互动,并管理系统中所有Operator的生命周期。然后,通过Operator Metering实现使用报告和周围的东西。

      所以,基本上作为K8s控制器,Operator是有目的地建立与其需要执行的知识间的关系,这就是它的工作,通常比任何通用的工具更好、更智能。同样地,它还可以把自动的操作逻辑打包为Operator的一部分,进而允许复杂的自动化任务。

      TF Operator也一样,无非是一个K8s控制器,它的构建目的是解决Tungsten Fabric的生命周期管理需求,所以它本质上是一个TF的生命周期管理器。如果你看一下这些不同的组件在Operator框架中是如何定位的,就会发现Operator本质上是一个生命周期管理器,围绕它有一个封装的OLM,触发Operator实际进行安装和升级。

      8ff60953-24e7-4296-9c37-4308dec91d08-image.png

      围绕Tungsten Fabric生命周期管理的所有需求,目前包括OpenShift、Ansible、Operator Framework、Helm Charts,甚至Juju创建的各种资源库。由于多种安装方案的出现,以及各种集成的解决方案,基本上要把Tungsten Fabric的生命周期管理原生地做进这个方案。

      当你想用Ansible来做的时候,Tungsten Fabric所有的需求期待成为解决方案的一部分。当你想用OpenShift来做的时候,也是作为其中一部分方案来做的,而我们最后会把它们都复制过来。这本质上增加了任何一项工程的维护周期,额外的维护周期又涉及到更多的成本。

      所以我们一开始的目标很简单,就是看如何简化生命周期管理,尽量提高软件的可管理性,以及降低这些成本。而我们需要回答的进一步的问题,就是有没有一种方法来统一应对Tungsten Fabric的LCM处理?如何简化可以允许TF集成到各种部署方案中,而不用担心如何处理每一个独立部署组件之间的版本依赖性问题?当然,集群的扩展也是另一个要考虑的因素。

      这时候TF Operator就起到了一个重要的作用,让我们实现了生命周期管理器的统一。本质上TF Operator可以成为一个基于部署(based deployments)的生命周期管理器。当我们谈论TF Operator时,我们谈论的是K8s的原生控制器,其它组件部分都不在TF Operator的范围内,只与OLM有关。而我们在实现的时候,它所允许的是让我们能够重新使用TF Operator作为部署的一部分,也作为Helm deployment,以及Juju Charms的一部分。本质上是通过引入TF Operator来运行以及触发来做各种部署。

      通过这样的方式,基本上解决了各种K8s部署与TF集成的问题,比如Airship、OpenShift、K8s、kubeadm、Canonical等,甚至是OpenStack Helm部署。

      接下来,我们看下Airship集成的案例,这种整合是如何真正工作的,也将分享一个代码的链接,这是公开的,任何人都可以访问。

      首先从需求开始。无论何时,你想使用任何软件以实现首要的需求,我们要有一个Airship Armada Chart,这只不过是一个Helm Chart的wrapper,加入Airship站点定义。然后,Tungsten Fabric被包装为Helm Chart的形式,实际上可以部署SDN控制器、CNI,甚至是OpenStack Neutron。

      这种方案真正成功的原因,是你可以使用Helm Chart做一个常规的或基于概念验证的安装。目前,Helm Chart还没有足够的能力提供Tungsten Fabric所需要的生命周期管理的所有方面,这就是TF Operator能发挥更大作用的地方。

      6a69a971-d80f-4759-a124-0297cb7c8cf3-image.png

      如果你期待使用TF Operator作为其中的一部分,还要包括Operator本身的Helm Hook,所以Helm Chart不会部署TF本身,而是部署TF Operator,传统意义上它只提供站点定义作为其中的一部分。它将触发基于对象的K8s,本质上是以TF控制器的形式运行,这是由Operator本身管理的。为了完成这个动作循环,我们要确保等待TF控制器运行完成,并触发回Airship Armada Chart。当知道控制器已经运行,现在各种其它组件可以继续部署。把网络提供商看成一个基础设施组件,我们要确保这个触发的工作,否则组件运行会失败,这是非常重要的。

      我们有上述方案的参考实现方案,下面两个代码的链接都是可以公开访问的。

      https://github.com/atsgen/tf-Operator-helm-hook
      https://github.com/atsgen/treasuremap

      一旦我们有社区版TF Operator,我们将迁移这些方案,以使用社区版的TF Operator。以上是我们期待这个统一方案的问题解决方式。关于如何看待这个统一管理的成功,或者它真的可以走多远,欢迎任何人做出讨论、评论,我们要确保能够使用软件的LCM解决几乎所有的问题。


      视频链接:https://v.qq.com/x/page/x3218minifn.html
      文档:https://tungstenfabric.org.cn/assets/uploads/files/unified-life-cycle-management-using-tf-operator.pdf


      posted in 博客
      B
      bing
    • 共创2021:加入我们,创建一个透明的TF社区

      在Linux基金会主办的“LFN技术会议”上,Tungsten Fabric社区进行了一系列演讲,介绍最新的功能和未来发展方向。今天带来第二篇演讲,解析Tungsten Fabric社区的透明化机制。


      视频链接:https://v.qq.com/x/page/b32174zu7hc.html


      2020年给了每个人前所未有的反思,如果说这一年的启示是重构和改变,面对2021,我们应该以怎样的姿态,挑战变化和不确定,穿越更多的危机呢?也许开源、连接、共享,是一把通向未来的钥匙,让我们能在相互依存中共同守望。

      TF中文社区旨在架设国内开发者、用户与Tungsten Fabric国际资源之间的桥梁,设有技术委员会,以及文档工作组、社区联络工作组、行业案例工作组和基础架构工作组等机构,负责TF中文社区相应工作的开展。

      欢迎更多小伙伴加入TF中文社区,共创2021年开源SDN新的可能性。

      大家好!我叫Marek Chwal,我将和Szymon Golebiewski一起,给大家介绍Tungsten Fabric社区的信息,它也是Linux基金会旗下的项目之一。
      7e508c68-2d57-4996-8301-e35c9b2f412b-image.png
      什么是Tungsten Fabric呢?它是一个用于综合编排的开源项目,能够统一管理各种由不同组件构建的软件定义网络。组件包括SDN控制器、虚拟路由器,也包括Analytics部分需要的API、硬件集成,而且它是基于REST API的。

      接下来介绍一下Tungsten Fabric社区的主要架构或主要角色。首先是一个强大的技术指导委员会(Technical Steering Committee),负责制定顶层的架构目标,也协调整个项目的架构和技术方向。目前由7名有投票权的成员组成。
      f116e12c-557d-46af-b534-107cfc077344-image.png

      然后,我们还有发布经理(Release Manager),我很荣幸能够担任这个角色,发布经理为期一年,也是票选出来的,负责对想实现的目标设定和监督响应。

      我们还有一些子项目,也有个人的项目技术负责人(Project Technical Lead),负责处理特定的子项目,提供方向,他们从特定项目的委员会中选出。

      当然我们还有提交者(Committer)和贡献者(Contributor)。Committers是有资格提交源代码的人,因为对特定模块有很深的了解。

      这一切都要尽可能的透明化,让任何愿意加入我们的人都能得到帮助,所以如果你想成为一个贡献者,可以查看项目列表,在我们的wiki页面上构建模块列表,也可以指派人员来做。
      d2901e5e-8391-4040-9874-94a27d5cf83e-image.png
      关于项目的架构。我刚才说过有几个子项目,最主要的是Tungsten Fabric core项目,负责处理我们几乎所有模块的开发。这些模块代表了Tungsten Fabric的相关功能区,关于如何把产品划分成模块,我们进行了大量的讨论。对于每一个模块,我们也有专门的人员,他们被提名来处理特定的模块,处理特定的存储库,他们能够帮助我们,也理解所要求的变化,所以这些人被提名来提供反馈,并为所要求的变化提供批准。

      接下来是Tungsten Fabric社区发布流程的部分,我们已经开始了这个讨论,并且定义了有关这个流程的若干里程碑。
      45012fe4-cdf1-4fd7-a28c-2f34c782eb0c-image.png
      首先,M0是对于参与特定发布的简单声明,同时它也收集蓝图,蓝图是对于所要求变化的粗略描述。所以,如果有人想参与我们的发布,提供新的功能,或增加现有的功能,可以提出蓝图。蓝图将在Tungsten Fabric社区内进行讨论,负责审批的人将检查它是否合适。不需要提供完整细节,只需要一个想法就可以。

      然后我们有M1,对于M1的实现,我们希望明确定义这个新功能和现有功能之间模块之间的依赖关系,只是为了确保新的变化不会对产品产生负面影响。而且在这个里程碑中,我们也希望有这个特定变化的发布计划。这意味着要把这个想法分解成更小的部分,变成任务,以后可以跟踪的。

      关于M2里程碑内部的技术设计,我们要确定技术设计冻结(technical design freeze),意思是从设计的角度什么都不要改,当然此刻通常叫“正在开发”。

      那么到M4里程碑的时候,大约至少要有一个比较好的外部API的版本,能够开始测试的版本。M4的阶段是代码冻结(code freeze),意味着主要功能应该已经可以使用了,目前只允许修复bug。

      然后我们有几个阶段的候选版本的发布,从0到3,如果需要的话也可能会更多。所有的候选发布,都已准备好所有的功能,准备好适合创建新的分支。而这将使我们专注于核心的稳定,并为他们的部署做好准备。这就是主要的发布流程原则。
      56506697-e18b-4f19-96c9-8fc1fb0b4f69-image.png

      为了能够跟踪它,变更请求被呈现为Jira epic,为此我们在Jira看板中创建了这个看板,这只是看板的一部分,每一个里程碑都被呈现为列。所以你可以看到,我们已经开始为下一个版本工作,也就是2011的版本吗,大概有17个变化或者17个大的epic,大部分已经到了M0的状态,我相信被选中讨论的那两个很快就会完成。

      接下来,由Szymon来介绍一下文档相关的原则。
      ed6b9cb3-c768-4160-b882-bad8936073e5-image.png
      为了创造Tungsten Fabric社区的透明度,从组织文档过程本身开始,对于需要在项目中给出适当的文档,我们做了很多努力。你可以看到,我们定义了文档应该涵盖的几乎所有领域,并沿着现有的材料创建了一个适当的Jira任务,每个人都可以跟踪我们在这个领域到底在做什么。另外,我们还有我们即将到来的任务,从最大的贡献者Juniper迁移到Tungsten Fabric的文档。对于社区来说,这是一个非常重要的任务,它作为一个工具,对于整个开发、部署和安装建议等方面,给我们提供了一个非常好的基础。另外,摆在我们面前的其他重要任务是建立规则和要求。这样无论做什么都会维护项目,产品的适用性也会保持更长时间。最长期的任务是填补我们在文档中发现的所有空白。而且我们需要确保所有的东西都有很好的文档,运行一个开源项目是不能有一个失败点的。这就是为什么我们定义了这样的文档领域。
      319a2eb6-080c-4458-9027-8579ce139040-image.png

      我们认为文档不仅要包含治理(Governance),并且在社区内发生的每一个活动都应该被很好地记录和描述给现有的和任何新的参与者,这一点至关重要。这就是为什么我们的目标是记录治理、发布流程,甚至支持活动等方面的内容。

      如果你想加入,参与创建文档,可以从下面这两个链接开始:
      https://wiki.tungsten.io/
      https://jira.tungsten.io/projects/DOC/

      记录你的活动,在Jira中跟踪我们的活动。包括你想了解自Tungsten Fabric启动以来文档各个部分的真相,可以访问文档项目的wiki页面。
      815a69f8-7b33-436b-b6eb-8687a2de9502-image.png

      最后一张幻灯片,如果大家想要加入Tungsten Fabric社区,只需要做五个简单的步骤:在Linux基金会创建你的账户(myprofile.linuxfoundation.org),然后登录Jira和wiki,这样你的账户就会被填充,然后打开 tungsten.io/community 网站页面,在那里你会发现所有的链接,比如slack频道等。加入这些频道,你可以认识创造这个伟大社区的人们,当然也可以开始自己的贡献。


      视频链接:https://v.qq.com/x/page/b32174zu7hc.html


      posted in 博客
      B
      bing
    • TF功能开发路线图:盘点2021年Tungsten Fabric聚焦领域

      在Linux基金会主办的“LFN技术会议”上,Tungsten Fabric社区进行了一系列演讲,介绍最新的功能和未来发展方向。今天带来第一篇演讲,看看Tungsten Fabric在2021年将聚焦哪些亮点功能和项目,以及计划涵盖的主要创新领域。

      大家好!我是Nick Davey,现在是早上8点,我刚喝过咖啡,会尽量保持清醒,非常感谢你们这么早参与进来,感谢有这个机会与社区进行探讨。

      我是瞻博网络的产品经理,日常工作是以各种形式使用Contrail和Tungsten Fabric,我认为自己在Tungsten Fabric上投入的情感更多一些。特别是过去的几个季度,在整个社区——包括瞻博网络CTO在内——大家的努力下,有了一些新的进展,我很期待看到一些伟大的事情和蓝图正在展开。

      我们在社区中扮演着独特的角色,作为开发者,我们推动一些功能往前走,确保我们在Juniper所做的事情,能够转化为对于社区来说具有可行性的东西,这是一个不小的挑战。但我们与社区中的技术专家和领导者一起,找到了一种方法,使功能或项目回到符合我们的意图和愿景的道路上,我认为我们已经做出了有意义的改变。

      那么我们到底要做什么?这里我整理了几个简要事项,关于重点领域已经和将要推进的工作。我会围绕其中的一些点进行讨论,希望这些项目能激发大家的讨论,如果有任何问题或评论,请直接提问。

      fc9867d0-fde2-44f5-83cc-aff00db65bce-image.png

      我把要关注的工作集中到两个框里。第一个是让Tungsten Fabric更具时代性,适应更多的云原生用例。Tungsten Fabric社区一直是走在网络前沿,我们已经有了一个令人难以置信的强大的解决方案,首先是开放的 Contrail,然后是用于容器编排和网络的Tungsten Fabric。我想这要追溯到两年半以前,那时我们已经有了一套强大的K8s功能套件项目。今年的主要进展之一,是更动态地适应可用的K8s服务和API端点,并允许我们部署较新的版本。

      每当Juniper内部有一个版本发布的时候,我们都会进行资格认证,针对不同的编排器和不同版本进行测试。之前几乎所有的测试都是围绕着K8s 1.12进行的,然后我们通过了对OpenShift 3.11的支持,将K8s版本推到了1.14和1.16,而现在已经进行了包括1.18在内的资格认证。我们花了很多时间来覆盖1.16和1.14之间的版本。你可以对使用当前版本的K8s开展工作抱有信心,可以使用K8s RK DS版本参数部署任何版本的K8s。总之,我们现在已经运行在Kubernetes 1.18上,它的工作状况也非常棒!

      我知道这不是什么头条,但对于跨编排器和跨多个版本保持灵活性,这件事真的至关重要。K8s已经显示出非常快的创新步伐,所以我们需要确保跟上。确保花很多时间测试这些版本,确保一切都能正常工作。在K8s里面增加了对多接口网络的支持,这里面也有一堆工作。它们引入了对多网络附件定义的支持,对于多接口pod是一个非常非常长的路。

      多接口pod背后的想法是,pod的每一个接口都会连接到CNI,提供一套差异化的服务。电信行业用户设想了一个部署模式,默认的pod网络提供安全的管理访问,然后一个或多个数据平面接口将提供直接访问或访问底层网络的支持。

      这些设想的方案,往往集中在多CNI方面,每个CNI通常有一个或多个接口。我们与Tungsten Fabric社区一起工作,去了解电信客户设想的这个功能的用例,真的是需求什么。我们一起合作,开发自己的网络附件定义。

      我们仍然使用相同的manifest来控制这个功能,所以当你使用Tungsten Fabric的时候,它是相同的配置来创建多个接口,在K8s manifest里面实际的附件定义会触发Tungsten Fabric上虚拟网络的创建,这真的很酷。现在你可以让集群租户自己服务于自己的网络,但关键的区别在于,所有的网络连接都是由单一的CNI来交付的,Tungsten Fabric交付你在pod上创建的所有接口。这很好,符合电信运营商用户的需求,要注意的是,对这些工作负载有一些不同类别的连接要求,通常像SRIOV这样的需求会排在前面。

      在此基础上,一些应用如OKD和红帽OpenShift,会假设Multus是不间断的,Multus将成为K8s生态系统的一部分。团队提供了对Multus的支持,这使得Tungsten Fabric仍然有多个接口连接到它,提供这种强大的和电信级路由器一样的体验。基于Tungsten Fabric可以有多个接口,连接到不同的虚拟网络,服务于不同的功能。并且,你还可以复用正在使用的实际的CNI。我们前进的方法是与上游保持一致,时刻考虑客户和社区成员的用例。

      围绕IaaS领域,也发生了令人兴奋的变化,特别是我们作为系统运营商如何管理虚拟机方面。K8s正在变成几乎所有东西的首选编排器,有越来越多的功能被添加到这个平台上。KubeVirt最新的改进,是允许使用一堆客户资源定义在K8s里面运行虚拟机。这代表了一条非常宽广的前进道路。首先,向云原生和容器的过渡,这不是一朝一夕的事情,通过在K8s集群里面添加虚拟机对象,我们现在有了选择,可以更快地从传统的VMware和OpenStack编排器中转型。如果这是我们的计划,显然这些技术需要一段时间才能成熟,但我们要确保Tungsten Fabric在这个转型的前沿。我们正在努力并计划在短期内提供基于K8s在Tungsten Fabric上部署虚拟机的能力,已经有一堆代码提交以确保其能够运行,同时团队仍在进行功能的测试和验证,保证它能很好地工作。

      最后一项工作是针对高性能容器部署的工作,我们正在紧锣密鼓地将DPDK接口引入到容器中。目前TF可支持DPDK 19.11的版本,将过去我们所依赖的一些旧的DPDK代码从Tungsten Fabric中移除,这是我们向前迈出的一大步。社区也围绕这个做了很多工作,确保大家所有的努力工作首先是要提供真正的功能、产品和项目。

      我们已经花了大量的时间在DPDK上,无论是在Juniper内部,还是社区内部的工作,结果都是非常美妙的,我已经看到了一些数据,基于新的MD硬件,使用最新的DVDK库,可实现每核心每秒320万个数据包转发。考虑到还可以通过额外的核心来扩展这一事实,我们有一个真正的、非常强大的高性能解决方案!我们现在正寻找将这种类型的软件加速的数据平面带入到容器中,并与社区成员合作,以确保联合做到这一点。

      现在我们的经验是,很多初始的容器网络功能都是依赖于SRIOV,所以我们正在利用的一个解决方案是Multus和SRIOV CNI组合来提供SRIOV,目前我们正在与容器网络功能厂商、电信用户,以及运营商项目成员合作,了解连接这些SRIOV最理想的模式是什么。这完全是云运营商的选择,但我们认为,那些希望使用更多分解堆栈的人,与那些希望看到这种能力内在地建立在单一数据平面中的人之间会有分歧。

      这真的是我们在云原生方面的关注点。世界正在走向云原生的未来,OpenStack也有一个漫长而充满活力的未来,有很多很多的OpenStack部署正在进行,大型的OpenStack项目正在出现,这些云才刚刚开始,它们会成长和扩展,提供更多的服务,它们会发展到更多的区域。总之,OpenStack是不会消失的。我们需要认识到作为一个项目和一个社区,我们的角色是脚踏两个阵营:帮助传统的云运营商,以最小的影响方式迈向云原生的未来。

      为了做到这一点,我们正努力将很多现有的生命周期管理变得具有时代性,所以在TF社区做了大量的工作,增加了对Ubuntu新版本、Charmed Canonical OpenStack新版本和Red Hat OpenStack新版本的支持和更新。这可能是我们大家做的最辛苦的工作,是最不容易被发现的,或者说是最不容易兴奋的,直到不能运行了才会被发现。

      通过支持更具时代性的编排器和版本,也带来了新的生命周期管理和新的模式。围绕Tungsten Fabric的运营,包含了大量难以置信的工作。运营商将是我们打算如何生命周期Tungsten Fabric向前发展,不仅是OpenShift K8s,也是所有的OpenStack dest drawers,我们部署典型的虚拟机和微服务将嵌入现在的逻辑,为运营商部署Tungsten Fabric容器,并嵌入所需的逻辑,以扩大或缩小规模,或升级这些容器。通过云原生的框架来管理Tungsten Fabric的控制和数据平面,随着编排器的发展,随着工作负载更多走向云原生,我们很好地将其插入到这些容器中,并提供虚拟机和容器之间的网络。

      还有两块正在做的工作,是考虑到我们的解决方案往往部署在基础设施网络为关键任务网络的情况。第一个是我们正在提高路由器的弹性,以检测和应对网络故障或变化,你看到的是第一种工作,trickle in,现在有可调节或可适应的XMPP定时器,这是更快地检测到故障的第一步,所以现在我们允许在所有的vRouter节点上实现XMPP可调节。下一步是围绕服务和可能情况下的传输下一跳,提供快速收敛功能,我们正在寻找适应BGP前缀独立收敛,或选择安装服务路由的备份路径等概念,以便在发生控制器或网关故障时,我们的反应能够更快。我们还希望根据需要引入对其他hello和keep alive协议的支持,以方便更快地检测到链接丢失。

      现在正在进行的第二项弹性和可靠性工作,是改善Controller和vRouter的升级体验。首先的工作是能够在不重启的情况下升级vRouter。这听起来很枯燥,但其实我们是用一个非常整洁的机制来完成这个任务的。我们对重启的要求,最常见的是需要连续的内存驱动的,通过利用标准的巨量页面部署,我们可以保证有大块的连续内存,从而有更顺畅的升级体验。

      此外,在其它零碎的事项上,我们也做了一些工作。第一个是关于数据平面学习,这是以前没有在Tungsten Fabric中做过的事情。我们通常依靠一个编排器来通知控制器Mac IP地址和端口绑定,然后用这些条目填充转发表,并将这些条目传播到集群内部和外部的所有端点。我们看到大量的网络功能被部署在Tungsten Fabric或者vRouter上面的容器、虚拟机里面,结果是传统的机制留下了一个盲点,我们不会有一个编排器来通知这些工作负载的位置,所以必须被动地观察它们,听起来很像flood and learn,但是我们做得更聪明一点。我们现在有了动态学习这些端点位置的机制,所以如果大家在运行assay、任意工作负载或透明服务链,它们就可以在每个虚拟网络的基础上启用这个功能,并看到这些转发条目动态填充。

      我们也认识到在这些容器上面部署了关键的基础设施,我们把动态服务健康检查也作为一个选项嵌入到这些容器中。

      最后,我们现在围绕连接服务器的网络设备的自动化做了很多工作,这一切都始于围绕OpenStack ML2推动的一个项目,用于网络供应,现在正在扩展到允许为OpenStack连接计算节点的SRIOV虚拟功能的自动供应。现在网络中存在一种自动化的漏洞,当我们通过Tungsten Fabric在分配或连接到一个提供商网络时,我们提供一个fabric结构,这是对数据平面的信号,我们希望能够提供一个虚拟功能,但实际上没有任何东西去为我们提供这种连接性。也就是说,如果我们说VLAN on WAN上分配了虚拟功能,在底层网络中并没有任何东西可以确保VLAN on WAN的存在。而这些能力将允许我们通过VLAN on WAN上动态地提供适当的交换机端口,允许OpenStack运营商动态地驱动网络中的配置变化。

      以上就是TF社区近期的亮点,我们最近所做的一些重要事项,希望为2021年即将到来的事情做铺垫。

      Tungsten Fabric内部专注于云原生绝对会带来很多变化,未来会迫使我们做出改变,如果我们只是在它们到来的时候做出反应,会错过更广阔的画面。我们很乐意与TF社区合作,未来会以更多的云原生方式适应或推动我们的工作。


      原文链接:
      https://wiki.lfnetworking.org/display/LN/2020+October+Virtual+Technical+Event+Topic+Proposals#id-2020OctoberVirtualTechnicalEventTopicProposals-TFFeatureDevelopmentRoadmap

      视频链接:
      https://v.qq.com/x/page/u3216w92rq4.html


      posted in 博客
      B
      bing
    • Tungsten Fabric如何实现路由的快速收敛?收敛速度有多快?

      在发布R2008版本之前,Tungsten Fabric无法同时提供南北向和东西向流量的快速收敛。

      实际上,对于南北流量来说,是可以实现快速收敛的,但机制在Tungsten Fabric的逻辑之外:

      • 一个解决方案是将overlay的control_node-sdn_gw的BGP会话分成两个会话,以解决在Tungsten Fabric上缺乏BFD的问题(但这个问题无法完全解决)。包括一个iBGP会话,不含BGP,在Tungsten Fabric和IP Fabric spine之间;一个eBGP会话,含BFD,在spine和SDN GW之间。在这些会话中,交换了overlay路由。因此,一旦eBGP下线,所有指向SDN GW的overlay路由都会从spine上被移除,而spine也会告诉TF控制节点移除这些路由。

      • 另一个解决方案是在SDN网关上实现下一跳可达性检查,这样MPLSoUDP只有在计算节点还活跃/可达的情况下才会启动。如何实现?我们稍后再谈。

      两种变通的方法都能为我们提供南北向的快速收敛。无论如何,东西向的流量仍然容易出现收敛缓慢的情况,因为它依靠的是XMPP timer(默认情况下非常缓慢)。

      实现原理:下一跳的可达性

      为了带来快速收敛,Tungsten Fabric在概念上实现了我们刚才提到的SDN网关的解决方案:下一跳的可达性。

      背后的思路,就是利用过去已经使用过的相同构件来验证SDN GW计算节点是否活跃。

      下图是总结的解决方案:
      960d5810-a56b-45f1-893a-a87712506b00-image.png
      假设IP Fabric实现的是ERB模式(在VMTO的帮助下,CRB模式也是可以的),ERB是指叶子节点为L2/L3 GW,简单地说,就是在叶子节点上配置了VLAN IRB接口。

      在这种模式下,一旦叶子节点学习到一个MAC:IP对,它就会为该IP在inet.0中安装一个/32路由,其下一跳是该IP所属VLAN的IRB逻辑接口。

      在我的测试拓扑中,2个计算节点连接到leaf2。结果如下:
      62e73672-3cdd-4624-b770-815faeabf76a-image.png
      它们在这里了!每个连接的服务器都有一条/32路由!

      现在,我们要通过underlay会话向spine通告这些路由:
      67ce575a-53a2-4d59-a87e-e20a7a34d07b-image.png
      策略导出本地环回(因为是vtep地址,所以需要有)和那些协议evpn路由。

      于是,现在所有计算节点的spine都有了一条/32路由。

      如果其中一个计算节点发生故障,或者连接叶子节点和服务器的链路(或多服务器的链路)发生故障,那么/32路由将从叶子节点上消失。结果就是,将向spine发送一个BGP UPDATE,通知“删除该/32路由”。

      Spine也会收到SDN GW的环回地址。我们希望这个SDN GW环回是南北向流量的MPLSoUDP隧道端点。

      现在,在Tungsten Fabric中实现快速收敛的解决方案应该很清楚了。基本的概念是:指向计算节点的/32路由的存在被解释为计算活跃的标志;当我们看到这个路由,那么计算节点就已经启动并运行了;如果给定的计算节点没有/32路由,那么这个计算节点应该被标记为死机,没有流量将被转发到它那里。这就是我们说的下一跳的可达性。

      我们需要的做最后一步,是将这些/32路由带到TF。这可以通过在控制节点和spine之间的会话上配置family inet来实现。这将允许spine向TF发布/32 evpn路由通告。

      Tungsten Fabric会将这些路由存储到inet.0表中。现在,是解决方案的核心部分。假设compute1死机。相应的/32将作为BGP withdraw消息的结果从inet.0中移除。该下一跳将不再可到达,任何通过它到达的路由都将无法通过下一跳可达性测试。因此,该下一跳后面的所有overlay路由都将失效。

      当然,这里有个假设是,所有这些步骤都是在很短的时间间隔内发生的,比长的XMPP timer要短得多。后面我们将会看到这有多快!

      如果故障节点是SDN GW,也会出现同样的情况;记住,spine同时向服务器/32路由和SDN GW环回发布通告!

      当然,一旦控制节点删除了所有的路由,它也会通知它的对等体(peer):SDN GW通过BGP,计算节点通过XMPP。

      这就是快速收敛的原理。正如你所看到的,它并非“仅仅是Tungsten Fabric”,而是不同角色的组合:

      • 叶子节点必须快速检测到服务器不再可达,从而删除/32路由。
      • fabric必须快速地将这些信息通过BGP传播到TF节点。
      • 控制节点必须快速更新其路由表,并向SDN GW和计算节点传播信息。
      • 计算节点必须快速更新其转发表。

      启用Nh可达性检查

      在查看这个收敛有多快之前,我们先来看看它是如何配置的。如前所述,这个功能从R2008版本就有了。

      在配置模式中,我们在全局设置下找到快速收敛设置:
      10ce3002-6b13-4632-a788-8694e1b5891d-image.png
      同时启用“Nh可达性检查”和“启用”两个复选框。此外,我们还可以配置XMPP timer,以使用比默认选项更小的timer。
      如果我们有了nh可达性检查,为什么还需要XMPP保持定时?这里,nh可达性检查是为了解决网络故障,即叶子节点能够检测到连接到服务器的问题的故障。但这并不是我们可能遇到的唯一的故障。叶子节点和服务器之间的链路可能是可以运行的,但是vRouter软件出现了问题,没有正确处理数据包。在这种情况下,叶子节点不会删除/32路由,控制节点也不会因为nh可达性检查失败而导致路由无效。如果是这样,我们就需要依靠XMPP保持到期时间,让控制节点意识到计算节点已经死机。

      在这里,我们重点介绍基于nh可达性检查的快速收敛。

      启用快速收敛是不够的。我们需要在控制节点和spine之间的BGP会话上增加family inet unicast:
      33f2a143-2fe1-4540-9903-49bfd0afef1b-image.png
      有一个细节我们需要知道。我们必须在spine BGP路由对象(1.1.1.1)和控制节点 BGP路由对象(192.168.200.10)上添加 family inet。如果其中一个对象上缺少inet,family inet就不会被TF control通告。

      让我们检查一下发送这些路由的spine:
      8d27b203-07e5-4a3a-878d-b184ebb6091b-image.png
      Spine正在通告计算节点地址和SDN GW环回地址(2.2.2.1)。它还通告控制节点的IP地址(由控制节点连接的叶子节点也会为该地址生成一个/32)。

      Tungsten Fabric将这些路由存储到inet.0中:
      8b4db014-39e6-4829-a50f-4c1303385c44-image.png
      前面说过,在检查下一跳可达性时,控制节点会验证该下一跳是否作为inet.0中的一个条目。

      收敛速度到底有多快

      现在,是时候验证一下收敛的速度了。

      我的集群是TF+K8s集群。如你所见,有两个计算节点。

      每个计算节点都运行一个连接到默认pod网络的pod:
      b85fce65-2a1d-45f3-ab57-152a29b750c6-image.png
      我打算将compute2从fabric中隔离出来。

      我们可以期待看到什么?

      • 控制节点删除指向192.168.200.12(compute2节点)的inet路由和该计算节点后面的所有overlay路由
      • 将该信息传播给compute1节点

      为了隔离节点,我禁用了连接叶子节点和服务器的接口。

      提交(commit)发生在:

      0   2020-11-24 08:57:40 PST by root via cli
      

      我们检查叶子节点上的BGP轨迹,看看什么时候发送BGP更新:
      8aecf6c5-7e18-460d-a0b3-8e59876e08e7-image.png
      在控制节点上,我们使用Introspect Sandesh Trace来查看BGP更新何时到达:
      131f8d74-89bc-4157-b6a1-3d31a5b05399-image.png
      接下来,我们使用tcpdump查看控制节点何时向compute1(192.168.200.11)发送XMPP更新:
      34237fd9-e32c-4f88-93a7-f3fdbeb73ca9-image.png
      我们还可以用Wireshark可视化XMPP数据包,看它们说要“删除192.168.200.12”:
      013334b9-7b76-4c1d-a481-06736900ed0e-image.png
      最后,在compute1上,我们再次使用Introspect Sandesh Trace来查看路由是何时从转发表中删除的。

      vRouter将compute2前缀删除:
      3a008493-2178-44ce-aeea-3bdd2d48435f-image.png
      同时删除的还有pod前缀:
      c9264383-a340-4269-ae9a-bb2dae8c09e5-image.png
      每个前缀有3个条目,这些路由可以在3个虚拟网络中找到。

      我们将时间戳转换并得到:
      5f531976-0434-472a-bc23-6cfe548787bf-image.png
      让我们来总结一下所有的部分:
      586550be-4b7d-42cc-b140-333112d618cb-image.png
      总的来说,我们花了2.5秒的时间来实现收敛(假设在08:57:40.000提交,这是最坏的情况)。总之,这里的大部分时间,2秒,是从提交到BGP更新发送之间的时间。

      这个时间间隔的意义不大。为什么这么说呢?有下面几个原因。

      第一,这样的故障是人为的,包括提交时间。第二,我在虚拟环境中使用了vMX,所以不是在测试真实的故障情况。第三,由于前面的考虑,我们没有一个精确的故障检测时间值,也就是设备意识到服务器已经无法到达并删除/32路由所需要的时间。而且即使我们有,那也是虚拟MX所需要的时间,在现实情况中,我们很可能会有一个物理QFX。
      因此,最好关注从发送BGP更新到计算节点删除路由的时间。这个时间间隔大约是450毫秒,是一个很好的数值。
      综上所述,收敛时间可能在450毫秒左右+叶子节点检测时间,正如我们所说,必须在真实环境中验证。只要这个检测时间在500ms左右,就可以说我们实现了亚秒级的收敛!


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https://iosonounrouter.wordpress.com/2020/11/26/how-contrail-fast-convergence-works-and-how-fast-it-can-be/


      posted in 博客
      B
      bing
    • TF+ OpenStack部署指南丨利用OpenStack TF配置虚拟网络

      成功安装Tungsten Fabric的下一步,是了解在具体的配置场景中使用编排器部署Tungsten Fabric的工作流程。前面讨论了Kubernetes的部署方案,本文则聚焦在OpenStack上的网络配置过程。

      在OpenStack中创建项目以配置TF中的租户

      在Tungsten Fabric中,租户配置称为一个项目(project)。每一组虚拟机(VM)和虚拟网络(VN)都会创建一个项目,这些虚拟机和VN被配置为租户的独立实体。

      项目是在OpenStack项目页面创建、管理和编辑的。

      1.单击OpenStack仪表板上的Admin选项卡,然后单击Projects链接以访问Projects页面;请参见图1。

      图1:OpenStack项目(Projects)
      3c0947e0-ef40-47b2-a2a3-94ae2ea5ecfc-image.png
      2.在右上角,单击“创建项目”按钮,进入“添加项目”窗口,见图2。

      图2:添加项目
      e4ee6732-08bf-49a5-8bfa-6dfc8d4b46e1-image.png
      3.在“添加项目”窗口的“项目信息”选项卡中,输入新项目的名称和描述,并选择“已启用(Enabled )”复选框以激活该项目。

      4.在“添加项目”窗口中,选择“项目成员”选项卡,并为该项目分配用户。将每个用户指定为管理员或成员。

      一般来说,会有一个超级用户担任所有项目的管理员(admin)角色,而一个成员(member)角色的用户只对应于一般的配置目的。

      5.单击“完成”创建项目。

      有关创建和管理项目的更多信息,请参考OpenStack文档。

      用OpenStack TF创建虚拟网络

      你可以在Tungsten Fabric中通过OpenStack创建虚拟网络。下面的过程显示了如何在使用OpenStack时创建一个虚拟网络。

      1.要在使用OpenStack TF时创建虚拟网络,请选择 Project > Network > Networks。此时将显示“网络”页面。请参阅图 1。

      图 1:网络(Networks)页面
      5a585841-96fb-4afd-b68f-5b7a90e74555-image.png
      2.单击“创建网络”。显示“创建网络”窗口。参见图2和图3。

      图2:创建网络
      91499f41-2495-407c-b204-6d0b95fecef0-image.png
      图3:子网和网关详情
      55fd423e-050c-4428-b6e5-579317038b06-image.png
      3.单击“网络”和“子网”选项卡,完成“创建网络”窗口中的字段。请参阅表 1 中的字段说明。

      表1:创建网络字段
      4a80a7bd-fa9f-4d3d-b90e-0712eaf5f6c4-image.png

      4.单击“子网详细信息”选项卡来指定分配池、DNS域名服务器和主机路由。

      图4:附加子网属性
      ae6a1926-8bf2-4525-9157-5e59fa6b6e23-image.png
      5.要保存你的网络,请单击“创建”,或单击“取消”以放弃工作并重新开始。

      在OpenStack TF中为项目创建映像

      通过使用OpenStack仪表板为系统中的项目指定要上传到映像服务(Image Service)的映像,你需要:

      1.在 OpenStack 中,选择 Project > Compute > Images。将显示“映像”窗口。请参见图1。

      图1:OpenStack映像(Image)窗口
      ad5d0b46-34c3-4d3b-8bd2-2bc2739b36d8-image.png
      2.确保选择了要关联映像的正确项目。

      3.单击“创建映像”。

      此时将显示“创建一个映像”窗口,见图2。

      图2:OpenStack创建映像窗口
      13d2814f-b105-46f6-a391-79182303667e-image.png
      4.完成字段以指定你的映像。表1描述了窗口中的每个字段。

      注意:只支持通过HTTP URL提供的映像,并且映像位置必须能够被映像服务访问。支持压缩的映像二进制文件(.zip和.tar.gz)。

      表1:创建一个映像字段
      4f54f28b-5aed-4273-a446-9b469bfe16f9-image.png

      5.完成后,单击“创建映像”。

      在虚拟机(实例)中使用安全组

      安全组概述

      安全组是指定安全组规则的容器。安全组和安全组规则允许管理员指定允许通过端口的流量类型。在虚拟网络(VN)中创建虚拟机(VM)时,可在虚拟机启动时将其与安全组关联。如果没有指定安全组,则端口将与默认安全组关联。默认安全组允许入口(ingress)和出口(egress)流量。可以将安全规则添加到默认安全组中以更改流量行为。

      创建安全组和添加规则

      每个项目都会创建一个默认的安全组,你可以向默认的安全组添加安全规则,也可以创建其它的安全组并向其添加规则。当虚拟机启动时,或随后启动时,安全组将与虚拟机相关联。

      要向安全组添加规则,你需要:

      1.从OpenStack界面,单击“项目”选项卡,选择“访问和安全”,然后单击“安全组”选项卡。

      任何现有的安全组都会在“安全组”选项卡下列出,包括默认安全组;请参见图1。

      图1:安全组
      3d219d4a-45b5-416e-9b26-72b8f816c9aa-image.png
      2.选择默认安全组,然后单击“动作”栏中的“编辑规则”。

      显示“编辑安全组规则”窗口,见图2。任何已经与安全组相关联的规则都会被列出。

      图2:编辑安全组规则
      93d70c1d-dc91-4fd6-b3fa-6769cdeb7ebc-image.png
      3.单击“添加规则”来添加新规则,见图3。

      图3:添加规则
      59ae769b-e1d4-470f-81af-0c66245e78be-image.png
      表1:添加规则字段
      07b5b67f-51c4-419e-b8e8-041426845852-image.png

      4.单击“创建安全组”以创建其它安全组。

      显示“创建安全组”窗口,见图4。

      每个新的安全组都有一个唯一的32位安全组ID,并将ACL与配置的规则关联起来。

      图4:创建安全组
      97825edd-3474-4de4-a490-bbee6a9a2b6d-image.png
      5.启动实例时,有机会关联安全组,见图5。

      在安全组列表中,选择要与实例关联的安全组名称。

      图5:启动实例的关联安全组
      42d41042-ae44-40fa-96ed-83c9562c4bbb-image.png

      6.你可以通过查看与agent.xml相关联的SgListReq和IntfReq来验证安全组是否有被关联上。

      posted in 博客
      B
      bing
    • TF+K8s部署指南丨容器的多网络接口(multi-net)功能支持

      从4.0版开始,Tungsten Fabric为使用Kubernetes编排器的容器提供网络支持。你可以使用标准容器网络接口(CNI插件)为创建的每个容器分配一个网络接口。有关Tungsten Fabric容器联网的更多信息,请参阅已发表文章。

      从5.1版本开始,Tungsten Fabric支持为容器分配多个网络接口(multi-net),使容器能够连接到多个网络,并且可以指定容器能连接到的网络。网络接口可以是物理接口,也可以是虚拟接口,并连接到Linux网络命名空间。网络命名空间是Linux内核中的网络栈。一个以上的容器可以共享同一个网络命名空间。

      Tungsten Fabric多网络支持是基于Kubernetes多网模型的。Kubernetes多网模型有特定的设计和结构,可以扩展到TF多网络等非kubernetes的模型当中。TF多网模型不需要修改Kubernetes API和Kubernetes CNI驱动。TF多网模型与Kubernetes多网模型一样,也不改变已有的集群范围网络行为。

      创建多网络接口时,请注意以下限制和注意事项:
      当pod仍在运行时,不能添加或删除sidecar 网络。
      在从Kubernetes API服务器中删除网络附件定义之前,由管理员负责删除相应的TF pod。
      除了自定义网络外,TF还创建了一个默认的cluster-wide-network。
      TF CNI插件不是一个委托插件。它不支持Kubernetes Network Custom Resource Definition De Facto Standard Version 1中提供的委托插件规范。有关更多信息,请从以下页面中查看:
      https://github.com/K8sNetworkPlumbingWG/multi-net-spec

      创建多网络接口

      按照这些步骤来创建多网络接口。

      1.创建网络对象模型

      如果集群不支持网络对象模型,你就创建一个网络对象模型。

      容器编排平台的对象模型表示网络,并将网络连接到容器。如果模型默认不支持网络对象,你可以使用扩展来表示网络。

      使用Kubernetes NetworkAttachmentDefinition CRD对象创建网络对象模型。

      apiVersion: apiextensions.k8s.io/v1beta1
      kind: CustomResourceDefinition
      metadata:
        # name must match the spec fields below, and be in the form: .
        name: network-attachment-definitions.k8s.cni.cncf.io
      spec:
        # group name to use for REST API: /apis//
        group: k8s.cni.cncf.io
        # version name to use for REST API: /apis//
        version: v1
        # either Namespaced or Cluster
        scope: Namespaced
        names:
          # plural name to be used in the URL: /apis///
          plural: network-attachment-definitions
          # singular name to be used as an alias on the CLI and for display
          singular: network-attachment-definition
          # kind is normally the CamelCased singular type. Your resource manifests use this.
          kind: NetworkAttachmentDefinition
          # shortNames allow shorter string to match your resource on the CLI
          shortNames:
          - net-attach-def
        validation:
          openAPIV3Schema:
            properties:
              spec:
                properties:
                  config:
                    type: string
      

      Kubernetes在其对象模型中使用自定义扩展来表示网络。Kubernetes的CustomResourceDefinition(CRD)功能有助于支持自定义扩展。

      注意:安装Tungsten Fabric时,会自动创建一个CRD。CRD指定的网络是不被Kubernetes识别的sidecars。附加的pod网络附件与Kubernetes API及其对象(如服务、端点、代理等)的交互没有被指定。Kubernetes不能识别这些对象与任何pod的关联。

      2.建立网络

      在集群中创建网络:

      通过API服务器创建

      apiVersion: k8s.cni.cncf.io/v1
      kind: NetworkAttachmentDefinition
      metadata:
        annotations:
          opencontrail.org/cidr: "/24"
          opencontrail.org/ip_fabric_forwarding: "false"
          opencontrail.org/ip_fabric_snat: "false"
        name: right-network
        namespace: default
      spec:
        config: '{ "cniVersion": "0.3.0", "type": "contrail-k8s-cni" }'
      

      创建一个right-network.yaml文件。

      通过映射到从Tungsten Fabric Web用户界面或从Command用户界面创建的现有网络。

      apiVersion: "k8s.cni.cncf.io/v1"
      kind: NetworkAttachmentDefinition
      metadata:
        name: extns-network
        annotations:
          "opencontrail.org/network" : '{"domain":"default-domain", "project": "k8s-extns", "name":"k8s-extns-pod-network"}'
      spec:
        config: '{
          "cniVersion": "0.3.1",
          "type": "contrail-k8s-cni"
      }'
      

      创建网络的命令:
      kubectl apply -f right-network.yaml

      3.将网络分配给pod

      可以将步骤2中创建的网络分配给 pod。每个pod也有一个默认网络分配给它。因此,每个pod都将有以下网络分配:

      默认网络(由Kubernetes分配)

      注意:Tungsten Fabric内部创建了一个名为cluster-wide-network的默认网络。这个接口是pod的默认接口。

      在步骤2中创建的网络

      使用k8s-semantics将网络分配给pod:

      方案1

      apiVersion: v1
      kind: Pod
      metadata:
        name: multiNetworkPod
        annotations:
          k8s.v1.cni.cncf.io/networks: '[
            { "name": "network-a" },
            { "name": "network-b" }
          ]'
      spec:
        containers:
        - image: busybox
          command:
            - sleep
            - "3600"
          imagePullPolicy: IfNotPresent
          name: busybox
          stdin: true
          tty: true
        restartPolicy: Always
      

      方案2

      apiVersion: v1
      kind: Pod
      metadata:
        name: ubuntu-pod-3
        annotations:
          k8s.v1.cni.cncf.io/networks: left-network,blue-network,right-network,extns/data-network
      spec:
        containers:
        - name: ubuntuapp
          image: ubuntu-upstart
          securityContext:
            capabilities:
              add:
              - NET_ADMIN
      

      (注:原文出现Contrail或Contrail networking的地方,本文都以Tungsten Fabric替代,绝大多数情况下两者功能一致。)

      原文链接:
      https://www.juniper.net/documentation/en_US/contrail20/topics/task/configuration/multi-network-interfaces-containers.html

      posted in 博客
      B
      bing
    • TF+K8s部署指南丨利用TF防火墙策略实现Kubernetes网络策略(含映射表)

      从5.0版本开始(版本更迭时间和具体内容),Tungsten Fabric支持使用防火墙安全策略框架实现Kubernetes 1.9.2网络策略。虽然Kubernetes网络策略也可以使用TF中的其它安全对象(如安全组和TF网络策略)来实现,但TF防火墙安全策略对标签的支持,有助于简化和抽象Kubernetes的工作负载。

      TF防火墙安全策略可以实现路由与安全策略的解耦,并提供多维度分段和策略可移植性,同时显著提升用户可见性和分析功能。

      另外,TF防火墙安全策略使用标签来实现不同实体之间的多维度流量分段,并具有安全功能。标签是与部署中不同实体相关联的键值对。标签可以是预先定义的,也可以是自定义的。

      Kubernetes网络策略是有关如何允许Kubernetes工作负载的组(以下简称为pod)与其它网络端点相互通信的规范。网络策略资源使用标签来选择pod,并定义规则,这些规则规定了允许哪些流量进入所选的pod。

      Kubernetes网络策略特性

      Kubernetes网络策略具有以下特性:

      网络策略是特定于pod的,适用于一个pod或一组pod。如果指定的网络策略适用于一个pod,则到pod的流量由网络策略的规则决定。
      如果网络策略没有应用到pod,那么pod就会接受来自所有来源的流量。
      网络策略可以在ingress、egress或两个方向上为pod定义流量规则。如果没有明确指定方向,默认情况下,网络策略应用于ingress方向。
      当网络策略应用于pod时,该策略必须有明确的规则来指定ingress和egress方向的允许流量的允许列表。所有不符合允许列表规则的流量都会被拒绝和丢弃。
      可以在任何pod上应用多个网络策略。必须允许符合任何一个网络策略的流量通过。
      网络策略作用于连接而不是单个数据包。例如,如果从pod A到pod B的流量被配置的策略所允许,那么从pod B到pod A的该连接的返回数据包也是被允许的,即使已制定的策略不允许从pod B发起到pod A的连接。
      Ingress策略。Ingress规则由源的身份和允许转发到pod的源的流量的protocol:port类型组成。

      源身份可以是以下类型:

      无类别域间路由(CIDR)块——如果源IP地址来自CIDR块,且流量符合protocol:port,那么流量将被转发到pod。
      Kubernetes命名空间——命名空间选择器标识命名空间,其pod可以将定义的protocol:port流量发送到ingress pod。
      Pod——Pod选择器标识网络策略所对应的命名空间中的pod,这些pod可以向ingress pod发送匹配的protocol:port流量。
      Egress策略。该策略指定了一个CIDR允许列表,允许特定protocol:port类型的流量从网络策略所针对的pod出发。

      目的身份可以是以下类型:

      CIDR块——如果目标IP地址来自CIDR块,且流量符合protocol:port,那么流量将被转发到目的地址。
      Kubernetes命名空间——命名空间选择器标识命名空间,其pod可以将定义的protocol:port流量发送到egress pod。
      Pod——Pod选择器标识网络策略所对应的命名空间中的pod,这些pod可以从egress pod接收匹配的protocol:port流量。

      将Kubernetes网络策略表示为TF防火墙安全策略

      Kubernetes和Tungsten Fabric防火墙策略在各自指定网络策略的语义上是不同的。通过TF防火墙策略高效实现Kubernetes网络策略的关键在于,在这两个实体之间映射相应的配置结构。

      这些结构的映射关系如表1所示。

      表1:Kubernetes网络策略和TF防火墙策略映射表

      20c7ec88-21b0-42fb-ac49-e6e310eab595-image.png

      注意:创建Tungsten Fabric防火墙策略结构的项目是容纳Kubernetes集群的项目。例如,如果Kubernetes集群是独立集群,则在全局范围内创建TF防火墙策略结构,如果Kubernetes集群是嵌套集群,则在项目范围内创建TF防火墙策略结构。

      解决Kubernetes网络策略标签问题

      在TF防火墙策略中,pod的表示方式与相应的Kubernetes网络策略中的表示方式完全相同。TF防火墙策略处理的是Tungsten Fabric术语中的label或tag。TF不会将标签扩展到IP地址。

      例如,在默认的命名空间中,如果网络policy-podSelector指定:role=db,那么对应的防火墙规则指定pod为(role=db && namespace=default)。不对pod IP地址或其它做翻译。

      如果同一个网络策略也有namespaceSelector为namespace=myproject,那么对应的防火墙规则将该命名空间表示为(namespace=myproject)。不做其它翻译,也不做其它规则表示"myproject"命名空间的pod。

      同样,每个CIDR由一个规则来代表。实质上,Kubernetes网络策略被1:1翻译成TF防火墙策略。只有一个额外的防火墙规则为每个Kubernetes网络策略创建。该规则的目的是实现网络策略的隐性拒绝要求,没有其它规则产生。

      TF防火墙策略命名公约

      Tungsten Fabric防火墙安全策略和规则命名如下:

      • 为Kubernetes网络策略创建的TF防火墙安全策略以如下格式命名:
      < Namespace-name >-< Network Policy Name >
      
      • 例如,命名空间"Hello"中的网络策略"world":
      Hello-world
      
      • 为Kubernetes网络策略创建的TF防火墙规则按以下格式命名:
      < Namespace-name >--< Network Policy Name >----
      

      例如:

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: world
        namespace: hello
      spec:
        podSelector:
          matchLabels:
            role: db
        policyTypes:
        - Ingress
        ingress:
        - from:
          - podSelector:
              matchLabels:
                role: frontend
      

      与该策略对应的规则被命名为:

      hello-ingress-world-0-podSelector-0-0
      

      Kubernetes网络策略的实现

      contrail-kube-manager daemon将Kubernetes和Tungsten Fabric绑定在一起。这个daemon 连接到Kubernetes集群的API服务器,并将Kubernetes事件(包括网络策略事件)覆盖到适当的TF对象中。对于Kubernetes网络策略,contrail-ke-manager执行以下操作:

      为每个Kubernetes标签(tag)创建一个TF标签(label)。
      为每个Kubernetes网络策略创建一个防火墙策略。
      创建一个应用策略集(APS)来表示该集群。在该集群中创建的所有防火墙策略都会附加到该应用策略集。
      对现有Kubernetes网络策略的修改会导致相应的防火墙策略被更新。

      网络策略配置示例

      下面的例子演示了在各种场景下网络策略和相应防火墙安全策略的创建。

      例1 - 有条件的egress和ingress流量

      以下策略指定了一个网络策略示例,其中包含了一个命名空间中所有 pod 的ingress和egress流量的特定条件。
      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: test-network-policy
        namespace: default
      spec:
        podSelector:
          matchLabels:
            role: db
        policyTypes:
        - Ingress
        - Egress
        ingress:
        - from:
          - ipBlock:
              cidr: 17x.xx.0.0/16
              except:
              - 17x.xx.1.0/24
          - namespaceSelector:
              matchLabels:
                project: myproject
          - podSelector:
              matchLabels:
                role: frontend
          ports:
          - protocol: TCP
            port: 6379
        egress:
        - to:
          - ipBlock:
              cidr: 10.0.0.0/24
          ports:
          - protocol: TCP
            port: 5978
      

      TF防火墙安全策略示例
      在Kubernetes中定义的test-network-policy会导致在Tungsten Fabric中创建以下对象。

      1、标签tag

      如果以下标签不存在,则会创建它们。在常规工作流中,这些标签必须在创建命名空间和pod时就已创建。
      65726ed3-a1d5-4107-b3d6-f42fe60e0454-image.png

      2、地址组

      创建以下地址组:
      9b480482-6aa7-4690-8914-1248a03a9dcc-image.png

      3、防火墙规则

      创建以下防火墙规则:
      f752262e-253c-4b4a-980b-572a1e83228b-image.png

      4、防火墙策略

      以下防火墙安全策略的创建规则如下:
      1a9575d5-b222-450c-990b-8904d5e01866-image.png

      例2 - 允许所有Ingress流量

      以下策略明确允许一个命名空间中的所有pod的所有流量:

      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      	kind: NetworkPolicy
      	metadata:
      	  name: allow-all-ingress
      	spec:
      	  podSelector:
      	  ingress:
      	  - {}
      

      Tungsten Fabric防火墙安全策略示例

      1、标签Tag

      如果以下标签不存在,则会创建它们。在常规工作流程中,这些标签会在创建命名空间和pod之前创建。
      52bea622-b318-482c-9170-707acbfb785a-image.png

      2、地址组 - 无

      3、防火墙规则

      创建以下防火墙规则:
      4c9227b7-9cc5-464f-babc-ecb0b62538d6-image.png

      4、防火墙策略

      创建以下防火墙策略:
      4638956a-5162-421e-acb8-65d6eb094c25-image.png

      例3 - 拒绝所有ingress流量

      下面的策略明确拒绝所有命名空间中的所有pod的ingress流量。

      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: deny-ingress
      spec:
        podSelector:
        policyTypes:
        - Ingress
      

      Tungsten Fabric防火墙安全策略示例

      1、标签tag

      如果以下标签不存在,则会创建它们。在常规工作流程中,这些标签会在创建命名空间和pod之前创建。
      0b749e8e-7294-45c3-9137-e44a4790ca9f-image.png

      2、地址组 - 无

      3、防火墙规则 - 无

      注意:任何网络策略的隐性行为都是拒绝不符合显性允许流的相应流量。但是在这个策略中,没有明确的允许规则。因此,没有为该策略创建防火墙规则。

      4、防火墙策略

      创建以下防火墙策略:
      e766721f-b4d2-4bfa-89f5-ce53eda82ec4-image.png

      例4 - 允许所有egress流量

      以下策略明确允许来自命名空间中所有pod的所有egress流量。

      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-all-egress
      spec:
        podSelector:
        egress:
        - {}
      

      Tungsten Fabric防火墙安全策略示例

      1、标签tag

      如果以下标签不存在,则会创建它们。在常规工作流程中,这些标签是在创建命名空间和pod之前创建的。
      0695eb6f-1d4b-4af7-bd07-3dceced1b41f-image.png

      2、地址组 - 无

      3、防火墙规则

      创建以下防火墙规则:
      06bff5ff-d1fa-4f78-9b5e-d4ef6a483603-image.png
      4、防火墙策略

      创建以下防火墙策略:
      331230ef-c28e-47d2-934a-973dca98d62d-image.png

      例5 - 默认拒绝所有egress流量

      以下策略明确拒绝来自命名空间中所有pod的所有egress流量。

      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: deny-all-egress
      spec:
        podSelector: {}
        policyTypes:
        - Egress
      

      Tungsten Fabric防火墙安全策略示例

      1、标签tag

      如果以下标签不存在,则会创建它们。在常规工作流程中,这些标签是在创建命名空间和 pod 之前创建的。
      de16f31d-bcf2-4490-9621-a8ddc8a37794-image.png
      2、地址组 - 无

      3、防火墙规则 - 无

      注意:任何具有egress策略类型的网络策略的隐性行为都是拒绝不匹配显性egress允许流的相应流量。在此策略中,没有明确的egress允许规则。因此,不会为该策略创建防火墙规则。

      4、防火墙策略

      创建以下防火墙策略:
      638eed66-70b6-4caa-be8e-0d6065dfe51c-image.png

      例6 - 默认拒绝所有ingress和egress流量

      以下策略明确拒绝了该命名空间中所有 pod 的所有ingress和egress流量。

      Kubernetes网络策略示例

      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: deny-all-ingress-egress
      spec:
        podSelector:
        policyTypes:
        - Ingress
        - Egress
      

      Tungsten Fabric防火墙安全策略示例

      1、标签tag

      如果以下标签不存在,则会创建它们。在常规工作流中,这些标签是在创建命名空间和pod之前创建的。
      b85b61d4-8a25-47b4-a15c-ba63be38f4e2-image.png

      2、地址组 - 无

      3、防火墙规则 - 无

      注意:任何具有ingress/egress策略类型的网络策略的隐性行为都是拒绝不匹配显性允许流的相应流量。在此策略中,没有明确的允许规则。因此,不会为该策略创建防火墙规则。

      4、防火墙策略

      创建以下防火墙策略:
      b67ef9ac-9e23-4f48-b39e-e61fb3acc7a9-image.png

      集群范围策略动作执行

      网络策略的规范和语法允许最大的灵活性和各种组合。但是,在配置网络策略时必须小心谨慎。
      接下来考虑一种情况,即创建两个网络策略:

      策略1:Pod A可以发到Pod B。
      策略2:Pod B只能从Pod C接收。

      从网络流量的角度来看,上述策略之间存在着内在的矛盾。策略1规定,允许从Pod A流向Pod B。策略2意味着不允许从Pod A流向Pod B。从网络的角度来看,Tungsten Fabric优先考虑流量行为,认为其更为关键。在网络策略内在矛盾的情况下,Tungsten Fabric将尊重流量的视角。这个概念的核心之一是,如果一个策略与流量相匹配,那么这个行为将在整个集群范围内得到尊重。

      例如,如果一个流在源端匹配一个策略,那么该流在目的端也会匹配相同的策略。因此,Tungsten Fabric管理的Kubernetes集群中的流的行为,如下图所示:

      允许从Pod A舱流向Pod B(由于策略1)。
      允许从Pod C舱流向Pod B(由于策略2)。
      任何其它流向Pod B的流量都是不允许的(由于策略2)。

      网络策略动作执行场景示例

      考虑以下网络策略动作执行的例子:

      允许所有egress流量,拒绝所有ingress流量。
      设置:命名空间NS1有两个pod,Pod A和Pod B。
      策略:在命名空间NS1上应用的网络政策规定:

      规则1:允许NS1中所有pod的所有egress流量
      规则2:拒绝NS1中所有pod的所有ingress流量

      行为:
      Pod A可以向Pod B发送流量(由于规则1)
      Pod B可以向Pod A发送流量(由于规则1)
      来自不同命名空间的PodX不能向Pod A或Pod B发送流量(由于规则2)

      允许所有ingress流量,拒绝所有egress流量。
      设置:命名空间NS1有两个pod,Pod A和Pod B。
      策略:在命名空间NS1上应用的网络政策规定:

      规则1:允许NS1中所有pod的所有igress流量
      规则2:拒绝NS1的所有pod的所有egress流量

      行为:
      Pod A可以向Pod B发送流量(由于规则1)
      Pod B可以向Pod A发送流量(由于规则1)
      Pod A和Pod B不能向任何其它命名空间的pod发送流量

      Egress CIDR规则
      设置:命名空间NS1有两个pod,Pod A和Pod B。
      策略:在命名空间NS1上应用的网络策略规定:

      策略1:允许Pod A向Pod B的CIDR发送流量。
      策略2:拒绝NS1中所有pod的所有ingress流量。

      行为:
      Pod A可以向Pod B发送流量(由于策略1)
      所有其它通往Pod A和Pod B的流量都被取消(由于策略2)


      原文链接:https://www.juniper.net/documentation/en_US/contrail20/topics/concept/k8s-network-policy.html
      (注:原文出现Contrail或Contrail networking的地方,本文都以Tungsten Fabric替代,绝大多数情况下两者功能一致。)


      posted in 博客
      B
      bing
    • TF+K8s部署指南丨K8s更新及Tungsten Fabric功能支持

      本文重点介绍Kubernetes的更新,以及Tungsten Fabric中相应支持的功能。

      Kubernetes节点的TLS引导功能

      从5.1版本开始,Tungsten Fabric支持Kubernetes节点的TLS引导(Bootstrapping)。TLS引导简化了## Kubernetes从TF集群中添加和移除节点的能力。

      基于优先权的多租户

      从5.1版本开始,Tungsten Fabric通过ResourceQuotaScopeSelector功能支持各种资源配额的优先级。

      改进的自动缩放功能

      从5.1版本开始,Tungsten Fabric可以基于负载创建和删除pod,从而支持改进的pod自动缩放功能。

      通过ip-fabric-forwarding功能实现Kubernetes Pod的可达性

      Kubernetes pod是一组单个或多个容器(如Docker容器),这些容器共享的存储,以及如何运行容器的配置选项。由于pod处于overlay网络中,所以如果没有网关或vRouter,就无法从underlay网络直接到达。

      从TF 5.0版本开始,ip-fabric-forwarding功能可以将虚拟网络作为underlay网络的一部分而创建,并消除了针对数据的封装和解封装需求。注意,ip-fabric-forwarding功能仅适用于pod网络。如果启用了ip-fabric-forwarding功能,pod-网络就会关联到ip-fabric-ipam,而不是pod-ipam,pod-ipam也是一个flat子网。

      这里的ip-fabric-forwarding功能在全局级和命名空间级中被启用和禁用。默认情况下,全局级别的ip-fabric-forwarding功能是被禁用的。要在全局级别启用该功能,必须在/etc/contrail/contrail-kubernetes.conf文件的"[KUBERNETES]"部分将"ip_fabric_forwarding"设置为"true"。要在命名空间级别启用或禁用该功能,必须在命名空间注释中分别将"ip_fabric_forwarding"设置为"true"或"false"。例如,"opencontrail.org/ip_fabric_forwarding":"true"。该功能一旦启用,就不能被禁用。

      更多信息,请参阅以下链接:
      https://github.com/tungstenfabric/tf-specs/blob/master/gateway-less-forwarding.md

      通过虚拟网络实现服务隔离

      在隔离命名空间模式下,一个命名空间中的服务无法从其它命名空间访问,除非明确定义了安全组或网络策略以允许访问。如果任何Kubernetes服务是由隔离命名空间中的pod实现的,那么这些服务只能通过Kubernetes的service-ip对同一命名空间中的pod进行访问。

      Kubernetes的service-ip虽然在一个隔离的命名空间中,但还是从集群网络中分配。因此,默认情况下,来自一个命名空间的服务可以到达另一个命名空间的服务。然而,隔离命名空间中的安全组会阻止从外部命名空间的访问,也会阻止从集群外部的访问。为了使外部命名空间能够访问,必须编辑安全组以允许访问所有命名空间,但这就违背了隔离的目的。

      从5.0版本开始,Tungsten Fabric在隔离的命名空间中实现了从外部集群的服务或入口的可达性。在隔离的命名空间中会创建两个虚拟网络,一个专用于 pod,一个专用于服务。在 pod 网络和服务网络之间创建 TF network-policy,用于 pod 和服务之间的可达性。服务使用相同的service-ipam,这是一个像pod-ipam一样的flat子网。以上也适用于默认命名空间的情况。

      TF ip-fabric-snat功能

      通过TF ip-fabric-snat功能,处于overlay中的pod可以在没有浮动IP或逻辑路由器的情况下到达互联网。该ip-fabric-snat功能使用计算节点IP创建一个源NAT来到达所需的服务,并且只适用于pod网络。当kube-manager初始化时,在global-config中为TCP保留56000到57023端口,为UDP保留57024到58047端口,以创建源NAT。

      该ip-fabric-snat功能可以在全局或命名空间级别启用或禁用。默认情况下,该功能在全局级别是禁用的。要在全局级别启用ip-fabric-snat功能,必须在/etc/contrail/contrail-kubernetes.conf文件中的"[KUBERNETES]"部分将"ip-fabric-snat"设置为"true"。要在命名空间级别启用或禁用它,必须在命名空间注释中分别将"ip_fabric_snat"设置为"true"或"false"。例如,"opencontrail.org/ip_fabric_snat":"true"。

      另外,ip_fabric_snat功能可以在任何时候被启用和禁用。要在default-pod-network中启用或禁用ip_fabric_snat功能,必须使用默认命名空间。如果启用了ip_fabric_forwarding,则会忽略ip_fabric_snat。

      更多信息,请参阅以下链接:
      https://github.com/tungstenfabric/tf-specs/blob/master/distributed-snat.md

      第三方Ingress控制器

      在Tungsten Fabric中可以有多个ingress控制器(ingress controller)共存。如果Kubernetes ingress资源的注释中没有"kubernetes.io/ingress.class"或者是"opencontrail",kube-manager就会创建一个HAProxy负载均衡器。否则会被忽略,由各自的ingress控制器处理ingress资源。由于Tungsten Fabric确保了pod和服务之间的可达性,因此任何ingress控制器都可以直接或通过服务到达端点或pod。

      自定义网络支持Ingress资源

      Tungsten Fabric支持在命名空间级别为pod定制网络。从5.0版本开始,Tungsten Fabric对于ingress资源也支持自定义网络。

      Kubernetes探针和Kubernetes服务节点端口

      Kubelet需要对pod的可达性进行存活和就绪检查。Tungsten Fabric网络策略创建在IP Fabric网络和pod网络之间,以提供节点和pod之间的可达性。每当创建pod网络时,网络策略就会被附加到pod网络上,以提供节点和pod之间的可达性。所以,节点中的任何进程都可以到达pod。
      Kubernetes服务Node-Port是基于节点与pod的可达性。由于Tungsten Fabric通过网络策略提供了节点和pod之间的连接,所以支持Node Port。

      Kubernetes网络策略支持

      Tungsten Fabric支持以下Kubernetes 1.12版网络策略功能。

      • 网络策略的egress支持——每个 NetworkPolicy包括一个policyTypes列表(包括Ingress、Egress,或两者兼有)。policyTypes字段表示给定策略是否适用于所选pod的ingress流量,是否适用于所选pod的egress流量,或者两者都适用。从5.1版本开始,Tungsten Fabric支持podSelector&namespaceSelector egress规范。从5.0版本开始,Tungsten Fabric还支持podSelector、namespaceSelector和egress CIDR规范。

      • 无类别域间路由(CIDR)选择器支持egress和ingress网络策略。

      • Contrail-ansible-deployer提供——Contrail-ansible-deployer更新以支持Kubernetes 1.12。

      Tungsten Fabric支持Kubernetes 1.9.2版本,并能够在TF中使用防火墙安全策略框架实现Kubernetes网络策略。虽然Kubernetes网络策略可以使用TF中的其它安全对象(如安全组和TF网络策略)来实现,但TF防火墙安全策略对标签的支持,有助于工作负载的简化和抽象。


      原文链接:
      https://www.juniper.net/documentation/en_US/contrail20/topics/concept/k8s-ip-fabric.html
      (注:原文出现Contrail或Contrail networking的地方,本文都以Tungsten Fabric替代,绝大多数情况下两者功能一致。)


      posted in 博客
      B
      bing
    • 配置SDN网关:关于VRF、本地路由及inet-vpn路由

      上次谈到SDN网关及其在Tungsten Fabric集群中的作用,简单地说,SDN网关是Tungsten Fabric和网络其它部分之间的“胶水”。

      它通过终结源自计算节点的overlay隧道来实现这一功能。一旦隧道在SDN网关上被终结,那么流量就可以进一步去往任何目的地。在这个环节上,可以使用任何解决方案/技术:MPLS、IP等等。

      在这里,我们将专注于使用MPLS传输的网络,这是一个“经典”的MPLS骨干网。这意味着来自计算节点上运行的虚拟机的流量通过MPLSoUDP隧道(或MPLSoGRE、VXLAN)到达SDN网关。在那里,正如刚才所说,MPLSoUDP隧道被终止,“原始流量”(由虚拟机发起的流量)通过众所周知的MPLS传输(vpn服务标签+rsvp/ldp传输标签),跨越网络核心,被进一步发送出去。

      换句话说,流量来自MPLSoUDP隧道内的计算节点,并通过熟悉的MPLSoMPLS隧道发送到骨干网。
      毕竟,Tungsten Fabric的工作原理就像一个VPN!虚拟网络是分配了路由目标的VRF。控制节点将MPLS标签(服务标签)分配给路由(例如通向虚拟机的路由)。底层传输是IP(或者更好的是UDP),因为IP Fabric(DC中的底层元素)只支持IP而非MPLS(在IP Fabric中没有rsvp/ldp)。

      换句话说,把TF - SDN网关的交互看作是标准的PE-PE交互,它们之间有IP传输。

      配置了VRF,就能控制路由通告吗?

      现在,我们毕竟是在VPN中……另一个问题开始出现了。“到底要不要用VRF?”换句话说,我们到底要不要在SDN网关上配置VRF?

      这里有两种可能的模式:
      dfb0c26f-0dfd-4f48-baa4-a12586571915-image.png
      第一种场景下,我们在SDN网关上配置了VRF。在这种情况下,SDN GW可以被看作是一个纯PE。选择这种方案可能有几个原因:例如,VRF允许路由汇总(不向核心发送VM /32路由,而只发送聚合路由),或者SDN GW使用PE-CE协议与另一个设备“对话”。

      相反,第二种场景是一种Inter-AS的情况,SDN GW作为ASBR,通过在MPLSoUDP和MPLSoMPLS隧道之间切换来转发流量。第二种场景可能比较简单,因为我不需要配置VRF和所有相关对象(例如策略)。

      本文将重点介绍第一种场景。具体来说,我们要看看在这样的场景下如何管理路由通告。为什么这件事值得一说呢?

      通常情况下,当涉及到VRF的时候,我们往往认为可以通过VRF导入/导出策略来控制路由通告。无论如何,这并不完全正确。

      请考虑以下几点:
      a054bd6a-7c63-46a1-b279-93c517255559-image.png
      我们的SDN网关有一个配置了路由目标X的VRF,该路由目标与Tungsten Fabric虚拟网络上配置的路由目标一致。在该虚拟网络上,有一个虚拟机在运行。通向虚拟机的/32路由被导入到VRF中。这是一个来自TF的inet-vpn,由SDN GW导入到VRF中。SDN网关和计算节点之间的数据平面是MPLSoUDP。然后,这条相同的路由通过iBGP(通常是通过路由反射器route reflector)以inet-vpn nlri的形式向核心重新通告。这也是最早来自TF的路由。这里的数据平面是MPLSoMPLS。

      SDN网关上的VRF也有一条本地0/0静态路由。这个路由是通向TF的通告,也就是说SDN网关要把它翻译成inet-vpn路由。SDN网关还与另一个路由器传递OSPF。在这种情况下,另一个路由器可以看作是CE,而OSPF可以看作是PE-CE协议。同样的本地静态0/0也是以OSPF路由的方式向CE发布通告。
      正如你所看到的,这个场景几乎什么都有:来自TF的VPN路由,本地路由导出到TF,VPN路由向远程PE发布通告。
      正如已经预料到的那样,VRF导入/导出策略不足以控制一切。这是因为我们有inet-vpn、静态、PE-CE路由,而SDN GW必须通告inet路由,并重新通告inet-vpn路由(从TF到RR)。

      都有哪些策略?分别控制什么路由?

      为了更好地理解如何控制路由通告,我们需要看一些Tungsten Fabric的“细节”。

      首先要回答的问题是:VRF导入/导出策略的范围是什么?

      VRF导入策略是用来决定哪些inet-vpn路由必须导入到VRF中。这意味着它控制了哪些来自于TF或远程PE的路由,将被复制到VRF中。

      另一方面,导出策略控制哪些路由必须从VRF向PE(或RR)导出。

      显然,VRF导出策略做了一切:它查看VRF内的路由,并决定接受什么(并且作为inet-vpn路由发送给PE/RR),以及拒绝什么。不过,这并不完全正确。VRF导出策略对本地静态定义的路由和PE-CE协议的路由有控制能力。这意味着VRF导出策略可以用来导出0/0静态路由或从CE学习的路由(在这种情况下是通过ospf……但也可以是isis、rip、bgp等)。然而,该策略无法控制已经是inet-vpn路由的路由:这里是指TF路由。

      这些路由首先以inet-vpn路由的形式从Tungsten Fabric来,并存储到bgp.l3vpn.0中。然后,根据VRF导入策略,将该路由“复制”到VRF中。VRF是该路由的二级表,路由只从主表(bgp.l3vpn.0)导出。

      我们来看一下VM路由。这条路由最初由Tungsten Fabric以inet-vpn路由的形式向SDN网关发布通告。SDN网关根据VRF导入策略将该路由导入到VRF中。现在,VRF导出策略告诉阻止该路由向远程PE发布通过。但是,该路由还是向远程PE做了通告。这是因为该路由已经是inet-vpn的路由,它不是本地静态路由,也不是通过PE-CE协议学习的路由,因此VRF导出策略,如前所述,对其没有任何作用。

      这是一个很小、但很基础的细节!了解VRF策略的范围,以及如何处理属于不同家族的路由(inet或inet-vpn)是至关重要的。

      如何控制来自TF的路由?

      然而,仍有一个悬而未决的问题:如何控制来自TF的路由向RR/PE发布通告的行为?由于VRF导出策略无法控制这些路由,我们需要在管理inet-vpn路由的层面采取行动:SDN网关和PE/RR之间的BGP会话。在该会话上,我们可以使用导出策略来阻止VM路由向RR发布广告。
      0943ffcf-038f-435e-b9f9-17fcaa20f114-image.png
      其实这就是路由汇总的实现方式!想象一下,多个虚拟机连接到一个虚拟网络。假设你有IP为192.168.101.11/32的VM1,IP为192.168.101.12/32的VM2,以此类推。你可能希望只向RR(192.168.101.0/24)发送一个集合。如何实现这个目标呢?

      首先,你在VRF内部配置一个聚合路由,并通过VRF导出策略发布通告(这是一条以VRF为主表的路由,所以VRF-export策略对它有控制权)。接下来,我们对RR应用一个导出策略。这个策略可能很简单:它根据路由目标匹配inet-vpn /32路由,并拒绝它们。

      其实,这并不是唯一的选择。我们还可以在SDN网关和Tungsten Fabric之间的会话中使用一个导入策略。正如我们所知道的,就是会话所携带的inet-vpn路由。这里的想法是匹配那些/32路由,接受它们,并设置众所周知的community属性为no-advertise。这样一来,路由将被导入到VRF中,但不会导出到RR。
      765a656f-d957-4c7a-ae23-3b2b2cdc8b35-image.png
      还有一个比较有趣的用例。假设一个虚拟网络被分配了路由目标X,在SDN网关上,我们配置了一个VRF,以便从Tungsten Fabric导入路由目标X。那个路由目标只具有本地意义,在骨干内部是完全不知道的。为了将这些路由与现有的VPN“集成”,必须使用另一个路由目标,比如说路由目标Y。这就需要一个所谓的路由目标转换。如何实现呢?答案应该很简单了!来自TF的路由是inet-vpn的,所以不能依靠VRF导出/导入策略。我们需要根据应用于会话的导出策略对RR(或远程PE)采取行动。在那里,将 TF 路由与路由目标 X 匹配,接受它们,并将community“设置”到路由目标 Y(这里“community设置”的意思是“删除所有现有的community并添加指定的community”)。
      c2032c2e-dfb7-4107-a4b2-610b51e582ba-image.png
      一旦你知道哪些策略可以控制哪些路由,就没那么难了,对吧?

      现在,你遇到的任何用例都应该没什么秘密了(我们知道总有一些奇怪的特例或非常好的请求)。设想一下:我们配置了VRF导出策略,这样就可以通告/导出在VRF中定义的静态路由。该路由将被通告到所有的远程PE/RR,更一般的情况是,通告到所有的inet-vpn对等点上。从我们的SDN网关来看,就是将该静态路由同时向TF和远程PE/RR做通告。假设你只想把该路由通告给TF。很简单!配置对RR的导出策略,使其匹配“静态路由A来自VRF XXX”并拒绝它!

      就是这样,利用很少的“模块”你就可以建立任何你想要的东西!


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https://iosonounrouter.wordpress.com/2020/09/08/1279/
      (注:原文为Contrail,在本系列文章中,Tungsten Fabric的功能与Contrail一致)


      posted in 博客
      B
      bing
    • 如何设置TF SDN网关,并与Tungsten Fabric协同工作

      Tungsten Fabric并不是“vanilla”(意为完美的)Openstack与OVS。

      在Neutron/OVS中,虚拟机通过所谓的供应商网络(Provider Networks)离开数据中心。它们是在数据中心交换结构上移动的VLAN网络,以便连接到网络的其它部分。这意味着要在交换结构上配置和管理所有这些VLAN。

      Tungsten Fabric的方法是不同的,它有一个单一的VLAN:TF控制+数据网络。在这个VLAN里面,Tungsten Fabric会建立隧道,允许compute-to-compute的通信,并将虚拟机的流量带到数据中心之外。

      当流量要离开数据中心时,必须经过一个作为SDN网关的设备。SDN网关并不是什么新概念,数据中心通常都会有一个数据中心的网关,类似于企业有一个WAN网关来连接分支机构/办公室和互联网。

      这里的区别在于SDN网关与SDN控制器集成在一起。在标准的Neutron/OVS环境中,数据中心网关对OpenStack是不可见的;它只是接收属于vlan的流量。而SDN网关则与Tungsten Fabric交互,参与到控制平面流量交换(通过BGP协议),以及数据平面(通过隧道)。

      接下来,我们一起试着理解上面提到的这些方面。

      我们以这个简单的拓扑结构作为参考。
      8c1901ce-3f18-486b-8944-0b0c72e75cee-image.png
      一个MX设备作为SDN网关,然后我们还有Tungsten Fabric云。接下来我们专注于两个元素:控制节点和计算节点(虚拟机就在那里运行)。

      虚拟机连接到一个名为INGRESS的虚拟网络,INGRESS也有一个路由目标分配给它。
      ac06538f-fa79-4e78-966e-5695c57523b3-image.png
      这是理解Tungsten Fabric如何运作的关键。正如我们将要看到的那样,TF只是重新使用了SDN这个众所周知的概念,但却将它们带入了一个新时代。

      我们将要看到的是与众所周知的3层VPN非常相似的东西:

      SDN网关就像一个支持VRF的PE
      计算节点也是支持VRF的PE(请记住,从TF的角度来看,虚拟网络不过是vRouter上的一个vrf)
      控制节点就像一个路由反射器
      虚拟机就像CE一样,使用某个协议(静态或BGP)作为PE-CE协议(与vRouter交换路由)

      这些概念在后面都会进一步说明。

      让我们从SDN网关——TF Control对话开始。该对话是用于控制平面的,这里使用的是BGP。路由在SDN网关和TF之间进行交换。与3层VPN完全一样,路由目标被用来将路由放入VRF当中。这意味着从SDN GW向特定的虚拟网络(这是一个VRF,并被分配了一个路由目标,正如我们之前看到的那样)发布通告路由,反之亦然。

      这个BGP会话可能是内部的,也可能是外部的;在这种情况下,我们创建一个eBGP会话,因为TF和SDN网关属于不同的AS。

      此外,BGP端点不属于同一个LAN,所以会话将是多跳的。

      首先,要验证我们对SDN网关的可到达性。

      在我们的设置中,我们有两个SDN网关,所以有两个对话。我们将只关注其中一个SDN GW,第二个SDN GW的情况是相同的。

      Tungsten Fabric控制节点必须在TF控制+数据网络上有一个接口(必须在交换结构上配置)。

      1 [root@cctrl ~]# ifconfig eth1
      2 eth1: flags=4163  mtu 9000
      3         inet 192.168.200.10  netmask 255.255.255.0  broadcast 192.168.200.255
      4         inet6 fe80::200:ff:fe42:11  prefixlen 64  scopeid 0x20
      5         ether 00:00:00:42:00:11  txqueuelen 1000  (Ethernet)
      6         RX packets 18811623  bytes 28524979120 (26.5 GiB)
      7         RX errors 0  dropped 0  overruns 0  frame 0
      8         TX packets 16157459  bytes 1514455749 (1.4 GiB)
      9         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      

      控制节点必须有一条通往SDN GW的路由:

      1 [root@cctrl ~]# ip route
      2 ...
      3 192.168.255.101 via 192.168.200.1 dev eth1
      4 192.168.255.102 via 192.168.200.1 dev eth1
      

      并且网络可达:

       1 [root@cctrl ~]# ping -c 3 192.168.255.101
       2 PING 192.168.255.101 (192.168.255.101) 56(84) bytes of data.
       3 64 bytes from 192.168.255.101: icmp_seq=1 ttl=61 time=23.7 ms
       4 64 bytes from 192.168.255.101: icmp_seq=2 ttl=61 time=8.45 ms
       5 64 bytes from 192.168.255.101: icmp_seq=3 ttl=61 time=10.6 ms
       6 --- 192.168.255.101 ping statistics ---
       7 3 packets transmitted, 3 received, 0% packet loss, time 2001ms
       8 rtt min/avg/max/mdev = 8.457/14.292/23.769/6.761 ms
       9 
      10 [root@cctrl ~]# ping -c 3 192.168.255.102
      11 PING 192.168.255.102 (192.168.255.102) 56(84) bytes of data.
      12 64 bytes from 192.168.255.102: icmp_seq=1 ttl=62 time=1.88 ms
      13 64 bytes from 192.168.255.102: icmp_seq=2 ttl=62 time=9.62 ms
      14 64 bytes from 192.168.255.102: icmp_seq=3 ttl=62 time=9.34 ms
      15 --- 192.168.255.102 ping statistics ---
      16 3 packets transmitted, 3 received, 0% packet loss, time 2002ms
      17 rtt min/avg/max/mdev = 1.884/6.952/9.626/3.587 ms
      

      从TF GUI中我们可以配置BGP路由器。在我们的场景中,有两个BGP路由器:
      efdd0317-c72c-497e-8e94-0f9e3123b717-image.png
      这是我们配置BGP路由器的方法:
      bffbeb03-df1c-4a15-82b2-db90f82ffa7e-image.png
      供应商设置为Juniper
      IP地址和路由器ID设置为BGP端点地址
      AS设置为SDN GW AS
      在TF侧选择你要在这个会话上启用的地址族

      最后,我们将其关联到控制节点(也可以将其关联到其它设备,但我们暂时忽略这一点):
      95ec1714-50c2-4388-972c-fbea949fdefc-image.png
      到这里Tungsten Fabric节点这一边就可以了。

      接下来是SDN网关。

      我们先配置BGP会话:

      类型为外部(external)
      会话为多跳(multihop)
      本地地址为我们从TF控制节点到达的地址(这个地址是在此节点的环回上配置的)
      启用的amilies为inet-vpn-unicast和route-target。
      对等AS为TF AS
      在发布通告路由时,会删除私有AS
      邻居为TF Control
      启用多路径(用于负载均衡)
      导出策略适用于vpn路由

      在这里,导出策略是相当重要的:

      1 tim@mx10003-4-ES-2# show policy-options policy-statement BGP-Contrail-Control-EXP
      2 term INET-VPN {
      3     from family inet-vpn;
      4     then {
      5         community add COM-ENCAP-UDP;
      6     }
      7 }
      8 then reject;
      

      该策略只是简单地告诉Junos为任何向Tungsten Fabric通告的vpn路由添加一个community。
      我们来看看这个community:

      1 tim@mx10003-4-ES-2# show policy-options community COM-ENCAP-UDP
      2 members 0x030c:64520:13;
      

      这里的community并不是随机的。我们来看64520:这是TF AS,但这不是最重要的。真正重要的是“0x030c”和“13”,它表示“这条路由将使用MPLSoUDP封装”。MPLSoUDP是Tungsten Fabric支持的一种overlay技术。L3的overlay可以使用MPLSoUDP或MPLSoGRE,而L2的overlay使用VXLAN。我们在这里可以使用MPLSoGRE,但更推荐MPLSoUDP,因为它提供了更好的负载均衡(UDP源端口可以设置为内部数据包的哈希)。此外,MPLSoUDP默认用于compute-to-compute的通信。综上所述,该community让Tungsten Fabric明白必须使用MPLSoUDP来到达这些地址。

      以上说的都是控制平面。

      我们还有数据平面。现在应该很清楚了:我们在控制平面上使用BGP,在数据平面上使用MPLSoUDP。简单来说,SDN网关通过MP-eBGP从Tungsten Fabric控制节点学习一个VM IP。这个BGP路由包含了虚拟机所在的计算节点的信息。该计算节点是MPLSoUDP隧道的端点。数据平面将使用该隧道在SDN网关和VM之间发送数据包。

      这些MPLSoUDP是动态的,这意味着只有在需要时才会被创建出来。例如,当SDN网关收到一条到达特定计算节点上托管的虚拟机的路由,就会创建一条隧道。后面我们会更好地理解这一点。

      即使是动态的,我们仍然需要告诉SDN网关做好创建这些动态隧道的准备:

      1 tim@mx10003-4-ES-2# show routing-options dynamic-tunnels
      2 ComputeNode {
      3     source-address 192.168.255.102;
      4     udp;
      5     destination-networks {
      6         192.168.200.0/24;
      7     }
      8 }
      

      这会告诉Junos,它可以动态地创建MPLSoUDP隧道,源头是192.168.255.102(我们知道这个地址),指向计算节点所在的控制+数据网络。通过设置整个控制+数据网络,我们也覆盖了控制节点;这可能会很方便,以确保在inet.3中有一条通往控制节点的路由,并让MX能够解析BGP路由(这正是我们与VPN工作的标准RR所拥有的)。

      现在一切所需配置都到位了。

      让我们检查一下BGP会话状态:

      1 tim@mx10003-4-ES-2> show bgp neighbor 192.168.200.10 | match State
      2   Type: External    State: Established    Flags: 
      3   Last State: OpenConfirm   Last Event: RecvKeepAlive
      

      我们找到已配置的选项:

      1 tim@mx10003-4-ES-2> show bgp neighbor 192.168.200.10 | match Options
      2   Options: 
      3   Options:
      

      协商的地址族是:

      1 tim@mx10003-4-ES-2> show bgp neighbor 192.168.200.10 | match NLRI
      2   NLRI for restart configured on peer: inet-vpn-unicast route-target
      3   NLRI advertised by peer: inet-vpn-unicast inet6-vpn-unicast route-target evpn
      4   NLRI for this session: inet-vpn-unicast route-target
      5   NLRI that restart is negotiated for: inet-vpn-unicast route-target
      6   NLRI of received end-of-rib markers: inet-vpn-unicast route-target
      7   NLRI of all end-of-rib markers sent: inet-vpn-unicast route-target
      

      Tungsten Fabric通告了更多的族(例如evpn),但只有inet-vpn-unicast和route-target(SDN GW上配置的)会用到。
      目前这两个对等点之间交换的路由涉及这些表:

      1 tim@mx10003-4-ES-2> show bgp neighbor 192.168.200.10 | match Table
      2   Table LTE-TRAFFIC.inet.0
      3   Table bgp.l3vpn.0 Bit: 20000
      4   Table bgp.rtarget.0 Bit: 10000
      

      这一点可以通过查看从该对等点接收到的路由来确认。

      1 tim@mx10003-4-ES-2> show route receive-protocol bgp 192.168.200.10
      2 
      3 inet.0: 30 destinations, 32 routes (30 active, 0 holddown, 0 hidden)
      4 
      5 inet.3: 7 destinations, 7 routes (7 active, 0 holddown, 0 hidden)
      6 
      7 LTE-TRAFFIC.inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      8   Prefix                  Nexthop              MED     Lclpref    AS path
      9 * 0.0.0.0/0               192.168.200.11                          64520 65101 I
      10 * 172.30.124.10/32        192.168.200.11       100                64520 ?
      11 * 172.30.124.11/32        192.168.200.11       100                64520 ?
      12 * 192.168.20.3/32         192.168.200.11       200                64520 ?
      13 * 192.168.20.4/32         192.168.200.11       200                64520 ?
      14 
      15 mpls.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      16 
      17 bgp.l3vpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      18   Prefix                  Nexthop              MED     Lclpref    AS path
      19   192.168.200.11:5:0.0.0.0/0
      20 *                         192.168.200.11                          64520 65101 I
      21   192.168.200.11:5:172.30.124.10/32
      22 *                         192.168.200.11       100                64520 ?
      23   192.168.200.11:5:172.30.124.11/32
      24 *                         192.168.200.11       100                64520 ?
      25   192.168.200.11:5:192.168.20.3/32
      26 *                         192.168.200.11       200                64520 ?
      27   192.168.200.11:5:192.168.20.4/32
      28 *                         192.168.200.11       200                64520 ?
      29 
      30 inet6.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
      31 
      32 LTE-TRAFFIC.inet6.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
      33 
      34 bgp.rtarget.0: 50 destinations, 50 routes (37 active, 0 holddown, 13 hidden)
      35   Prefix                  Nexthop              MED     Lclpref    AS path
      36   64520:64520:101/96
      37 *                         192.168.200.10                          64520 I
      38   64520:64520:102/96
      39 *                         192.168.200.10                          64520 I
      40   64520:64520:6100/96
      41 *                         192.168.200.10                          64520 I
      42   64520:64520:6200/96
      43 *                         192.168.200.10                          64520 I
      44 ...
      

      其中涉及到的一个表,就是众所周知的bgp.l3vpn.0。这再次告诉我们,Tungsten Fabric和SDN网关几乎是自由集成的,不需要额外的学习成本,因为我们使用的是非常熟知的概念!

      让我们看看一条具体的路由(VM地址):

      1 tim@mx10003-4-ES-2> show route receive-protocol bgp 192.168.200.10 172.30.124.10/32 extensive table bgp.l3vpn.0
      2 
      3 bgp.l3vpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      4 * 192.168.200.11:5:172.30.124.10/32 (1 entry, 1 announced)
      5      Import Accepted
      6      Route Distinguisher: 192.168.200.11:5
      7      VPN Label: 34
      8      Nexthop: 192.168.200.11
      9      MED: 100
      10      AS path: 64520 ?
      11      Communities: target:64520:102 target:64520:8000004 encapsulation:unknown(0x2) encapsulation:mpls-in-udp(0xd) mac-mobility:0x0 (sequence 1) unknown type 0x8071:0xfc08:0x7
      

      看下community,有两个特别重要的细节:MPLSoUDP封装和target:64520:102。这就是我们在虚拟网络里配置的Tungsten Fabric的路由目标。

      另外,我们看到VPN标签。这就是MPLSoUDP数据包的内部标签。

      路由的区分符是192.168.200.11:5,其中192.168.200.11是承载虚拟机的计算节点的控制+数据地址,配置的IP为172.30.124.10。通过查看nexthop字段(192.168.200.11)也可以证实这一点。

      这就清楚地表明了我们之前所说的:我们在控制平面上通过BGP在控制节点和SDN网关之间交换路由,在数据平面上通过SDN GW和计算节点之间的MPLSoUDP隧道发送/接收实际数据帧。

      之前我们看到,在SDN GW上涉及到一个VRF。我们来具体看一下:

      1 tim@mx10003-4-ES-2# show routing-instances LTE-TRAFFIC | match vrf
      2 instance-type vrf;
      3 vrf-import LTE-IMPORT;
      4 vrf-export LTE-EXPORT;
      5 vrf-table-label;
      

      我们来检查导入策略:

      1 tim@mx10003-4-ES-2# show policy-options policy-statement LTE-IMPORT
      2 term 1 {
      3     from {
      4         protocol bgp;
      5         community 64520:102;
      6     }
      7     then accept;
      8 } 
      9 term 2 {
      10     then reject;
      11 }
      12 tim@mx10003-4-ES-2# show policy-options community 64520:102
      13 members target:64520:102;
      

      VRF被配置为INGRESS虚拟网络的导入路由。这就是我们把虚拟网络带到虚拟机之外的方法! 而这也不是什么新鲜事:这是标准的L3VPN!从SDN GW的角度来看,这只是一个PE从RR中获取路由来学习如何到达其它PE。对于那些PE是vRouters的实施,它不知道也不关心。一旦把路由从Tungsten Fabric导入到 vrf 中,剩下的事情就顺理成章了:MPLS建立隧道到远端PE,0/0缺省路由表到GRT等等……

      我们来看看VRF里面虚拟机路由的细节:

      1 tim@mx10003-4-ES-2> show route table LTE-TRAFFIC.inet.0 172.30.124.10/32 extensive
      2 
      3 LTE-TRAFFIC.inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      4 172.30.124.10/32 (1 entry, 1 announced)
      5 TSI:
      6 KRT in-kernel 172.30.124.10/32 -> {indirect(1048577)}
      7         *BGP    Preference: 170/-101
      8                 Route Distinguisher: 192.168.200.11:5
      9                 Source: 192.168.200.10
      10                 Next hop type: Tunnel Composite, Next hop index: 639
      11                 Import Accepted
      12                 VPN Label: 34
      13                 Localpref: 100
      14                 Router ID: 192.168.200.10
      15                 Primary Routing Table bgp.l3vpn.0
      16                 Indirect next hops: 1
      17                         Protocol next hop: 192.168.200.11
      18                         Label operation: Push 34
      19                         Indirect path forwarding next hops: 1
      20                                 Next hop type: Tunnel Composite
      21                                 Next hop:
      22                                 192.168.200.11/32 Originating RIB: inet.3
      23                                   Node path count: 1
      24                                   Forwarding nexthops: 1
      25                                         Next hop type: Tunnel Composite
      26                                         Tunnel type: UDP, nhid: 0, Reference-count: 4, tunnel id: 0
      27                                         Destination address: 192.168.200.11, Source address: 192.168.255.102
      

      这里有很多有趣的东西!我们很容易找到MPLS标签。下一跳的类型是隧道(MPLSoUDP隧道),我们可以看到这个隧道的端点。源地址是192.168.255.102(我们在动态隧道下配置的),目的地址是192.168.200.11(虚拟机所在的计算节点)。这个路由在inet.3中,所以同样地,正如我们已经知道的,通过查看inet.3来解析bgp路由。

      然而,需要注意的是:这条路由源地址是192.168.200.10(TF Controller、RR、控制平面、BGP),而下一跳是192.168.200.11(计算节点、vRouter、数据平面、MPLSoUDP)。

      我们还将SDN GW的路由通告到Tungsten Fabric:

      1 tim@mx10003-4-ES-2> show route advertising-protocol bgp 192.168.200.10
      2 
      3 LTE-TRAFFIC.inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      4   Prefix                  Nexthop              MED     Lclpref    AS path
      5 * 10.10.0.0/24            Self                 0                  I
      6 * 10.20.0.0/24            Self                 0                  I
      7 * 170.170.170.1/32        Self                 0                  I
      8 * 192.168.254.38/31       Self                 2                  I
      9 
      10 bgp.l3vpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      11   Prefix                  Nexthop              MED     Lclpref    AS path
      12   192.168.255.102:100:10.10.0.0/24
      13 *                         Self                 0                  I
      14   192.168.255.102:100:10.20.0.0/24
      15 *                         Self                 0                  I
      16   192.168.255.102:100:170.170.170.1/32
      17 *                         Self                 0                  I
      18   192.168.255.102:100:192.168.254.38/31
      19 *                         Self                 2                  I
      20 
      21 bgp.rtarget.0: 50 destinations, 50 routes (37 active, 0 holddown, 13 hidden)
      22   Prefix                  Nexthop              MED     Lclpref    AS path
      23   3269:64520:102/96
      24 *                         Self                                    I
      

      请记住这些路由。我们会发现它们都在Tungsten Fabric虚拟网络路由表里面:
      80b8b4e4-afc0-4808-928e-3577ded5c489-image.png
      让我们仔细看看其中一条路由:

      1 tim@mx10003-4-ES-2> show route advertising-protocol bgp 192.168.200.10 10.10.0.0/24 table bgp.l3vpn.0 extensive
      2 
      3 bgp.l3vpn.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      4 * 192.168.255.102:100:10.10.0.0/24 (1 entry, 1 announced)
      5  BGP group Contrail-Control type External
      6      Route Distinguisher: 192.168.255.102:100
      7      VPN Label: 16
      8      Nexthop: Self
      9      Flags: Nexthop Change
      10      MED: 0
      11      AS path: [3269] I
      12      Communities: target:64520:102 rte-type:0.0.0.0:5:1 encapsulation:mpls-in-udp(0xd)
      

      我们设置了两个community:Tungsten Fabric虚拟网络上匹配的路由目标和MPLSoUDP封装。当然,我们还通告了MPLS标签。别忘了,MPLS标签在L3VPN上的意义是一样的,没有什么新鲜的!

      这个路由是通过OSPF在VRF中学习的:

      1 tim@mx10003-4-ES-2> show route table LTE-TRAFFIC.inet.0 10.10.0.0/24
      2 
      3 LTE-TRAFFIC.inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
      4 + = Active Route, - = Last Active, * = Both
      5 
      6 10.10.0.0/24       *[OSPF/171] 2d 19:22:13, metric 0, tag 0
      7                     >  to 192.168.254.40 via ae3.2
      

      OSPF是SDN网关与网络中另一设备之间的PE-CE协议(本文不做探讨)。

      我们的vrf导出策略可以匹配OSPF路由,并添加所需的路由目标:

      1 tim@mx10003-4-ES-2# show policy-options policy-statement LTE-EXPORT
      2 term 1 {
      3     from protocol ospf;
      4     then {
      5         community add 64520:102;
      6         accept;
      7     }
      8 }
      9 then reject;
      

      Tungsten Fabric虚拟网络默认会导入带有自己路由目标标签的路由。

      我们也可以选择配置虚拟网络来导出/导入多个路由目标,就像在Junos设备上通过vrf-import/export策略实现一样。

      以上涵盖了基本的Tungsten Fabric - SDN GW通信。

      我认为优势是显而易见的。比如,在交换结构上只有一个vlan,即TF控制+数据网络。此外,通过一个单一的BGP会话,承载多个虚拟网络的路由。数据中心之外的设备不再需要与每一个虚拟网络对等,因为全部的所需信息都会通过这个单一的MP-eBGP会话进行传递!


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https:// iosonounrouter.wordpress.com/2019/04/11/setting-up-a-contrail-sdn-gateway-and-how-it-works-with-contrail/
      (注:原文为Contrail,在本系列文章中,Tungsten Fabric的功能与Contrail一致)


      posted in 博客
      B
      bing
    • 四种模式、七大元素:玩转TF+K8s CNI集成部署

      Tungsten Fabric从4.0版本起,就开始支持用于将Kubernetes自动化平台与TF的集成的容器网络接口(CNI)。本文就来介绍基于CNI的TF+K8s集成部署。

      什么是Kubernetes

      Kubernetes也称为K8s,是一个开放源代码平台,用于跨主机集群自动执行应用程序容器的部署、扩展和运行,从而提供以容器为中心的基础架构。它提供了跨公共云和私有云的可移植平台。Kubernetes支持应用程序的部署、扩展和自动修复。

      Kubernetes支持可用于大多数基本网络连接的容器网络接口(CNI)的可插入框架,包括容器Pod寻址、网络隔离、基于策略的安全性、网关、SNAT、负载均衡器,以及Kubernetes编排的服务链功能。Tungsten Fabric自4.0版本起即可支持Kubernetes的CNI功能。

      Kubernetes提供了一个扁平的网络模型,其中所有容器Pod都可以彼此通信。添加了网络策略功能,以提供Pod之间的安全性。与Kubernetes集成的Tungsten Fabric则添加了其它网络功能,包括多租户、网络隔离、具有网络策略的微分段和负载均衡等。

      表1列出了Kubernetes概念与Tungsten Fabric资源之间的映射。

      表1:Kubernetes到Tungsten Fabric的映射
      b4449080-97eb-4ab3-a6c4-732513e08bb6-image.png

      什么是Kubernetes Pod?

      Kubernetes pod是一组单个或多个容器(例如Docker容器),这些容器共享的存储和如何运行容器的配置选项。Pod始终位于同一位置,在同一时间编排,并在共享的上下文中运行。Pod的共享上下文是一组Linux命名空间、cgroup和其它隔离方面。在Pod的相关环境中,每个应用程序可能会有进一步的子隔离。

      你可以在以下位置找到有关Kubernetes的更多信息:
      http://kubernetes.io/docs/whatisk8s/

      TF+K8s的四种配置模式

      可以在Kubernetes中以几种不同的模式配置Tungsten Fabric,本节介绍的几种配置模式包括:

      • 默认模式
      • 命名空间隔离模式
      • 自定义隔离模式
      • 嵌套模式

      默认模式

      在Kubernetes中,所有Pod可以与所有其它Pod通信,而无需使用网络地址转换(NAT)。这也是TF Kubernetes集群的默认模式。在默认模式下,Tungsten Fabric创建一个由所有命名空间共享的虚拟网络,从该命名空间分配服务和Pod IP地址。

      Kubernetes集群中产生的所有命名空间中的所有Pod都可以相互通信。所有Pod的IP地址都是从TF Kubernetes管理器中配置的Pod子网分配的。

      注意:
      在kube-system命名空间中生成的系统Pod不在Kubernetes集群中运行;它们以underlay的方式运行,并且这些pod的网络也不是由TF处理的。

      命名空间隔离模式

      除了Kubernetes授权使用的默认网络模型外,Tungsten Fabric还支持其他自定义网络模型,这些模型为Kubernetes集群的用户提供了许多丰富的Tungsten Fabric功能。其中一种这样的功能,就是Kubernetes命名空间的网络隔离。

      对于命名空间隔离模式,集群管理员可以配置命名空间注释以打开隔离。在该模式下,除非明确定义了安全组或网络策略以允许访问,否则无法从其它命名空间访问该命名空间中的服务。

      可以通过注释Kubernetes命名空间元数据,来将Kubernetes命名空间配置为隔离的:

      opencontrail.org/isolation : true

      命名空间隔离为Pod提供了网络隔离,因为隔离的命名空间中的Pod无法访问集群中其它命名空间中的Pod。

      命名空间隔离还为Pod提供服务的隔离。如果任何Kubernetes服务是由隔离命名空间中的Pod实现的,则这些Pod仅可通过Kubernetes service-ip到达同一命名空间中的Pod。

      为了使服务仍然可以访问其它命名空间,可以通过在命名空间上标记以下注释来禁用服务隔离:

      opencontrail.org/isolation.service : false

      禁用服务隔离,可以使服务访问其它命名空间中的Pod,但是隔离的命名空间中的Pod仍然无法访问其它命名空间中的Pod。

      对于Pod和服务隔离都被标记为“已隔离”的命名空间,具有以下网络行为:

      • 在隔离的命名空间中创建的所有Pod彼此之间都具有网络可达性。
      • Kubernetes集群中其它命名空间中的pod无法到达隔离命名空间中的pod。
      • 在隔离命名空间中创建的pod可以到达非隔离命名空间中的pod。
      • 隔离命名空间中的Pod可以访问Kubernetes集群中任何命名空间中的非隔离服务。
      • 来自其它命名空间的Pod无法到达隔离命名空间中的服务。

      被标记为“已隔离”,且服务隔离被禁用、pod隔离被启用的命名空间,具有以下网络行为:

      • 在隔离的命名空间中创建的所有Pod彼此之间都具有网络可达性。
      • Kubernetes集群中其它命名空间中的pod无法到达隔离命名空间中的pod。
      • 在隔离命名空间中创建的pod可以到达其它命名空间中的pod。
      • 隔离命名空间中的Pod可以访问Kubernetes集群中任何命名空间中的非隔离服务。
      • 来自其它命名空间的Pod可以到达隔离命名空间中的服务。

      自定义隔离模式

      管理员和应用程序开发人员可以添加注释,以指定要在其中配置一个或多个Pod的虚拟网络。用于指定此自定义虚拟网络的注释为:

      "opencontrail.org/network: "

      如果在Pod规范上配置了此注释,则会在该网络中启动Pod。如果在命名空间规范中配置了注释,则将在提供的网络中启动命名空间中的所有Pod。

      注意:
      在Pod或命名空间规范中配置虚拟网络之前,必须使用Tungsten Fabric VNC API或Tungsten Fabric-UI创建虚拟网络。

      嵌套模式

      Tungsten Fabric支持在OpenStack集群内部配置Kubernetes集群。虽然这种集群的嵌套本身并不是独一无二的,但Tungsten Fabric提供了一个折叠式的控制和数据平面,在这个平面中,一个TF控制平面和一个网络栈同时管理和服务OpenStack和Kubernetes集群。通过统一的控制和数据平面,这些集群的互通和配置是无缝的,并且没有复制和重叠的现象,使其成为非常有效的选项。

      在嵌套模式下,一个OpenStack集群的虚拟机中预配置了一个Kubernetes集群。Kubernetes集群的CNI插件和TF-kubernetes管理器,直接与管理OpenStack集群的Tungsten Fabric组件交互。

      在嵌套模式部署中,所有Kubernetes特性、功能和规格都可以被支持。嵌套部署允许其与底层的OpenStack集群在同一平面上运行,从而扩展了Kubernetes的边界和局限性。

      想要了解更多的信息,请查看以下链接:
      https://www.juniper.net/documentation/en_US/contrail20/topics/task/installation/provisioning-k8s-cluster.html

      Kubernetes服务

      Kubernetes服务是一种抽象概念,它定义了逻辑上的Pod集以及用于访问Pod的策略。根据服务定义中的LabelSelector字段选择实现服务的Pod集。在Tungsten Fabric中,Kubernetes服务被实现为原生于ECMP的负载均衡器。

      TF Kubernetes集成支持以下ServiceType:

      • “clusterIP”:这是默认模式。选择此ServiceType可使服务通过集群网络访问。
      • “LoadBalancer”:将ServiceType指定为“LoadBalancer”可以从外部访问该服务。为“LoadBalancer”_Service_分配了CluserIP和ExternalIP地址。此ServiceType假定用户已使用浮动IP池配置了公共网络。

      TF Kubernetes服务集成支持TCP和UDP协议。另外,服务可以暴露多个端口,而这些端口都与targetPort不同。例如:

      kind: Service
      apiVersion: v1
      metadata:
        name: my-service
      spec:
          selector:
            app: MyApp
          ports:
            - name: http
              protocol: TCP
              port: 80
              targetPort: 9376
            - name: https
              protocol: TCP
              port: 443
              targetPort: 9377
      

      Kubernetes用户可以为LoadBalancer和clusterIP ServiceTypes指定spec.clusterIP和spec.externalIPs。

      如果ServiceType为LoadBalancer,并且用户未指定spec.externalIP,那么conutil-kube-manager将从公共池中分配一个浮动IP,并将其关联到ExternalIP地址。

      Ingress

      Kubernetes服务可以通过多种方式在外部公开或在集群外部暴露。

      有关从外部公开Kubernetes服务的所有方法的列表,请参见链接:
      https://kubernetes.io/docs/concepts/services-networking/ingress/#alternatives

      Ingress就是这样一种方法。Ingress提供7层负载均衡,而其它方法提供4层负载均衡。Tungsten Fabric支持基于http的单一服务入口、简单扇出入口,和基于命名的虚拟主机入口。

      TF K8s解决方案的七大元素

      Tungsten Fabric Kubernetes解决方案包括以下元素:

      • TF Kubernetes Manager
      • Kubernetes服务的ECMP负载均衡器
      • 用于Kubernetes Ingress的HAProxy 负载均衡器
      • Kubernetes网络策略的安全组
      • Kubernetes对安全策略的支持
      • 域名服务器(DNS)
      • 支持的Kubernetes注释

      接下来请它们一一登场。

      TF Kubernetes Manager

      TF Kubernetes的实施需要侦听Kubernetes API消息,并在Tungsten Fabric API数据库中创建相应的资源。

      在Docker容器中运行一个新的模块——conilil-kube-manager,以侦听来自Kubernetes API服务器的消息。

      Kubernetes服务的ECMP负载均衡器

      Kubernetes中的每个服务都由一个负载均衡器对象表示。Kubernetes分配的服务IP用作负载均衡器的VIP。正在侦听的服务端口上会创建侦听器。每个Pod都被添加为侦听器池的成员。Consilute-kube-manager会侦听基于服务标签或Pod标签的任何更改,并使用添加、更新或删除的Pod更新成员池列表。

      服务的负载均衡是基于ECMP的4层原生、非代理的负载均衡。instance-ip(service-ip)链接到服务中每个Pod的端口。这将在Tungsten Fabric中创建一个ECMP下一跳,并且流量直接从源pod进行负载均衡。

      用于Kubernetes Ingress的HAProxy 负载均衡器

      Kubernetes Ingress是通过Tungsten Fabric中的HAProxy负载均衡器功能实现的。只要在Kubernetes中配置了入口,contrail-kube-manager就会在contrail-controller中创建负载均衡器对象。TF服务监视器将侦听负载均衡器对象,并根据主备模式下的入口规范规则以适当的配置启动HAProxy。

      有关负载均衡器的更多信息,请参见:
      https://www.juniper.net/documentation/en_US/contrail20/topics/task/configuration/lbaas-contrail3-F5.html

      Kubernetes网络策略的安全组

      Kubernetes网络策略是有关如何允许Pod组彼此通信,以及与其它网络端点进行通信的规范。NetworkPolicy资源使用标签来选择Pod,并定义允许列表规则,该规则除了对给定命名空间的隔离策略所允许的内容外,还允许对选定Pod的访问。

      有关Kubernetes网络策略的更多信息,请参阅:
      https://kubernetes.io/docs/concepts/services-networking/networkpolicies/

      Contil-kube-manager侦听Kubernetes网络策略事件以创建、更新和删除,并将Kubernetes网络策略转换为应用于虚拟机接口(VMI)的Tungsten Fabric安全组对象。当添加和删除pod和标签时,VMI会动态更新。

      Kubernetes对安全策略的支持

      在Kubernetes环境中创建的网络策略,是通过使用Tungsten Fabric安全策略框架来实现的。Kubernetes环境中的标签(labels)在Tungsten Fabric中作为标签(tags)公开。从Tungsten Fabric 5.0版开始,你可以为Kubernetes环境定义标签。Tungsten Fabric安全策略使用这些标签来实现指定的Kubernetes策略。你可以在UI中定义标签或以JSON格式上传配置。新定义的标签可用于在TF Security中创建和实施策略。

      域名服务器(DNS)

      Kubernetes使用SkyDNS实施DNS,SkyDNS是一个小型DNS应用程序,可响应来自Pod的DNS请求以解析服务名称。SkyDNS在Kubernetes中作为pod运行。

      支持的Kubernetes注释

      当前,Tungsten Fabric支持以下Kubernetes注释:

      'opencontrail.org/network': '{"domain":"default-domain", "project": "k8s-contrail", "name":"deu"}'
      'opencontrail.org/isolation': 'true'
      'opencontrail.org/fip-pool': '{"domain": "default-domain", "project": "k8s-default", "network": "k8s-default-svc-public", "name": "default"}'
      

      有关更多详细信息,请参阅:
      https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/.

      验证Kubernetes的CNI配置

      你可以使用下面的验证步骤,来查看和验证针对Kubernetes的Tungsten Fabric容器网络接口(CNI)的配置。

      查看Pod名称和IP地址

      使用以下命令查看分配给Pod的IP地址。

      [root@device ~]# kubectl get pods --all-namespaces -o wide 
      NAMESPACE         NAME               READY     STATUS    RESTARTS   AGE       IP                         NODE
      default               client-1            1/1         Running     0               19d       10.47.25.247   k8s-minion-1-3
      default               client-2            1/1         Running     0               19d       10.47.25.246   k8s-minion-1-1
      default               client-x             1/1        Running     0               19d       10.84.21.272   k8s-minion-1-1
      

      验证Pod的可达性

      执行以下步骤,以验证各个pod是否可以相互到达。

      1.确定pod的IP地址和名称。

      [root@device ~]# kubectl get pods --all-namespaces -o wide
      NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
      example1-36xpr   1/1       Running   0          43s       10.47.25.251   b3s37
      example2-pldp1   1/1       Running   0          39s       10.47.25.250   b3s37
      

      2.从源Pod去ping目标Pod,以验证Pod是否可达。

      root@device ~]# kubectl exec -it example1-36xpr  ping 10.47.25.250
      PING 10.47.25.250 (10.47.25.250): 56 data bytes
      64 bytes from 10.47.25.250: icmp_seq=0 ttl=63 time=1.510 ms
      64 bytes from 10.47.25.250: icmp_seq=1 ttl=63 time=0.094 ms
      

      验证隔离命名空间的Pod是否为不可访问

      执行以下步骤,以验证非隔离命名空间中的pod是否无法访问隔离命名空间中的pod。

      1.确定隔离命名空间中Pod的IP地址和名称。

      [root@device ~]# kubectl get pod -n test-isolated-ns -o wide
      NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
      example3-bvqx5   1/1       Running   0          1h        10.47.25.249   b3s37
      

      2.确定非隔离命名空间中的Pod的IP地址。

      [root@device ~]# kubectl get pods
      NAME                        READY     STATUS    RESTARTS   AGE
      example1-36xpr   1/1       Running   0          15h
      example2-pldp1   1/1       Running   0          15h
      

      3.从非隔离命名空间中的Pod去ping隔离命名空间中的Pod的IP地址。

      [root@device ~]# kubectl exec -it example1-36xpr ping 10.47.25.249
              --- 10.47.255.249 ping statistics ---
       2 packets transmitted, 0 packets received, 100% packet loss
      

      验证非隔离命名空间的Pod是否为可以访问

      执行以下步骤,以验证非隔离命名空间中的Pod是否可以访问非隔离命名空间中的Pod。

      1.确定非隔离命名空间中Pod的IP地址。

      [root@device ~]# kubectl get pods -o wide
      NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
      example1-36xpr   1/1       Running   0          15h       10.47.25.251   b3s37
      example2-pldp1   1/1       Running   0          15h       10.47.25.250   b3s37
      

      2.确定隔离命名空间中的Pod的IP地址和名称。

      [root@device ~]# kubectl get pod -n test-isolated-ns -o wide
      NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
      example3-bvqx5   1/1       Running   0          1h        10.47.25.249   b3s37
      

      3.从隔离命名空间中的pod去ping非隔离命名空间中pod的IP地址。

      [root@device ~]# kubectl exec -it example3-bvqx5 -n test-isolated-ns ping 10.47.25.251
      PING 10.47.25.251 (10.47.25.251): 56 data bytes
      64 bytes from 10.47.25.251: icmp_seq=0 ttl=63 time=1.467 ms
      64 bytes from 10.47.25.251: icmp_seq=1 ttl=63 time=0.137 ms
      ^C--- 10.47.25.251 ping statistics ---
      2 packets transmitted, 2 packets received, 0% packet loss
      round-trip min/avg/max/stddev = 0.137/0.802/1.467/0.665 ms
      

      验证命名空间是否隔离

      命名空间注释用于打开Kubernetes命名空间中的隔离。在隔离的Kubernetes命名空间中,命名空间元数据使用opencontrail.org/isolation : true标注进行注释。

      使用以下命令查看命名空间上的注释。

      [root@a7s16 ~]#
      kubectl describe namespace test-isolated-ns   
      Name:       test-isolated-ns
      Labels:     
      Annotations:    opencontrail.org/isolation : true     Namespace is isolated
      Status:     Active
      

      原文链接:
      https://www.juniper.net/documentation/en_US/contrail20/topics/concept/kubernetes-cni-contrail.html
      https://www.juniper.net/documentation/en_US/contrail20/topics/task/verification/verifying-cni-k8s.html


      posted in 博客
      B
      bing
    • 三个理由告诉你,为什么在TF中必须使用MPLSoUDP

      Tungsten Fabric大量使用了overlay,它的整个体系结构基于利用overlay来提供L2/L3虚拟化,并使底层IP fabric对虚拟工作负载透明。

      Tungsten Fabric支持三种封装类型,分别是:

      1. MPLSoGRE
      2. MPLSoUDP
      3. VXLAN

      其中,MPLSoGRE 和 MPLSoUDP用于L3虚拟化,而VXLAN用于L2虚拟化。

      如果我们计划实施L2用例,那么没什么可考虑的……VXLAN就对了!

      不过,在L3用例中出现了一个问题:选择基于GRE的MPLS?还是基于UDP的MPLS?

      正如行业中常见的那样,答案可能是“取决于”某些具体情况。不过,这里的答案却十分明确——必须是MPLSoUDP!
      在理解为什么选择MPLSoUDP之前,让我们先来看看何时需要使用MPLSoGRE。

      答案同样是不言而喻的,当我们不能使用MPLSoUDP时——这可能是因为我们的SDN GW运行的软件版本不支持MPLSoUDP——我们使用MPLSoGRE。

      除了这种情况以外,建议都使用MPLSoUDP!

      为了理解为什么MPLSoUDP更好,我们需要回顾一下如何构建MPLSoUDP数据包。

      2c5d6b3e-0087-4675-8077-72a39a92a8cd-image.png

      首先将原始raw数据包添加一个mpls标签。该标签表示服务标签,并且是contrail/sdn_gw将数据包与正确的virtual_network/vrf相关联的方式。

      接下来,添加UDP (+ IP)标头。UDP标头包括源端口和目标端口。源端口是对内部数据包执行哈希操作的结果。结果是,该字段将会出现很大变化。源端口带来了巨大的熵!

      而这种熵就是我们选择MPLSoUDP的原因!

      使用MPLSoUDP可以带来不同级别的优势。

      第一个好处是在SDN GW上体现的。假设你在SDN GW和计算节点之间有一条MPLSoUDP隧道。在两个端点之间有多个ECMP路径。

      f60941ad-7d9b-4d7b-925c-71367239f318-image.png

      选择一个ecmp路径到另一个路径是基于对数据包执行的哈希函数。为了获得更好的分发,我们需要很高的熵,并且正如我们所看到的,MPLSoUDP已经为我们提供好了!

      让我们看一个有关SN GW的示例:
      a4ae70ca-ce5d-4728-9b9f-e8a1c1ee4e67-image.png
      我们看到,有2个ecmp数据包流向计算节点。使用MPLSoUDP将使我们能够以更平衡的方式在两个路径之间分配数据包。

      如果我们查看从计算节点发送的数据包,则可以看到使用MPLSoUDP的另一个好处。

      考虑到接口vhost0是bod接口(将2个物理NIC连接在一起)的设置,那么我要说的就是正确的。

      5d4385e6-c9cc-487b-b6df-053842df2ae8-image.png

      在这种场景下,计算节点被多宿主到了两个叶子节点(运行evpn + vxlan的IP Fabric,使用esi处理多宿主CE)上。结果是,当数据包离开服务器时,将通过绑定的2个链接之一发送数据包。

      现在,基于绑定配置,根据哈希在两个链接之间进行选择。同样,使用MPLSoUDP会更好,因为它带来更多的熵,这意味着更好的分发。在所有bond成员之间平均分配流量,可能会导致流量在整个fabric中分配得很好!

      最后一条需要关注的MPLSoUDP好处,在于dpdk节点上的性能。要理解这一点,我们至少需要对dpdk vRouter的某些方面如何工作,在一个非常高的层级上有所了解。

      为DPDK vRouter分配了一定数量的核心(基于配置参数)。假设为vRouter分配了4个内核。结果就是,通过ethdev,dpdk vRouter会在物理NIC(vif0/0)上对4个队列进行编程。然后,我们就在vRouter核心和NIC队列之间建立了1:1映射。

      对于来自服务器外部的数据包(物理网卡接收数据包),vRouter核心充当轮询核心(vRouter核心可以执行其它角色,处理核心;只是在这里我们对dpdk vRouter的详细理解不感兴趣,因此我们以后讨论这个问题)。

      这里重要的是,充当轮询核心的每个vRouter核心都会不断检查其分配的物理网卡是否有要轮询的数据包。在进行轮询操作之前,物理网卡首先在线路上接收到数据包,然后将该数据包“发送”到一个队列中。为此,物理NIC在数据包上执行哈希操作。

      到这里,事情应该很清楚了。由于涉及哈希,MPLSoUDP确保我们可以在NIC队列上更好地分配流量。在NIC队列上更好地分配数据包,意味着可以在vRouter核心之间更好地分配数据包(请记住,nic队列和vRouter核心之间存在1:1映射关系)。

      d1f053f4-0cb1-4cbf-8c5c-d57d9a6b0310-image.png

      为什么在转发核心之间尽可能平衡地分配流量很重要?

      每个转发核心最多可以处理X个PPS(每秒数据包)。PPS间接意味着吞吐量。通常来说,PPS越高,吞吐量越高。

      让我们举个例子。例如每个转发核心最多可处理2M PPS。这意味着vRouter最多可以处理8M PPS。

      现在,假设使用MPLSoGRE。这种封装不能保证有效的流量分发。这就意味着,可能会将流量仅发送到4个转发核心中的2个(或者至少大多数流量可能主要落在4个转发核心中的2个上)。如果是这样,vRouter的性能大约为4M PPS(约占总容量的50%)。而如果使用MPLSoUDP,流量将更好地分布在所有4个转发核心上。这意味着vRouter总共可以达到8M PPS。换句话说,性能要好得多!

      总结:网关更好平衡,计算节点更好平衡,dpdk vRouter内部更好平衡。除非你的SDN GW仅支持MPLSoGRE,否则没有理由不适用MPLSoUDP,因为它只有好处!


      作者:Umberto Manferdini 译者:TF编译组
      原文链接:https://iosonounrouter.wordpress.com/2020/09/11/why-we-must-use-mplsoudp-with-contrail/
      (注:原文为Contrail,在本系列文章中,Tungsten Fabric的功能与Contrail一致)


      posted in 博客
      B
      bing
    • TF功能指南 | 使用Device Manager管理TF物理路由器
      “TF功能指南”系列文章,旨在帮助大家深入了解Tungsten Fabric各组件功能,更好地部署和应用,发挥TF对于多云互联虚拟网络的创建和编排能力。本文重点介绍如何将TF的功能扩展到物理路由器的管理上。
      

      原文链接:https://www.juniper.net/documentation/en_US/contrail5.0/topics/concept/using-device-manager-netconf-contrail.html
      注:原文为Contrail,在本系列文章中,Tungsten Fabric的功能与Contrail一致。

      物理路由器支持概述

      Device Manager是部署在控制节点的daemon程序,可用于管理Tungsten Fabric系统中的物理路由器。

      Device Manager daemon程序侦听来自API服务器的配置事件,为其管理的所有物理路由器创建任何必要的配置,并对这些物理路由器进行编程。

      你可以扩展集群网络,将Juniper Networks MX系列的物理路由器,以及其它支持网络配置(NETCONF)协议的物理路由器都包含进来。你可以将物理路由器配置为Tungsten Fabric集群中配置的任何虚拟网络的一部分,以促进物理路由器与TF控制节点之间的通信。

      配置模型

      图1描述了系统中使用的配置模型。物理路由器、物理接口和逻辑接口都代表物理路由器实体。
      图1: Tungsten Fabric配置模型
      1daa22c2-8f13-4669-9922-b1cc8ad99f4b-image.png

      配置物理路由器
      TF Web用户界面可用于将物理路由器配置到Tungsten Fabric系统中。选择Configure > Physical Devices > Physical Routers,为物理路由器创建一个条目,并提供路由器的管理IP地址和用户证书。

      下面显示了如何从TF Web用户界面配置Juniper Networks MX系列设备。

      图2:添加Physical Router窗口
      eb322737-9647-49dd-bd88-31d98b7de18e-image.png

      选择Configure > Physical Devices > Interfaces以添加要在路由器上配置的逻辑接口。逻辑接口的名称必须与路由器上的名称匹配(例如ge-0 / 0 / 0.10)。

      图3:添加Interface窗口
      852a163f-0014-4dda-a22f-dbb4d99439af-image.png
      配置物理路由器的替代方法
      你还可以使用TF REST API配置物理路由器,请参阅以下链接:
      https://www.juniper.net/documentation/en_US/contrail5.0/topics/concept/rest-apis-routers-contrail.html

      Device Manager配置

      Device Manager可以在Juniper Networks MX系列设备和其它物理路由器上配置以下所有内容。

      根据需要为物理接口和逻辑接口创建配置。
      根据配置需要创建VRF表条目。
      根据需要将接口添加到VRF表。
      创建与外部虚拟网络相对应的公共VRF表。
      根据需要为内部或外部BGP组创建BGP协议配置,并将iBGP和eBGP对等体添加到适当的组中。
      根据策略配置对路由目标的导入和导出规则进行编程。
      根据需要创建策略和防火墙。
      配置以太网VPN(EVPN)。

      MX系列设备上要求的先决条件配置

      在使用Device Manager管理MX系列设备的配置之前,请使用以下Junos CLI命令在设备上启用NETCONF:
      set system services netconf ssh
      set system services netconf traceoptions file nc
      set system services netconf traceoptions flag all

      调试Device Manager配置
      如果在Device Manager配置期间出现任何故障,则失败的配置将作为候选配置存储在MX 系列设备上。Device Manager会将错误消息记录在本地系统日志中。

      Device Manager配置文件中的日志级别应设置为INFO,以记录发送到物理路由器的NETCONF XML消息。

      配置场景

      本节介绍不同的配置场景,并显示生成的MX系列设备配置的摘要。

      使用REST API配置物理路由器

      有关使用REST API进行配置的信息,请参阅:
      https://www.juniper.net/documentation/en_US/contrail5.0/topics/concept/rest-apis-routers-contrail.html

      使用REST API配置MX设备的示例Python脚本

      请参考以下链接,获取基于Python的脚本,以使用Tungsten Fabric提供的VNC Rest API在TF系统中配置所需的MX 系列设备资源。
      https://github.com/Juniper/contrail-controller/blob/master/src/config/utils/provision_physical_router.py

      Device Manager功能

      当Device Manager在Tungsten Fabric数据库中检测到关联时,它会自动配置物理路由器。

      以下命名规范用于生成MX系列路由器配置:
      Device Manager生成的配置组名称: contrail
      BGP组:
      内部组名称: contrail
      外部组名称: contrail_external
      VRF名称: contrai{l2|l3}[vn-id][vn-name]
      NAT VRF名称: contrai{l2|l3}[vn-id][vn-name]-nat
      导入策略: [vrf-name]—import, Export policy: [vrf-name]—export
      Service集: sv-[vrf-name]
      NAT规则,SNAT: sv-[vrf-name]-sn-rule, DNAT: sv-[vrf-name]-dn-rule
      SNAT术语名称: term
      [private_ip], DNAT term name: term
      [public_ip]
      防火墙过滤器:
      公共VRF过滤器: redirect_to_public_vrf_filter
      专用VRF过滤器: redirect_to_[vrf_name]_vrf
      逻辑接口单元编号:
      Service端口: 2vn_id -1, 2vn_id
      IRB接口: vn_id

      动态隧道

      Tungsten Fabric中的动态隧道配置,可以让你在TF Web用户界面上配置GRE隧道。当Tungsten Fabric检测到此配置时,Device Manager模块将构造GRE隧道配置并将其推送到MX系列路由器。TF架构的全局系统配置中使用了一个名为ip-fabric-subnets的属性。每个IP fabric子网和BGP路由器都被配置为MX系列路由器中的动态隧道目标点。物理路由器数据平面IP地址被视为动态隧道的源地址。你必须配置数据平面IP地址,以便在物理路由器上自动配置动态隧道。IP fabric子网是全局配置,所有子网都在具有数据平面IP配置的集群中的所有物理路由器上进行了配置。

      API配置中使用以下命名规范:
      全局系统配置: ip-fabric-subnets
      物理路由器: data-plane-ip

      Web UI配置

      图4显示了用于配置动态隧道的Web用户界面。
      图4: Edit Global Config窗口
      156ede07-90ff-4738-879f-e3ce54a3f929-image.png

      在“Edit Global Config”窗口中,VTEP地址用于data-plane-ip地址。

      以下是Device Manager生成的MX系列路由器配置的示例。

      root@host# show groups __contrail__ routing-options         
      
      router-id ;
      
      route-distinguisher-id ;
      
      autonomous-system 64512;
      
      dynamic-tunnels {
      
          __contrail__ {
      
              source-address 
      
              gre;
      
              destination-networks {
      
                  /24;
      
                  /32;
      
                  /32;
      
                  /32;
      
                  /32;
      
                  /32;
      
              }
      
          }
      
      }
      

      BGP组

      当Device Manager检测到BGP路由器配置及其与物理路由器的关联时,它将在物理路由器上配置BGP组。

      图5显示了用于配置BGP组的Web用户界面。

      图5: Edit BGP Router窗口
      a88eaf88-15f0-471d-a8ce-941b04efccbc-image.png

      图6显示了用于配置物理路由器的Web用户界面。

      图6: BGP组的Edit Physical Router窗口
      cd0f4b69-1975-4f0a-9ec5-c8cf365fe132-image.png

      以下是Device Manager生成的MX系列路由器配置的示例。

      root@host show groups __contrail__ protocols bgp    
      group __contrail__ {
          type internal;
          multihop;
          local-address ;
          hold-time 90;
          keep all;
          family inet-vpn {
              unicast;
          }
          family inet6-vpn {
              unicast;
          }
          family evpn {
              signaling;
          }
          family route-target;
          neighbor ;
          neighbor ;
          neighbor ;
          neighbor ;
      }
      
      group __contrail_external__ {
          type external;
          multihop;
          local-address ;
          hold-time 90;
          keep all;
          family inet-vpn {
              unicast;
          }
          family inet6-vpn {
              unicast;
          }
          family evpn {
              signaling;                      
          }                                   
          family route-target;                
      }
      

      扩展专用网络

      Device Manager允许你将专用网络和端口扩展到物理路由器。当Device Manager检测到VNC配置时,它将推送第2层(EVPN)和第3层VRF,将规则和接口配置导入和导出到物理路由器。

      图7显示了用于配置物理路由器以扩展专用网络的Web用户界面。

      图7: 用于扩展专用网络的Edit Physical Router窗口
      3e5a2937-90fd-4ce3-ba29-d540ca283745-image.png

      以下是Device Manager生成的MX系列路由器配置的示例。

      /* L2 VRF */
      
      root@host# show groups __contrail__ routing-instances _contrail_l2_147_vn_private-x1-63           
      vtep-source-interface lo0.0;
      instance-type virtual-switch;
      vrf-import _contrail_l2_147_vn_private-x1-63-import;
      vrf-export _contrail_l2_147_vn_private-x1-63-export;
      protocols {
          evpn {
              encapsulation vxlan;
              extended-vni-list all;
          }
      }
      bridge-domains {
          bd-147 {
              vlan-id none;
              routing-interface irb.147;
              vxlan {
                  vni 147;
              }
          }
      }
      
      /* L3 VRF */
      root@host# show groups __contrail__ routing-instances _contrail_l3_147_vn_private-x1-63    
      instance-type vrf;
      interface irb.147;
      vrf-import _contrail_l3_147_vn_private-x1-63-import;
      vrf-export _contrail_l3_147_vn_private-x1-63-export;
      vrf-table-label;
      routing-options {
          static {
              route /24 discard;
          }
          auto-export {
              family inet {
                  unicast;
              }
          }
      }
      
      /* L2 Import policy */
      
      root@host# ...cy-options policy-statement _contrail_l2_147_vn_private-x1-63-import
      term t1 {
          from community target_64512_8000066;
          then accept;
      }
      then reject;
      
       
      
      /* L2 Export Policy */
      root@host# ...ail__ policy-options policy-statement _contrail_l2_147_vn_private-x1-63-export    
      term t1 {
          then {
              community add target_64512_8000066;
              accept;
          }
      }
      
      /* L3 Import Policy */
      
      root@host# ...ail__ policy-options policy-statement _contrail_l3_147_vn_private-x1-63-import    
      term t1 {
          from community target_64512_8000066;
          then accept;
      }
      then reject;
      
      /*L3 Export Policy */
      root@host# ...ail__ policy-options policy-statement _contrail_l3_147_vn_private-x1-63-export    
      term t1 {
          then {
              community add target_64512_8000066;
              accept;
          }
      }
      

      扩展公用网络

      当公用网络扩展到物理路由器时,将在MX系列路由器上配置静态路由。配置将下一跳从public.inet.0路由表复制到inet.0默认路由表,并将转发表过滤器从inet.0路由表复制到public.inet.0路由表。该过滤器将应用于在inet.0路由表中查找的所有数据包,并与公共虚拟网络的子网中的目标匹配。策略动作是为了执行在public.inet.0路由表中的查找操作。

      图8显示了用于扩展公用网络的Web用户界面。

      图8: Edit Network Gateway窗口
      5f253dd7-6f8e-43a9-a0c4-7ceb6193c83e-image.png

      以下是Device Manager生成的MX系列路由器配置的示例。

      /* forwarding options */
      
      root@host show groups __contrail__ forwarding-options
      family inet {
          filter {
              input redirect_to_public_vrf_filter;
          }
      }
      
      /* firewall filter configuration */
      
      root@host# show groups __contrail__ firewall family inet filter redirect_to_public_vrf_filter
      
      term term-_contrail_l3_184_vn_public-x1- {
      
          from {
      
              destination-address {
      
                  /16;
      
              }
      
          }
      
          then {
      
              routing-instance _contrail_l3_184_vn_public-x1-;
      
          }
      
      }
      
      term default-term {
      
          then accept;
      
      }
      
      /* L3 VRF static route 0.0.0.0/0 configuration */
      
      root@host# ...instances _contrail_l3_184_vn_public-x1- routing-options static route 0.0.0.0/0   
      next-table inet.0;
      

      EVPN配置

      对于每个专用网络,在MX系列路由器上都配置了2层以太网VPN(EVPN)实例。如果有任何2层接口与虚拟网络相关联,那么还要在网桥域下创建逻辑接口。

      以下是Device Manager生成的MX系列路由器配置的示例。

      root@host# show groups __contrail__ routing-instances _contrail_l2_147_vn_private-x1-63           
      vtep-source-interface lo0.0;
      instance-type virtual-switch;
      vrf-import _contrail_l2_147_vn_private-x1-63-import;
      vrf-export _contrail_l2_147_vn_private-x1-63-export;
      protocols {
          evpn {
              encapsulation vxlan;
              extended-vni-list all;
          }
      }
      bridge-domains {
          bd-147 {
              vlan-id none;
      
              interface ge-1/0/5.0;
              routing-interface irb.147;
              vxlan {
                  vni 147;
              }
          }
      }
      

      客户虚拟机和裸机服务器的浮动IP地址和源网络地址转换

      本节描述了裸机服务器部署场景,其中服务器连接到专用网络内部的TOR QFX设备,而MX系列路由器则是公用网络连接的网关。

      MX系列路由器提供了NAT功能,该功能允许来自公用网络的流量进入专用网络,以及反向的情况。为此,你需要在MX系列路由器上配置NAT规则。当Device Manager检测到裸机服务器连接到公用网络时,将负责在MX系列路由器上对这些NAT规则进行编程。

      你必须为TOR设备、MX系列路由器、专用网络和公用网络(包括地址池)配置虚拟网络计算。当TOR设备上的逻辑接口与虚拟机接口相关联,并且将浮动IP地址分配给同一虚拟机接口(VMI)时,Tungsten Fabric会检测到此情况,并且Device Manager会在与专用网络关联的每个MX系列路由器上配置必要的浮动IP NAT规则。

      图9说明了Device Manager在MX系列路由器上配置了两个特殊的逻辑接口,称为服务端口(service-ports),用于从专用网络到公用网络的NAT转换。

      图9:浮动IP和SNAT的逻辑拓扑
      8b687f5c-4d86-4204-83a9-bb7296b1773f-image.png

      TF架构允许用户使用虚拟网络计算API指定服务端口名称。服务端口必须是MX系列路由器上的物理链接,并且管理和操作状态必须为up。Device Manager在此服务端口上创建两个逻辑接口,每个逻辑接口用于一个专用虚拟网络,并应用NAT规则。

      MX系列路由器上的专用网络路由实例,具有指向内部服务接口的默认静态路由(0.0.0.0/0)下一跳。MX系列路由器上的公用网络路由实例,具有指向外部服务接口的专用IP前缀下一跳的路由。从公共IP地址到私有IP地址以及反向NAT规则,都在MX系列路由器上配置。

      在MX系列路由器上,为每个专用网络到一个或多个公用网络关联,都创建了一个特殊的路由实例。该VRF在一侧具有两个接口,允许往返于公用网络的流量,而另一个接口则允许往返于专用网络的流量。在MX系列路由器上需要配置防火墙过滤器,以便如果公用网络具有与由TF vRouter管理的guest VM关联的浮动IP地址,则vRouter将执行浮动IP地址功能。否则,MX系列路由器将执行NAT功能,以便与裸机服务器VM之间收发通信。

      你必须创建必需的物理设备、接口和虚拟网络配置,并将其推送到MX系列路由器,如图9所示。

      可以使用Web UI或VNC API完成Tungsten Fabric配置。所需的配置是:
      创建专用虚拟网络。
      创建一个或多个TOR物理路由器(Tungsten Fabric无需将Junos OS配置推送到该设备。因此,这里vnc managed属性将设置为False)。
      将专用虚拟网络扩展到TOR设备。
      在TOR设备上创建物理和逻辑接口。
      在专用网络上为裸机服务器创建VMI,并将VMI与逻辑接口关联。这样做表明裸机服务器已通过逻辑接口连接到TOR设备。实例IP地址必须分配给该VMI。VMI将专用IP地址用于裸机服务器。
      创建网关路由器。这是由Device Manager管理的物理路由器。
      为物理MX系列路由器配置 service-port物理接口信息。Device Manager在MX系列路由器上,为与该设备关联的每个专用网络配置两个逻辑服务接口,并自动在这些接口上配置NAT规则以实现私有到公共IP地址的转换,并为反向动作配置SNAT规则。逻辑端口ID是根据TF VNC分配的虚拟网络ID计算得出的。每个专用网络需要两个逻辑端口。
      关联浮动IP地址,包括在Tungsten Fabric中创建公用网络、浮动IP地址池和浮动IP地址,并将该IP地址与VMI裸机服务器关联。
      专用网络和公用网络必须扩展到物理路由器。

      当Tungsten Fabric中存在所需的配置时,Device Manager会将生成的Junos OS配置推送到MX系列设备。以下展示了示例的配置:

      /* NAT VRF configuration */
      
      root@host# show groups __contrail__ routing-instances _contrail_l3_147_vn_private-x1-63-nat
      
      instance-type vrf;
      
      interface si-2/0/0.293;
      
      vrf-import _contrail_l3_147_vn_private-x1-63-nat-import;
      
      vrf-export _contrail_l3_147_vn_private-x1-63-nat-export;
      
      vrf-table-label;
      
      routing-options {
      
          static {
      
              route 0.0.0.0/0 next-hop si-2/0/0.293;
      
          }
      
          auto-export {
      
              family inet {
      
                  unicast;
      
              }
      
          }
      
      }
      
      /* NAT VRF import policy */
      
      root@host# ...y-statement _contrail_l3_147_vn_private-x1-63-nat-import       
      
      term t1 {
      
          from community target_64512_8000066;
      
          then accept;
      
      }
      
      then reject;
      
      /* NAT VRF Export policy */
      
      root@host# ..._ policy-options policy-statement _contrail_l3_147_vn_private-x1-63-nat-export   
      
      term t1 {
      
          then reject;
      
      }
      
      /* The following additional config is generated for public l3 vrf */
      
      root@host# show groups __contrail__ routing-instances _contrail_l3_184_vn_public-x1-
      
      interface si-2/0/0.294;              
      
      routing-options {                      
      
          static {                           
      
              route /32 next-hop si-2/0/0.294;
      
              route /32 next-hop si-2/0/0.294;
      
          }
      
      }
      
      /* Services set configuration */
      
      root@host# show groups __contrail__                
      
      services {
      
          service-set sv-_contrail_l3_147_vn_ {
      
              nat-rules sv-_contrail_l3_147_vn_-sn-rule;
      
              nat-rules sv-_contrail_l3_147_vn_-dn-rule;
      
              next-hop-service {
      
                  inside-service-interface si-2/0/0.293;
      
                  outside-service-interface si-2/0/0.294;
      
              }
      
          }
      
      }
      
      /* Source Nat Rules*/
      
      root@host# show groups __contrail__ services nat rule sv-_contrail_l3_147_vn_-sn-rule   
      
      match-direction input;
      
      term term {
      
          from {
      
              source-address {
      
                  /32;
      
              }
      
          }
      
          then {
      
              translated {
      
                  source-prefix /32;
      
                  translation-type {
      
                      basic-nat44;
      
                  }
      
              }
      
          }
      
      }
      
      term term {
      
          from {
      
              source-address {
      
                  /32;
      
              }
      
          }
      
          then {
      
              translated {
      
                  source-prefix /32;
      
                  translation-type {
      
                      basic-nat44;
      
                  }
      
              }
      
          }
      
      }
      
      /* Destination NAT rules */
      
      root@host# show groups __contrail__ services nat rule sv-_contrail_l3_147_vn_-dn-rule   
      
      match-direction output;
      
      term term {
      
          from {
      
              destination-address {
      
                  /32;
      
              }
      
          }
      
          then {
      
              translated {
      
                  destination-prefix /32;
      
                  translation-type {
      
                      dnat-44;
      
                  }
      
              }
      
          }
      
      }
      
      term term {
      
          from {
      
              destination-address {
      
                  /32;
      
              }
      
          }
      
          then {
      
              translated {
      
                  destination-prefix /32;
      
                  translation-type {
      
                      dnat-44;
      
                  }
      
              }
      
          }
      
      }
      
       
      
      /* Public VRf Filter */
      
      root@host# show groups __contrail__ firewall family inet filter redirect_to_public_vrf_filter
      
      term term-_contrail_l3_184_vn_public-x1- {
      
          from {
      
              destination-address {
      
                  /16;
      
              }
      
          }
      
          then {
      
              routing-instance _contrail_l3_184_vn_public-x1-;
      
          }
      
      }
      
      term default-term {
      
          then accept;
      
      }
      
      /* NAT Vrf filter */
      
      root@host# ...all family inet filter redirect_to__contrail_l3_147_vn_private-x1-63-nat_vrf  
      
      term term-_contrail_l3_147_vn_private-x1-63-nat {
      
          from {
      
              source-address {
      
                 /32;
      
                 /32;
      
              }
      
          }
      
          then {
      
              routing-instance _contrail_l3_147_vn_private-x1-63-nat;
      
          }
      
      }
      
      term default-term {
      
          then accept;
      
      }
      
      /* IRB interface for NAT VRF */
      
      root@host# show groups __contrail__ interfaces            
      
      irb {
      
          gratuitous-arp-reply;
      
          unit 147 {
      
              family inet {
      
                  filter {
      
                      input redirect_to__contrail_l3_147_vn_private-x1-63-nat_vrf;
      
                  }
      
                  address /24;
      
              }
      
          }
      
      /* Service Interfaces config */
      
      root@host# show groups __contrail__ interfaces si-2/0/0        
      
      unit 293 {
      
          family inet;
      
          service-domain inside;
      
      }
      
      unit 294 {
      
          family inet;
      
          service-domain outside;
      
      }
      

      MX系列设备生成的配置样本

      本节提供了使用Python脚本生成的MX系列设备配置的几种场景和示例。

      场景1:无外部网络的物理路由器

      以下描述了没有外部虚拟网络的基本vn、vmi、li、pr、pi配置的用例。当使用此用例的参数执行以下所示的Python脚本时,该配置将应用于MX系列物理路由器。

      在Tungsten Fabric控制器上执行的脚本:

      # python provision_physical_router.py --api_server_ip  --api_server_port 8082 --admin_user  --admin_password  --admin_tenant_name default-domain --op add_basic
      

      MX系列设备生成的配置:

      root@host# show groups __contrail__    
      routing-options {
          route-distinguisher-id ;
          autonomous-system 64512;
      }
      protocols {
          bgp {
              group __contrail__ {
                  type internal;
                  multihop;
                  local-address ;
                  keep all;
                  family inet-vpn {
                      unicast;
                  }
                  family inet6-vpn {
                      unicast;
                  }
                  family evpn {
                      signaling;
                  }
                  family route-target;
              }
              group __contrail_external__ {
                  type external;
                  multihop;
                  local-address ;
                  keep all;
                  family inet-vpn {
                      unicast;
                  }
                  family inet6-vpn {
                      unicast;
                  }
                  family evpn {
                      signaling;
                  }
                  family route-target;
              }
          }
      }
      policy-options {
          policy-statement __contrail__default-domain_default-project_vn1-export {
              term t1 {
                  then {
                      community add target_64200_8000008;
                      accept;
                  }
              }
          }
          policy-statement __contrail__default-domain_default-project_vn1-import {
              term t1 {
                  from community target_64200_8000008;
                  then accept;                
              }                               
              then reject;                    
          }                                   
          community target_64200_8000008 members target:64200:8000008;
      }                                       
      routing-instances {                     
          __contrail__default-domain_default-project_vn1 {
              instance-type vrf;              
              interface ge-1/0/5.0;           
              vrf-import __contrail__default-domain_default-project_vn1-import;
              vrf-export __contrail__default-domain_default-project_vn1-export;
              vrf-table-label;                
              routing-options {               
                  static {                    
                      route/24 discard;
                  }                           
                  auto-export {               
                      family inet {           
                          unicast;            
                      }                       
                  }                           
              }                               
          }                                   
      }
      

      场景2:具有外部网络、公共VRF的物理路由器

      本节介绍带有外部虚拟网络公共VRF的vn、vmi、li、pr、pi配置的用例。当使用此用例的参数执行所示的Python脚本时,该配置将应用于MX系列物理路由器。

      本示例假定已执行场景1中已描述的配置。

      在Tungsten Fabric控制器上执行的脚本:

      # python provision_physical_router.py --api_server_ip  --api_server_port 8082 --admin_user  --admin_password  --admin_tenant_name default-domain --op add_basic --public_vrf_test True
      

      MX系列设备生成的配置:

      除了在场景1中生成的配置之外,还将以下其它配置推送到MX系列设备。

      forwarding-options {
          family inet {
              filter {
                  input redirect_to___contrail__default-domain_default-project_vn1_vrf;
              }
          }
      }
      firewall {                           
          filter redirect_to___contrail__default-domain_default-project_vn1_vrf {
              term t1 {                    
                  from {                    
                      destination-address {
                          /24;     
                      }                    
                  }                        
                  then {                   
                      routing-instance __contrail__default-domain_default-project_vn1;
                  }                        
              }                            
              term t2 {                    
                  then accept;             
              }                            
          }                                
      }
      routing-instances {                  
          __contrail__default-domain_default-project_vn1 {
              routing-options {            
                  static {                 
                      route 0.0.0.0/0 next-table inet.0;
                  }                        
              }                            
          }                                
      }
      

      场景3:具有外部网络、公共VRF和EVPN的物理路由器

      本节中的场景描述了vn、vmi、li、pr、pi物理路由器配置与外部虚拟网络(公共VRF)和EVPN配置的使用情况。当使用此场景的参数执行Python脚本(如前面的示例中所示)时,以下配置将应用于MX系列物理路由器。

      本示例假定已执行场景1中已经描述的配置。

      在Tungsten Fabric控制器上执行的脚本:

      # python provision_physical_router.py --api_server_ip  --api_server_port 8082 --admin_user  --admin_password  --admin_tenant_name default-domain --op add_basic --public_vrf_test True –vxlan 2002
      

      MX系列设备的生成的配置:

      除了在场景1中生成的配置之外,还将以下其它配置推送到MX系列设备。

      protocols {
          mpls {
              interface all;
          }
      }                                      
      firewall {                            
          filter redirect_to___contrail__default-domain_default-project_vn1_vrf {
              term t1 {                     
                  from {                    
                      destination-address { 
                          /24;      
                      }                     
                  }                         
                  then {                    
                      routing-instance __contrail__default-domain_default-project_vn1;
                  }                         
              }                             
              term t2 {                     
                  then accept;              
              }                              
          }                                 
      }                              
      routing-instances {                   
          __contrail__default-domain_default-project_vn1 {
              vtep-source-interface lo0.0;  
              instance-type virtual-switch; 
              vrf-target target:64200:8000008;
              protocols {                   
                  evpn {                    
                      encapsulation vxlan;  
                      extended-vni-all;     
                  }                         
              }                             
              bridge-domains {              
                  bd-2002 {                  
                      vlan-id 2002;         
                      interface ge-1/0/5.0; 
                      routing-interface irb.2002;
                      vxlan {               
                          vni 2002;         
                          ingress-node-replication;
                      }                     
                  }                         
              }                             
          }                                 
      }
      

      场景4:具有外部网络、公共VRF和裸机服务器浮动IP地址的物理路由器
      本节中的场景描述了vn、vmi、li、pr、pi物理路由器配置的用户案例,该配置带有外部虚拟网络(公共VRF)和用于裸机服务器配置的浮动IP地址。

      在Tungsten Fabric控制器上执行的脚本:

      #python provision_physical_router.py --api_server_ip  --api_server_port 8082 --admin_user  --admin_password  --admin_tenant_name default-domain --op {fip_test|delete_fip_test}
      
      posted in 博客
      B
      bing
    • 如何在OpenStack-Ansible上集成Tungsten Fabric(下)

      如何在OpenStack-Ansible上集成Tungsten Fabric(上)

      测试验证

      Tungsten Fabric已配置为使用Keystone身份验证,要验证这一点,可以使用外部VIP地址和端口8143在浏览器中打开TF的UI:
      72242493-100d-4b77-92dc-647606011c20-image.png
      输入用户名admin,以及在openrc文件中定义的密码。域的地方填default。 如果身份验证成功,则登录面板应如下显示:
      cec48a1b-71ab-46a7-b426-ae15360e8962-image.png
      回到OpenStack,我们可以执行一个openstack network list 的命令来查看网络:

      root@aio1-utility-container-ee37a935:~# openstack network list
      +--------------------------------------+-------------------------+---------+
      | ID                                   | Name                    | Subnets |
      +--------------------------------------+-------------------------+---------+
      | 723e67c1-8ccd-43ba-a6f4-8b2399c1b8d2 | __link_local__          |         |
      | 5a2947ce-0030-4d2a-a06a-76b0d6934102 | ip-fabric               |         |
      | 5f4b0153-8146-4e9c-91d4-c60364ece6bc | default-virtual-network |         |
      +--------------------------------------+-------------------------+---------+
      

      这些网络都是由TF插件/驱动程序创建的,不应删除。
      创建一个测试网络:

      root@aio1-utility-container-ee37a935:~# openstack network create test_network_green
      +---------------------------+--------------------------------------+
      | Field                     | Value                                |
      +---------------------------+--------------------------------------+
      | admin_state_up            | UP                                   |
      | availability_zone_hints   | None                                 |
      | availability_zones        | None                                 |
      | created_at                | None                                 |
      | description               | None                                 |
      | dns_domain                | None                                 |
      | id                        | d9e0507f-5ef4-4b62-bf69-176340095053 |
      | ipv4_address_scope        | None                                 |
      | ipv6_address_scope        | None                                 |
      | is_default                | None                                 |
      | is_vlan_transparent       | None                                 |
      | mtu                       | None                                 |
      | name                      | test_network_green                   |
      | port_security_enabled     | True                                 |
      | project_id                | e565909917a5463b867c5a7594a7612f     |
      | provider:network_type     | None                                 |
      | provider:physical_network | None                                 |
      | provider:segmentation_id  | None                                 |
      | qos_policy_id             | None                                 |
      | revision_number           | None                                 |
      | router:external           | Internal                             |
      | segments                  | None                                 |
      | shared                    | False                                |
      | status                    | ACTIVE                               |
      | subnets                   |                                      |
      | tags                      |                                      |
      | updated_at                | None                                 |
      +---------------------------+--------------------------------------+
      

      注意 provider属性是未指定的,但这些对我们不再重要。TF插件可能不支持其它的属性。
      创建子网:

      root@aio1-utility-container-ee37a935:~# openstack subnet create --subnet-range 172.23.0.0/24 --network test_network_green test_subnet_green
      +-------------------+--------------------------------------+
      | Field             | Value                                |
      +-------------------+--------------------------------------+
      | allocation_pools  | 172.23.0.2-172.23.0.254              |
      | cidr              | 172.23.0.0/24                        |
      | created_at        | None                                 |
      | description       | None                                 |
      | dns_nameservers   |                                      |
      | enable_dhcp       | True                                 |
      | gateway_ip        | 172.23.0.1                           |
      | host_routes       |                                      |
      | id                | cc2d2f56-5c87-49fb-afd5-14e32feccd6a |
      | ip_version        | 4                                    |
      | ipv6_address_mode | None                                 |
      | ipv6_ra_mode      | None                                 |
      | name              | test_subnet_green                    |
      | network_id        | d9e0507f-5ef4-4b62-bf69-176340095053 |
      | project_id        | e565909917a5463b867c5a7594a7612f     |
      | revision_number   | None                                 |
      | segment_id        | None                                 |
      | service_types     | None                                 |
      | subnetpool_id     | None                                 |
      | tags              |                                      |
      | updated_at        | None                                 |
      +-------------------+--------------------------------------+
      

      IPv6应该是支持的,但是在尝试创建IPv6子网时遇到了问题。这里我们的网络已准备好用于VM。为了达到良好的效果,我创建了一个安全组,该安全组可以应用于允许SSH的实例:

      root@aio1-utility-container-ee37a935:~# openstack security group create allow_ssh
      +-----------------+--------------------------------------+
      | Field           | Value                                |
      +-----------------+--------------------------------------+
      | created_at      | None                                 |
      | description     | allow_ssh                            |
      | id              | 39a9e241-27c3-452a-b37a-80b6dcbbf783 |
      | name            | allow_ssh                            |
      | project_id      | e565909917a5463b867c5a7594a7612f     |
      | revision_number | None                                 |
      | rules           |                                      |
      | tags            | []                                   |
      | updated_at      | None                                 |
      +-----------------+--------------------------------------+
      
      root@aio1-utility-container-ee37a935:~# openstack security group rule create --dst-port 22 allow_ssh
      
      +-------------------+--------------------------------------+
      | Field             | Value                                |
      +-------------------+--------------------------------------+
      | created_at        | None                                 |
      | description       | None                                 |
      | direction         | ingress                              |
      | ether_type        | IPv4                                 |
      | id                | b8393e4d-1d9d-47e9-877e-86374f38dca1 |
      | name              | None                                 |
      | port_range_max    | 22                                   |
      | port_range_min    | 22                                   |
      | project_id        | e565909917a5463b867c5a7594a7612f     |
      | protocol          | tcp                                  |
      | remote_group_id   | None                                 |
      | remote_ip_prefix  | 0.0.0.0/0                            |
      | revision_number   | None                                 |
      | security_group_id | 39a9e241-27c3-452a-b37a-80b6dcbbf783 |
      | updated_at        | None                                 |
      

      +-------------------+--------------------------------------+
      随后,我使用tiny flavor和CirrOS镜像启动了实例:

      root@aio1-utility-container-ee37a935:~# openstack server create --image cirros --flavor test_flavor --nic net-id=test_network_green --security-group allow_ssh test1
      +-------------------------------------+----------------------------------------------------+
      | Field                               | Value                                              |
      +-------------------------------------+----------------------------------------------------+
      | OS-DCF:diskConfig                   | MANUAL                                             |
      | OS-EXT-AZ:availability_zone         |                                                    |
      | OS-EXT-SRV-ATTR:host                | None                                               |
      | OS-EXT-SRV-ATTR:hypervisor_hostname | None                                               |
      | OS-EXT-SRV-ATTR:instance_name       |                                                    |
      | OS-EXT-STS:power_state              | NOSTATE                                            |
      | OS-EXT-STS:task_state               | scheduling                                         |
      | OS-EXT-STS:vm_state                 | building                                           |
      | OS-SRV-USG:launched_at              | None                                               |
      | OS-SRV-USG:terminated_at            | None                                               |
      | accessIPv4                          |                                                    |
      | accessIPv6                          |                                                    |
      | addresses                           |                                                    |
      | adminPass                           | a8tghwSoTWZP                                       |
      | config_drive                        |                                                    |
      | created                             | 2018-06-18T14:34:49Z                               |
      | flavor                              | test_flavor (5c0600b7-f9fe-46f3-8af5-f8390ee5c6f3) |
      | hostId                              |                                                    |
      | id                                  | b14d1861-8855-4d17-a2d3-87eb67a3d81c               |
      | image                               | cirros (4006fd58-cdc5-4bd8-bc25-ef73be1cd429)      |
      | key_name                            | None                                               |
      | name                                | test1                                              |
      | progress                            | 0                                                  |
      | project_id                          | e565909917a5463b867c5a7594a7612f                   |
      | properties                          |                                                    |
      | security_groups                     | name='39a9e241-27c3-452a-b37a-80b6dcbbf783'        |
      | status                              | BUILD                                              |
      | updated                             | 2018-06-18T14:34:49Z                               |
      | user_id                             | f6aac1aa53294659998aa71838133a1d                   |
      | volumes_attached                    |                                                    |
      +-------------------------------------+----------------------------------------------------+
      
      root@aio1-utility-container-ee37a935:~# openstack server list
      +--------------------------------------+-------+--------+-------------------------------+--------+-------------+
      | ID                                   | Name  | Status | Networks                      | Image  | Flavor      |
      +--------------------------------------+-------+--------+-------------------------------+--------+-------------+
      | b14d1861-8855-4d17-a2d3-87eb67a3d81c | test1 | ACTIVE | test_network_green=172.23.0.3 | cirros | test_flavor |
      +--------------------------------------+-------+--------+-------------------------------+--------+-------------+
      

      现在,我可以连接到实例的控制台,并尝试出站连接:
      314af17b-247d-4eda-b05b-cf5c7f9b73cb-image.png
      在Tungsten Fabric UI中,我能够在网络上启用snat ,以允许vRouter对来自VM的出站连接进行snat:
      f70a04a8-cb17-4939-825c-281975752d63-image.png
      快速测试显示ping正常工作:
      2ab7327e-9acd-4d73-9862-5f2161f89201-image.png
      到VM的入站连接也是可行的,但需要Tungsten Fabric进行一些额外的工作才能通告VM地址。在我的实验室中有一个Cisco ASA 1001,已配置为与TF控制器建立对等关系,但我们下一次再展示它是如何配置的吧。

      总结

      对于学习了解Tungsten Fabric的运行方式,以及围绕如何在基于OpenStack-Ansible的云中部署构建最佳实践,还有很多工作要做。用于安装过程的某些组件,被大量包装在Docker容器中,并且必须先提取才能在LXC容器和/或主机中进行部署。这是不可扩展的,但目前来说已经足够了。

      最近,我遇到了与opencontrailnightly 版本有关的问题,vRouter丢弃来自VM的出站或响应流量。借助Juniper repo中的GA版本,该问题已经解决了,但并非每个人都可以使用该访问权限。

      我遇到的另一个问题是,在往返于VM的ping工作正常(在中间使用ASR)的同时,SSH却连接失败。实际上,任何TCP连接都失败了。在该实例中看到了SYN,并且观察到发送了SYN/ACK。但是,SYN/ACK从未通过vRouter。抓包信息表明,SYN/ACK的校验和无效。当在主机的“physical”接口上禁用通用IP校验和,这种情况下为ens160,可以使一切恢复正常。下面这篇文章超级有帮助:
      https://kb.juniper.net/InfoCenter/index?page=content&id=KB30500

      随着我获得更多的reps,我希望简化流程,并且能有一天将其移到上游以包含在OpenStack-Ansible中。在那之前,祝我们都好运!

      作者:James Denton 译者:TF编译组
      原文链接:https://www.jimmdenton.com/contrail-osa/

      posted in 博客
      B
      bing
    • 如何在OpenStack-Ansible上集成Tungsten Fabric(上)

      本文作者James Denton,拥有超过15年信息技术领域行业经验,目前为知名云计算服务商Rackspace Hosting首席架构师,致力于云网络和对基于OpenStack的Rackspace私有云产品的支持。

      Tungsten Fabric(前身为OpenContrail)是Linux基金会旗下的“多云、多技术栈”SDN解决方案。简而言之,Tungsten Fabric和Contrail(基于TF的商业产品)可以替代和增强标准OpenStack云的许多网络组件,并提供以下功能:
      分布式虚拟路由
      DHCP和元数据服务
      基于策略的访问控制
      与安全组的兼容性
      ……等等

      转发平面支持MPLS over GRE、VXLAN、L2/L3单播和L3多播,以实现虚拟网络和物理网络之间的互连。
      注:关于Tungsten Fabric架构的概述可在下面的链接找到:https://tungstenfabric.org.cn/docs

      我最近接受了将Tungsten Fabric集成到OpenStack-Ansible中的挑战,以简化TF和相关OpenStack bits在生产级OpenStack云中的部署。本文将在较高级别涵盖OpenStack-Ansible的主(Rocky)分支的一些补丁,以及Juniper和TF社区提供的用于部署Tungsten Fabric的contrail-ansible-deployer playbooks的一些调整。本文所描述的过程绝不意味着是最终的过程,可能会显得比较笨拙且不理想,但是,这是一个开始。

      注:本文作者指明文章中的Tungsten Fabric、OpenContrail和Contrail为混用,翻译时统一为Tungsten Fabric。

      集成要求

      几周前,我部署了一个独立的3节点Tungsten Fabric设置,其中包含基于Queens的OpenStack-Ansible的All-in-One节点。在弄清楚使事情进入半工作状态所需的调整后,我决定亲自尝试并部署一个AIO节点,该节点包含一个单一的Tungsten Fabric服务实例以及基本的OpenStack服务。

      以下为最低规格的配置建议:
      系统: Ubuntu VM
      OS: 16.04.4 LTS
      内存: 48GB
      硬盘: 300GB
      NIC: 单口网卡

      如我稍后指出的,裸机节点可能复杂度较小,但是ESXi或其它管理程序上的虚拟机应该是可以尝试的。

      从OpenStack-Ansible开始

      首先,请克隆OpenStack-Ansible存储库。在撰写本文时,master分支是与OpenStack的第18个发行版Rocky相关联的。

      # git clone https://git.openstack.org/openstack/openstack-ansible /opt/openstack-ansible
      # cd /opt/openstack-ansible
      # git checkout master
      # export ANSIBLE_ROLE_FETCH_MODE=git-clone
      

      接下来,运行引导程序脚本:

      # scripts/bootstrap-ansible.sh
      # scripts/bootstrap-aio.sh
      

      引导程序脚本将下载playbooks以部署OpenStack,还将在服务器上准备符合OpenStack-Ansible架构的网络环境。

      角色修改

      对使用OpenStack-Ansible部署的OpenStack云进行更改,通常意味着对构成部署的Ansible角色进行更改。这包括对任务、模板、变量等的更改。

      需要修改的角色包括:
      os_neutron
      os_nova

      是否所有这些角色的更改都是必需的,还有待观察,这里只是为了更好地说明。

      os_neutron

      一些新文件包括:

      root@aio1:/etc/ansible/roles/os_neutron# git diff --staged
      diff --git a/tasks/providers/opencontrail_config.yml b/tasks/providers/opencontrail_config.yml
      new file mode 100644
      index 0000000..8f5fc7d
      --- /dev/null
      +++ b/tasks/providers/opencontrail_config.yml
      @@ -0,0 +1,99 @@
      +---
      +# Copyright 2018, Rackspace Hosting, Inc.
      +#
      +# 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.
      +
      +- name: Set the packages to install
      +  set_fact:
      +    neutron_optional_combined_pip_packages: |-
      +      {% set packages = neutron_optional_opencontrail_pip_packages %}
      +      {{ packages }}
      +
      +- name: Install OpenContrail pip packages
      +  pip:
      +    name: "{{ neutron_optional_combined_pip_packages }}"
      +    state: "{{ neutron_pip_package_state }}"
      +    virtualenv: "{{ neutron_bin | dirname }}"
      +    virtualenv_site_packages: "no"
      +    extra_args: >-
      +      {{ neutron_developer_mode | ternary(pip_install_developer_constraints | default('--constraint /opt/developer-pip-constraints.txt'), '') }}
      +      {{ (pip_install_upper_constraints is defined) | ternary('--constraint ' + pip_install_upper_constraints | default(''),'') }}
      +      {{ pip_install_options | default('') }}
      +  register: install_packages
      +  until: install_packages|success
      +  retries: 5
      +  delay: 2
      +  tags:
      +    - opencontrail-install
      +    - opencontrail-pip-packages
      +
      +- name: Install git
      +  apt:
      +    name: git
      +    state: present
      +  delegate_to: "{{ item }}"
      +  with_items:
      +    - "{{ groups['neutron_server'] }}"
      +  tags:
      +    - opencontrail-install
      +
      +- name: Clone contrail neutron plugin
      +  git:
      +    repo: "{{ opencontrail_plugin_git_repo }}"
      +    version: "{{ opencontrail_plugin_git_install_branch }}"
      +    dest: /opt/contrail-neutron-plugin
      +    force: yes
      +  register: contrail_plugin_git_clone
      +  delegate_to: "{{ item }}"
      +  with_items:
      +    - "{{ groups['neutron_server'] }}"
      +  until: contrail_plugin_git_clone|success
      +  retries: 5
      +  delay: 2
      +  tags:
      +    - opencontrail-install
      +
      +# (jamesdenton) Will need to eventually compile and/or extract from Docker container
      +# The tasks marked (temp) should be reworked
      +
      +- name: Download Contrail python libraries (temp)
      +  vars:
      +  - dlpath: https://github.com/busterswt/contrail-openstack/raw/master
      +  get_url:
      +    url: "{{ dlpath }}/{{ item }}"
      +    dest: /opt
      +    mode: 0440
      +  with_items:
      +    - contrail-openstack-neutron-init.tar
      +  tags:
      +    - opencontrail-install
      +
      +- name: Unpack Contrail python libraries (temp)
      +  unarchive:
      +    remote_src: yes
      +    src: /opt/contrail-openstack-neutron-init.tar
      +    dest: /openstack/venvs/neutron-{{ neutron_venv_tag }}/lib/python2.7/site-packages
      +  when:
      +    inventory_hostname == groups['neutron_server'][0]
      +  tags:
      +    - opencontrail-install
      +
      +- name: Install contrail neutron plugin into venv
      +  command: "/openstack/venvs/neutron-{{ neutron_venv_tag }}/bin/python setup.py install"
      +  args:
      +    chdir: /opt/contrail-neutron-plugin
      +  delegate_to: "{{ item }}"
      +  with_items:
      +    - "{{ groups['neutron_server'] }}"
      +  tags:
      +    - opencontrail-install
      diff --git a/templates/plugins/opencontrail/ContrailPlugin.ini.j2 b/templates/plugins/opencontrail/ContrailPlugin.ini.j2
      new file mode 100644
      index 0000000..9d645b0
      --- /dev/null
      +++ b/templates/plugins/opencontrail/ContrailPlugin.ini.j2
      @@ -0,0 +1,23 @@
      +# {{ ansible_managed }}
      +
      +{% if neutron_plugin_type == 'opencontrail' %}
      +[APISERVER]
      +api_server_ip = {{ opencontrail_api_vip_address }}
      +api_server_port = {{ opencontrail_api_vip_port }}
      +multi_tenancy = True
      +contrail_extensions = ipam:neutron_plugin_contrail.plugins.opencontrail.contrail_plugin_ipam.NeutronPluginContrailIpam,policy:neutron_plugin_contrail.plugins.opencontrail.contrail_plugin_policy.NeutronPluginContrailPolicy,route-table:neutron_plugin_contrail.plugins.opencontrail.contrail_plugin_vpc.NeutronPluginContrailVpc,contrail:None,service-interface:None,vf-binding:None
      +
      +[COLLECTOR]
      +analytics_api_ip = {{ opencontrail_collector_vip_address }}
      +analytics_api_port = {{ opencontrail_collector_vip_port }}
      +
      +[keystone_authtoken]
      +auth_host = {{ internal_lb_vip_address }}
      +auth_port = {{ keystone_service_port }}
      +auth_protocol = {{ keystone_service_proto }}
      +admin_user = {{ keystone_admin_user_name }}
      +admin_password = {{ keystone_auth_admin_password }}
      +admin_tenant_name = {{ keystone_admin_tenant_name }}
      +insecure = True
      +region_name = {{ keystone_service_region }}
      +{% endif %}
      

      对现有文件的更改包括:

      root@aio1:/etc/ansible/roles/os_neutron# git diff
      diff --git a/defaults/main.yml b/defaults/main.yml
      index 162e933..7054c96 100644
      --- a/defaults/main.yml
      +++ b/defaults/main.yml
      @@ -63,6 +63,8 @@ networking_bgpvpn_git_repo: https://git.openstack.org/openstack/networking-bgpvp
       networking_bgpvpn_git_install_branch: master
       openstack_ceilometer_git_repo: https://git.openstack.org/openstack/ceilometer
       openstack_ceilometer_git_install_branch: master
      +opencontrail_plugin_git_repo: https://github.com/Juniper/contrail-neutron-plugin
      +opencontrail_plugin_git_install_branch: master
      
       # Developer mode
       neutron_developer_mode: false
      @@ -164,6 +166,7 @@ neutron_sriov_nic_agent_ini_overrides: {}
       neutron_sriov_nic_agent_init_overrides: {}
       neutron_vpn_agent_init_overrides: {}
       neutron_vpnaas_agent_ini_overrides: {}
      +neutron_opencontrail_conf_ini_overrides: {}
      
       ###
       ### Quotas
      @@ -434,3 +437,12 @@ ovs_nsh_support: False
      
       # Set higher priority to mardim PPA when ovs_nsh_support is True
       ovs_nsh_apt_pinned_packages: [{ package: "*", release: "LP-PPA-mardim-mardim-ppa"}]
      +
      +###
      +### Contrail/OpenContrail/Tungsten Fabric Configuration
      +###
      +
      +opencontrail_api_vip_address: "{{ external_lb_vip_address }}"
      +opencontrail_api_vip_port: "8082"
      +opencontrail_collector_vip_address: "{{ external_lb_vip_address }}"
      +opencontrail_collector_vip_port: "8081"
      diff --git a/templates/neutron.conf.j2 b/templates/neutron.conf.j2
      index 83d25a7..dd755ca 100644
      --- a/templates/neutron.conf.j2
      +++ b/templates/neutron.conf.j2
      @@ -42,6 +42,10 @@ core_plugin = {{ neutron_plugin_core }}
       {% if neutron_plugin_type.split('.')[0] == 'ml2' %}
       service_plugins = {{ neutron_plugin_loaded_base | join(',') }}
       {% endif %}
      +{% if neutron_plugin_type == 'opencontrail' %}
      +service_plugins = neutron_plugin_contrail.plugins.opencontrail.loadbalancer.v2.plugin.LoadBalancerPluginV2
      +api_extensions_path = /openstack/venvs/neutron-{{ neutron_venv_tag }}/lib/python2.7/site-packages/neutron_plugin_contrail/extensions:/openstack/venvs/neutron-{{ neutron_venv_tag }}/lib/python2.7/site-packages/neutron_lbaas/extensions
      +{% endif %}
      
       # MAC address generation for VIFs
       base_mac = fa:16:3e:00:00:00
      @@ -94,8 +98,9 @@ rpc_workers = {{ neutron_rpc_workers }}
      
       {% set dhcp_agents_max = num_agent if num_agent > 2 else 2 %}
       # DHCP
      -{% if neutron_plugin_type == 'ml2.dragonflow' %}
      -# In dragonflow, DHCP is fully distributed, and DHCP agents are not used
      +{% if neutron_plugin_type == ('ml2.dragonflow' or 'opencontrail') %}
      +# In dragonflow and opencontrail, DHCP is fully distributed and DHCP
      +# agents are not used
       dhcp_agent_notification = False
       {% else %}
       dhcp_agent_notification = True
      diff --git a/vars/main.yml b/vars/main.yml
      index cef4ee8..2d1c2a2 100644
      --- a/vars/main.yml
      +++ b/vars/main.yml
      @@ -121,6 +121,10 @@ neutron_plugins:
           plugin_ini: plugins/ml2/ml2_conf.ini
           driver_interface: "openvswitch"
           l3_agent_mode: "legacy"
      +  opencontrail:
      +    plugin_core: neutron_plugin_contrail.plugins.opencontrail.contrail_plugin.NeutronPluginContrailCoreV2
      +    plugin_ini: plugins/opencontrail/ContrailPlugin.ini
      +    plugin_conf_ini_overrides: "{{ neutron_opencontrail_conf_ini_overrides }}"
      
       ###
       ### ML2 Plugin Configuration
      diff --git a/vars/source_install.yml b/vars/source_install.yml
      index a246a45..24e57ea 100644
      --- a/vars/source_install.yml
      +++ b/vars/source_install.yml
      @@ -96,6 +96,13 @@ neutron_proprietary_nuage_pip_packages:
         - nuage-openstack-neutronclient
         - nuagenetlib
      
      +neutron_optional_opencontrail_pip_packages:
      +  - bitarray
      +  - bottle
      +  - geventhttpclient
      +  - psutil>=0.6.0
      +  - requests>=1.1.0
      +
       neutron_developer_constraints:
         - "git+{{ neutron_git_repo }}@{{ neutron_git_install_branch }}#egg=neutron"
         - "git+{{ neutron_fwaas_git_repo }}@{{ neutron_fwaas_git_install_branch }}#egg=neutron-fwaas"
      

      os_nova

      root@aio1:/etc/ansible/roles/os_nova# git diff
      diff --git a/defaults/main.yml b/defaults/main.yml
      index 67d92e9..bc44511 100644
      --- a/defaults/main.yml
      +++ b/defaults/main.yml
      @@ -325,6 +325,9 @@ nova_network_services:
         calico:
           use_forwarded_for: True
           metadata_proxy_enabled: False
      +  opencontrail:
      +    use_forwarded_for: True
      +    metadata_proxy_enabled: True
      
       # Nova quota
       nova_quota_cores: 20
      

      HAproxy更改

      为了提供单一的TF API和仪表板终端,我决定创建一个VIP,以平衡TF API和analytics服务之间的流量。这是否为最佳做法还有待观察,但是此处对group_vars的更改有助于创建VIP:

      root@aio1:/opt/openstack-ansible# git diff
      diff --git a/inventory/group_vars/haproxy/haproxy.yml b/inventory/group_vars/haproxy/haproxy.yml
      index b837443..dc53ef4 100644
      --- a/inventory/group_vars/haproxy/haproxy.yml
      +++ b/inventory/group_vars/haproxy/haproxy.yml
      @@ -36,6 +36,7 @@ haproxy_rabbitmq_management_whitelist_networks: "{{ haproxy_whitelist_networks }
       haproxy_repo_git_whitelist_networks: "{{ haproxy_whitelist_networks }}"
       haproxy_repo_cache_whitelist_networks: "{{ haproxy_whitelist_networks }}"
       haproxy_opendaylight_whitelist_networks: "{{ haproxy_whitelist_networks }}"
      +haproxy_opencontrail_whitelist_networks: "{{ haproxy_whitelist_networks }}"
      
       haproxy_default_services:
         - service:
      @@ -365,3 +366,23 @@ haproxy_default_services:
             haproxy_backend_httpcheck_options:
               - expect status 405
             haproxy_service_enabled: "{{ (groups['ceph-rgw'] is defined and groups['ceph-rgw'] | length > 0) or (ceph_rgws | length > 0) }}"
      +  - service:
      +      haproxy_service_name: opencontrail-api
      +      haproxy_backend_nodes: "{{ groups['opencontrail-api_hosts'] | default([]) }}"
      +      haproxy_bind: "{{ [opencontrail_api_vip_address] }}"
      +      haproxy_port: 8082
      +      haproxy_balance_type: tcp
      +      haproxy_timeout_client: 5000s
      +      haproxy_timeout_server: 5000s
      +      haproxy_whitelist_networks: "{{ haproxy_opencontrail_whitelist_networks }}"
      +      haproxy_service_enabled: "{{ neutron_plugin_type == 'opencontrail' }}"
      +  - service:
      +      haproxy_service_name: opencontrail-collector
      +      haproxy_backend_nodes: "{{ groups['opencontrail-analytics_hosts'] | default([]) }}"
      +      haproxy_bind: "{{ [opencontrail_collector_vip_address] }}"
      +      haproxy_port: 8081
      +      haproxy_balance_type: tcp
      +      haproxy_timeout_client: 5000s
      +      haproxy_timeout_server: 5000s
      +      haproxy_whitelist_networks: "{{ haproxy_opencontrail_whitelist_networks }}"
      +      haproxy_service_enabled: "{{ neutron_plugin_type == 'opencontrail' }}"
      

      我在All-in-One节点上使用此方法遇到的一些问题,包括HAproxy将VIP绑定到端口8081的能力。后来在过程中发现,Tungsten Fabric playbooks在0.0.0.0:8081上创建了一个侦听器,从而阻止了VIP绑定在同一端口上。这里的替代方法是注释掉该服务,或在部署HAproxy后将其禁用。对于HAproxy在不同节点上的多节点安装,可以保留它。最终,这两种服务的负载平衡可能无法实现,但我暂时将其保留。

      环境更改

      默认的Neutron env.d框架将部署原本没必要部署的Neutron代理容器。通过覆盖默认值,我们可以删除代理容器并定义一些新的组件:

      cat <> /etc/openstack_deploy/env.d/neutron.yml
      component_skel:
        neutron_server:
          belongs_to:
            - neutron_all
        opencontrail_vrouter:
          belongs_to:
          - neutron_all
        opencontrail_api:
          belongs_to:
          - neutron_all
        opencontrail_analytics:
          belongs_to:
          - neutron_all
      
      container_skel:
        neutron_agents_container:
          contains: {}
        opencontail-vrouter_container:
          belongs_to:
            - compute_containers
          contains:
            - opencontrail_vrouter
          properties:
            is_metal: true
        opencontrail-api_container:
          belongs_to:
            - opencontrail-api_containers
          contains:
            - opencontrail_api
          properties:
            is_metal: true
        opencontrail-analytics_container:
          belongs_to:
            - opencontrail-analytics_containers
          contains:
            - opencontrail_analytics
          properties:
            is_metal: true
        neutron_server_container:
            belongs_to:
              - network_containers
            contains:
              - neutron_server
      
      physical_skel:
        opencontrail-api_containers:
          belongs_to:
            - all_containers
        opencontrail-api_hosts:
          belongs_to:
            - hosts
        opencontrail-analytics_containers:
          belongs_to:
            - all_containers
        opencontrail-analytics_hosts:
          belongs_to:
            - hosts
      EOF
      

      在这一点上,我不确定所有这些更改都是必要的,以及方法是否正确,但目前暂时这样。
      在 openstack_user_config.yml文件中,我定义了两个新的组,以便能够在主机之间拆分API和Analytics服务。由于这是一个AlO节点,因此IP是相同的:

      opencontrail-api_hosts:
        aio1:
          ip: 172.29.236.100
      
      opencontrail-analytics_hosts:
        aio1:
          ip: 172.29.236.100
      

      Overrides

      对os_neutron角色的更改导致添加了新的默认值,并且还需要一些overrides。在user_variables.yml中添加了以下内容:

      neutron_plugin_type: opencontrail
      neutron_driver_quota: neutron_plugin_contrail.plugins.opencontrail.quota.driver.QuotaDriver
      opencontrail_plugin_git_install_branch: R5.0
      

      角色中指定的一些默认值包括:

      opencontrail_api_vip_address: "{{ external_lb_vip_address }}"
      opencontrail_api_vip_port: "8082"
      opencontrail_collector_vip_address: "{{ external_lb_vip_address }}"
      opencontrail_collector_vip_port: "8081"
      opencontrail_plugin_git_repo: https://github.com/Juniper/contrail-neutron-plugin
      opencontrail_plugin_git_install_branch: master
      neutron_opencontrail_conf_ini_overrides: {}
      

      最终要求仍尚未确定。

      运行OpenStack-Ansible playbooks

      至此,已经完成了对OpenStack-Ansible playbooks的大部分更改,并且可以部署OpenStack了:

      # cd /opt/openstack-ansible/playbooks
      # openstack-ansible setup-hosts.yml
      # openstack-ansible setup-infrastructure.yml
      # openstack-ansible setup-openstack.yml
      

      虽然Neutron会被下线,但在使用网络之前,还需要进行一些其它更改并部署Tungsten Fabric。可以使用Horizon,但可能无法完全发挥它的功能。
      接下来,我们必须要执行一些操作,包括克隆Juniper ansible playbook repo,设置overrides,以及运行这些playbooks,以安装Tungsten Fabric,并为与TF相关的服务overlay一些Docker容器。

      部署Tungsten Fabric

      到这里,我们已经部署了OpenStack,并且知道已实现的网络后端,但是该后端还不存在。Juniper提供的playbooks可以使用Docker容器部署Tungsten Fabric。这些相同的playbooks还可以部署基于Kolla的OpenStack版本,这是另一种OpenStack部署策略。在这里,我们实际上只需要与Tungsten Fabric相关的代码。
      为了实现一些更改,我克隆了repo,并进行了部署在基于OpenStack-Ansible的云上所需的必要更改。
      克隆repo:

      # git clone http://github.com/busterswt/contrail-ansible-deployer /opt/openstack-ansible/playbooks/contrail-ansible-deployer
      # cd /opt/openstack-ansible/playbooks/contrail-ansible-deployer
      # git checkout osa
      

      Overrides

      Juniper playbooks依赖于它们自己的清单和overrides,因此执行以下几步可能会感觉有些多余。我还没有重新编写playbooks以利用OpenStack-Ansible的可用清单。
      可以在/etc/openstack_deploy/user_opencontrail_vars.yml的新文件中定义这些overrides:

      config_file: /etc/openstack_deploy/user_opencontrail_vars.yml
      opencontrail_api_vip_address: ""
      opencontrail_collector_vip_address: ""
      provider_config:
        bms:
          ssh_pwd:
          ssh_user: root
          ssh_public_key: /root/.ssh/id_rsa.pub
          ssh_private_key: /root/.ssh/id_rsa
          ntpserver: 129.6.15.28
      instances:
        aio1:
          provider: bms
          ip: 172.29.236.100
          roles:
            config_database:
            config:
            control:
            analytics_database:
            analytics:
            webui:
            vrouter:
      	    VROUTER_GATEWAY: 10.50.0.1
      		PHYSICAL_INTERFACE: ens160
      global_configuration:
        CONTAINER_REGISTRY: opencontrailnightly
      #  CONTAINER_REGISTRY: hub.juniper.net/contrail
      #  CONTAINER_REGISTRY_USERNAME: 
      #  CONTAINER_REGISTRY_PASSWORD: 
      contrail_configuration:
        CLOUD_ORCHESTRATOR: openstack
        CONTRAIL_VERSION: latest
      #  CONTRAIL_VERSION: 5.0.0-0.40
      # UPGRADE_KERNEL: true
        UPGRADE_KERNEL: false
        KEYSTONE_AUTH_HOST: ""
        KEYSTONE_AUTH_PUBLIC_PORT: 5000
        KEYSTONE_AUTH_PROTO: http
        KEYSTONE_AUTH_URL_VERSION:
        KEYSTONE_AUTH_ADMIN_USER: admin
        KEYSTONE_AUTH_ADMIN_PASSWORD: ""
        KEYSTONE_AUTH_URL_VERSION: /v3
        CONTROLLER_NODES: 172.29.236.100
        CONTROL_NODES: 172.29.236.100
        ANALYTICSDB_NODES: 172.29.236.100
        WEBUI_NODES: 172.29.236.100
        ANALYTICS_NODES: 172.29.236.100
        CONFIGDB_NODES: 172.29.236.100
        CONFIG_NODES: 172.29.236.100
      

      请特别注意以下键/值对:

      VROUTER_GATEWAY: 10.50.0.1
      PHYSICAL_INTERFACE: ens160
      
      CONTAINER_REGISTRY: opencontrailnightly
      #  CONTAINER_REGISTRY: hub.juniper.net/contrail
      #  CONTAINER_REGISTRY_USERNAME: 
      #  CONTAINER_REGISTRY_PASSWORD: 
      CONTRAIL_VERSION: latest
      #  CONTRAIL_VERSION: 5.0.0-0.40
      
      CONTROLLER_NODES: 172.29.236.100
      CONTROL_NODES: 172.29.236.100
      ANALYTICSDB_NODES: 172.29.236.100
      WEBUI_NODES: 172.29.236.100
      ANALYTICS_NODES: 172.29.236.100
      CONFIGDB_NODES: 172.29.236.100
      CONFIG_NODES: 172.29.236.100
      

      第一部分定义了vRouter所需的vhost0 接口将重新利用或者利用的“physical”接口。这是一个具有单个NIC的AIO节点,这意味着机会很不错,playbooks会自动确定要使用的接口。我们继续前进,同时在此处进行了标注。该主机的IP地址是10.50.0.221,网关是10.50.0.1。对于多宿主主机,有可能将接口及其自己的网关地址专用于vRouter。我尚未进行多NIC部署,但期待能实现。

      第二部分定义了将从中下载容器的Docker注册表。这里opencontailnightly 注册表包含每隔一到两天生成的容器,这些容器不一定在任何给定的日期都是有效的。如果你通过Juniper访问GA注册表,还可以定义该注册表并提供访问凭据。在nightly注册表中唯一可用的版本是latest版本,而Juniper注册表可能具有已标记的发行版。记得要使用适当的注册表。

      第三部分定义了各个节点类型的地址,用于在整个playbooks中用于将值插入模板。这些是当前成功完成playbooks所必需的。请注意,我在这里使用了“CONTAINER_NET”地址,是希望Tungsten Fabric和OpenStack可以在LXC使用的现有容器网络上进行通信。在此AIO节点中,172.29.236.100是br-mgmt上配置的IP,并且恰好也是内部VIP地址。部署在Docker容器中的服务会将端口绑定到其各自服务的IP上。在多节点的安装中,此更改的方式是否可行仍为待定。

      OSA repo更改

      OpenStack-Ansible包括用于软件包管理repo服务器,该服务器目前禁止安装部署Tungsten Fabric所需的某些版本的软件包。在这里,我通过修改/root/.pip/pip.conf禁用了内部repo服务器:

      [global]
      disable-pip-version-check = true
      timeout = 120
      #index-url = http://172.29.236.100:8181/simple
      #trusted-host =
      #        172.29.236.100
      
      [install]
      upgrade = true
      upgrade-strategy = only-if-needed
      pre = true
      

      运行playbooks

      到这里,我们应该有了一个很好的起点,可以开始运行TF playbooks了。
      首先,节点必须运行引导程序:

      # cd /opt/openstack-ansible/playbooks/
      # openstack-ansible -e orchestrator=openstack contrail-ansible-deployer/playbooks/configure_instances.yml
      

      当UPGRADE_KERNEL 为true时,主机可能会重新启动。如果发生这种情况,请再次重新运行该playbook。如果TF节点不是需要部署的主机,则playbooks具有一个计时器,等待主机返回。
      接下来,运行install_contrail.yml playbook以部署TF:

      # cd /opt/openstack-ansible/playbooks/
      # openstack-ansible -e orchestrator=openstack contrail-ansible-deployer/playbooks/install_contrail.yml
      

      安装其它组件

      由于Juniper playbooks期望基于Kolla的部署,因此某些组件未安装在基于OpenStack-Ansible的云之上。我自己从Docker容器中提取了一些实用程序、模块,以及更多的内容,并编写了一个playbook来实现这些内容:

      # cd /opt/openstack-ansible/playbooks/
      # openstack-ansible contrail-ansible-deployer/playbooks/install_contrailtools.yml
      

      重启

      一旦TF完成部署,vRouter内核模块已编译并插入后,可能有必要重启主机以清除vRouter代理容器内遇到的一些问题,包括:

      contrail-vrouter-agent: controller/src/vnsw/agent/vrouter/ksync/ksync_memory.cc:107: void KSyncMemory::Mmap(bool): Assertion `0' failed.
      /entrypoint.sh: line 304: 28142 Aborted                 (core dumped) $@
      

      我发现在安装后重新启动主机,足以解决这些问题。

      部署后的工作

      现在我们已经安装了Tungsten Fabric,可以使用 contrail-status命令检查服务的状态:

      root@aio1:/opt/openstack-ansible/playbooks# contrail-status
      Pod        Service         Original Name                          State    Status
      analytics  api             contrail-analytics-api                 running  Up 21 minutes
      analytics  collector       contrail-analytics-collector           running  Up 21 minutes
      analytics  nodemgr         contrail-nodemgr                       running  Up 21 minutes
      analytics  query-engine    contrail-analytics-query-engine        running  Up 21 minutes
      config     api             contrail-controller-config-api         running  Up 24 minutes
      config     cassandra       contrail-external-cassandra            running  Up 27 minutes
      config     device-manager  contrail-controller-config-devicemgr   running  Up 24 minutes
      config     nodemgr         contrail-nodemgr                       running  Up 24 minutes
      config     rabbitmq        contrail-external-rabbitmq             running  Up 27 minutes
      config     schema          contrail-controller-config-schema      running  Up 24 minutes
      config     svc-monitor     contrail-controller-config-svcmonitor  running  Up 24 minutes
      config     zookeeper       contrail-external-zookeeper            running  Up 27 minutes
      control    control         contrail-controller-control-control    running  Up 23 minutes
      control    dns             contrail-controller-control-dns        running  Up 23 minutes
      control    named           contrail-controller-control-named      running  Up 23 minutes
      control    nodemgr         contrail-nodemgr                       running  Up 23 minutes
      database   cassandra       contrail-external-cassandra            running  Up 22 minutes
      database   nodemgr         contrail-nodemgr                       running  Up 22 minutes
      database   zookeeper       contrail-external-zookeeper            running  Up 22 minutes
      vrouter    agent           contrail-vrouter-agent                 running  Up 19 minutes
      vrouter    nodemgr         contrail-nodemgr                       running  Up 19 minutes
      webui      job             contrail-controller-webui-job          running  Up 23 minutes
      webui      web             contrail-controller-webui-web          running  Up 23 minutes
      
      vrouter kernel module is PRESENT
      == Contrail control ==
      control: active
      nodemgr: active
      named: active
      dns: active
      
      == Contrail database ==
      nodemgr: active
      zookeeper: active
      cassandra: active
      
      == Contrail analytics ==
      nodemgr: active
      api: initializing (UvePartitions:UVE-Aggregation[Partitions:0] connection down)
      collector: initializing (KafkaPub:172.29.236.100:9092 connection down)
      query-engine: active
      
      == Contrail webui ==
      web: active
      job: active
      
      == Contrail vrouter ==
      nodemgr: active
      agent: active
      
      == Contrail config ==
      api: active
      zookeeper: active
      svc-monitor: active
      nodemgr: active
      device-manager: active
      cassandra: active
      rabbitmq: active
      schema: active
      

      如果看到nodemgr 服务处于Initializing 状态(NTP状态未同步),请尝试重启主机上的NTP。你可能需要定义多个NTP服务器。我尚未解决Analytics的问题,希望能尽快解决。

      一些问题

      我想说的是,到这里一切都应该可以正常进行了,但事实并非如此!使用OpenStack或Neutron客户端可能无法正常工作,因为neutron-server服务可能因以下错误而运行失败:

      Unrecoverable error: please check log for details.: ExtensionsNotFound: Extensions not found: ['route-table']. Related to WARNING neutron.api.extensions [-] Extension file vpcroutetable.py wasn't loaded due to cannot import name attributes.
      

      在Rocky中,一个TF插件所依赖而被OpenStack弃用的模块被删除了。不要担心,它只是移动到了另一个模块/文件中。
      在 neutron_server容器中,我修改了/openstack/venvs/neutron-18.0.0.0b3/lib/python2.7/site-packages/neutron_plugin_contrail/extensions/vpcroutetable.py文件,如下所示:

      -from neutron.api.v2 import attributes as attr
      +from neutron_lib.api import attributes as attr
      

      需要重新启动neutron-server服务:

      # systemctl restart neutron-server
      

      如何在OpenStack-Ansible上集成Tungsten Fabric(下)

      posted in 博客
      B
      bing
    • Tungsten Fabric:为云网络而生的SDN控制器

      本文作者Farzaneh Pakzad是云解决方案服务商Aptira的网络顾问,拥有美国昆士兰大学软件定义网络博士学位。她的研究领域专注在SDN、云计算和网络安全方面,曾为澳大利亚电信巨头提供SDN传输、部署、SD-WAN等解决方案的咨询服务。2019年,Farzaneh对最受欢迎的几个开源SDN控制器进行了比较,评级和评估,帮助机构选择适合其网络设计和要求的平台,引发业界关注。

      d39a500c-4db2-4eb7-bd8b-001f0063859f-image.png
      在当前的IT市场中,组织正将其旧的基础设施迁移到云上,其基础设施的每个部分都在向云化的方向发展。因此,我们有必要来看一下为云级网络(cloud-grade network)而生的SDN控制器,其中一个就是Tungsten Fabric(TF)。

      对于云的构建者和云原生平台的工程师来说,TF是一个合适的选择,它由Juniper开源项目OpenContrail发展而来,现在迁移到了Linux基金会(Linux Foundation)下面。

      体系结构

      Tungsten Fabrics架构包含两个主要的软件组件:TF vRouter和TF Controller。
      4fbeac6d-0976-4c46-8118-d10ed552b651-image.png
      TF vRouter用于数据包转发,并将网络和安全策略应用于网络中的设备。
      •vRouter需要在网络中的每个主机或计算节点中运行。它取代了Linux桥接器和传统路由堆栈IP表,或者在计算主机上联网的OpenVSwitch。
      •TF Controller通过可扩展消息传递和协议(XMPP)与vRouters通信,以应用所需的网络和安全策略。

      TF Controllers包含以下软件服务:
      •用于与vRouter通信并维护网络拓扑和网络策略的Control和Configuration服务。
      •用于遥测和故障排除的Analytics服务。
      •用于与用户交互的Web UI服务。
      •最后,提供与私有云和公共云、CNI插件、虚拟机和裸机集成的服务。

      在Tungsten Fabric 5.0及更高版本上,其体系架构使用基于Docker容器的微服务(如下图所示)以部署上述服务。这使得控制器在用户体验方面具有抵御故障的弹性,并提供高可用性。
      9a1e3379-fa50-4ec4-83da-41b0e62841cc-image.png

      模块化和可扩展性

      基于TF微服务的体系架构,允许根据性能要求和持续增加的负载来开发特定的服务。同样,微服务本质上是模块化的,这使得平台的维护和可扩展性变得简单,同时也将服务的故障相互隔离开。

      可扩容性

      集群的可扩容性
      •TF以模块化方式实现集群的可扩容性。这意味着可以通过为相关角色添加更多节点从而水平扩展每个TF角色的节点数量。而且,每个节点的Pod数量是可扩容的。通过利用Zookeeper来选择活动节点,而根据Zookeeper算法的性质,在Controller和Analytics节点中部署的Pod数量必须为奇数。

      架构的可扩容性
      •TF支持BGP协议,每个TF controller都可以通过BGP协议连接到其它controller。这意味着TF可用于连接不同的SDN岛。

      接口

      •南向:TF使用XMPP协议与vRouters(数据平面)进行通信,以提供overlay SDN解决方案。BPG还可以用于与旧设备进行通信。
      •北向:TF支持Web GUI和RESTful API。插件与其它平台集成,例如编排器、云和OSS/BSS等。

      遥测

      Analytics节点从基础设施中提取可用的遥测信息。随后,可以将数据标准化为通用格式,通过Kafka服务将输出发送到Cassandra数据库中。从问题解决到容量规划,可以以多种方式使用此数据。Redis使用该数据生成图形和运行查询。Redis pod部署在Analytics pod和Web UI pod之间。

      弹性和容错能力

      Tungsten Fabric的模块化体系架构使其具有抵御故障的弹性,通常在多个服务器上运行多个Controller/Pod以实现高可用性。并且,服务的故障是被隔离的,不会影响到整个系统。通过负载均衡器,TF可以访问API和Web GUI服务。负载均衡器可以允许Pod位于不同的子网中。

      编程语言

      TF支持C++、Python、Go、Node.js。

      社区

      TF最初与Juniper相关联,现在得到Linux Foundation Networking umbrella的支持,拥有庞大的开发人员和用户社区。

      总结

      可以给出这样的评价:TF是云的构建者和云原生平台工程师的合适选择。因为它可以与私有云和公共云、CNI插件、虚拟机和裸机等,灵活地协同工作。

      通过其所集成的编排器,它公开Heat API、Kubernetes API等以实例化网络和安全策略。TF的可扩展性使其具有高可用性,并且能够抵御故障,从而增加了客户的用户体验。

      最后,它的模块化功能使用户可以轻松而又独立地自定义、读取、测试和维护每个模块。

      作者:Farzaneh Pakzad 译者:TF编译组

      原文链接:
      https://aptira.com/comparison-of-software-defined-networking-sdn-controllers-part-8-tungsten-fabric/

      posted in 博客
      B
      bing