Group Details Private

administrators

Member List

  • 要在数据中心实现快速收敛?你需要一个快速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 博客
  • 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 博客
  • 为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 博客
  • 洞察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 博客
  • 通过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 博客
  • 共创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 博客
  • 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 博客
  • 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 博客
  • 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 博客
  • 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 博客