Open vSwitch: 使用 VRRP 实现高可用性

此架构示例通过 keepalived 使用虚拟路由器冗余协议 (VRRP) 增强了自助服务部署示例,并为自助服务网络提供路由故障转移。由于 VRRP 为每个路由器创建了一个主 (活动) 实例和至少一个备份实例,因此需要至少两个网络节点。

在正常操作期间,特定项目的所有 VRRP 路由器连接的隐藏网络上的 keepalived 在主路由器上定期传输 *心跳* 数据包。使用 VRRP 路由器的每个项目使用单独的隐藏网络。默认情况下,此网络使用 ml2_conf.ini 文件中的 tenant_network_types 选项中的第一个值。为了获得更多控制,您可以使用 neutron.conf 文件中的 l3_ha_network_typel3_ha_network_name 选项指定隐藏网络的自助服务网络类型和物理网络名称。

如果备份路由器上的 keepalived 停止接收 *心跳* 数据包,则它假定主路由器发生故障,并通过在 qrouter 命名空间中的接口上配置 IP 地址来将备份路由器提升为主路由器。在具有多个备份路由器的环境中,优先级最高的备份路由器上的 keepalived 会将该备份路由器提升为主路由器。

注意

此高可用性机制使用相同的优先级为所有路由器配置 VRRP。因此,VRRP 将 IP 地址最高的备份路由器提升为主路由器。

警告

keepalived v1.2.15 及更早版本中存在一个已知错误,该错误可能导致在将 max_l3_agents_per_router 设置为 3 或更多时发生数据包丢失。因此,我们建议您在使用此功能时升级到 keepalived v1.2.16 或更高版本。

网络节点之间的 VRRP *心跳* 流量中断,通常是由于网络接口或物理网络基础设施故障造成的,会触发故障转移。重新启动第 3 层代理,或其故障,不会触发故障转移,前提是 keepalived 继续运行。

考虑此高可用性机制的以下属性,以确定其在您的环境中的实用性

  • 使用特定路由器进行自助服务网络的实例网络流量仅遍历该路由器的活动实例。因此,特定网络节点的资源限制可能会影响该网络节点上所有路由器的活动实例,而不会触发故障转移到另一个网络节点。但是,您可以配置调度器将每个路由器的活动实例均匀地分布在网络节点池中,以减少任何特定网络节点上资源争用的可能性。

  • 仅支持使用路由器的自助服务网络。提供商网络在第 2 层运行,并依赖物理网络基础设施来实现冗余。

  • 对于具有浮动 IPv4 地址的实例,由于 1:1 静态 NAT 的副作用,在故障转移期间会维护网络连接的状态。该机制实际上并未实现连接跟踪。

对于生产部署,我们建议至少使用三个网络节点,并提供足够的资源来处理整个环境的网络流量(如果一个网络节点发生故障)。此外,剩余的两个节点可以继续提供冗余。

先决条件

添加具有以下组件的网络节点

  • 三个网络接口:管理、提供商和叠加。

  • OpenStack Networking 第 2 层代理、第 3 层代理及其依赖项。

注意

您可以将 DHCP 和元数据代理保留在每个计算节点上,或将它们移动到网络节点。

架构

High-availability using VRRP with Linux bridge - overview

下图显示了一个自助服务网络和一个未标记(扁平)网络的组件和连接。主路由器位于网络节点 1 上。在这种特定情况下,实例位于与网络 DHCP 代理相同的计算节点上。如果 DHCP 代理位于另一个计算节点上,则后者仅包含 DHCP 命名空间和与覆盖物理网络接口连接的 Linux 网桥。

High-availability using VRRP with Linux bridge - components and connectivity - one network

示例配置

使用以下示例配置作为模板,以向现有的支持自助服务网络的运行环境添加对使用 VRRP 实现高可用性的支持。

控制器节点

  1. neutron.conf 文件中

    • 启用 VRRP。

      [DEFAULT]
      l3_ha = True
      
  2. 重新启动以下服务

    • 服务器

网络节点 1

无更改。

网络节点 2

  1. 安装 Networking 服务 OVS 第 2 层代理和第 3 层代理。

  2. 安装 OVS。

  3. neutron.conf 文件中,配置常用选项

    [DEFAULT]
    core_plugin = ml2
    auth_strategy = keystone
    
    [database]
    # ...
    
    [keystone_authtoken]
    # ...
    
    [nova]
    # ...
    
    [agent]
    # ...
    

    请参阅您的 OpenStack 版本的 安装教程和指南配置参考,以获取 [DEFAULT][database][keystone_authtoken][nova][agent] 部分的适当附加配置。

  4. 启动以下服务

    • OVS

  5. 创建 OVS 提供商网桥 br-provider

    $ ovs-vsctl add-br br-provider
    
  6. 将提供商网络接口作为端口添加到 OVS 提供商网桥 br-provider

    $ ovs-vsctl add-port br-provider PROVIDER_INTERFACE
    

    PROVIDER_INTERFACE 替换为处理提供商网络的底层接口的名称。例如,eth1

  7. openvswitch_agent.ini 文件中,配置第 2 层代理。

    [ovs]
    bridge_mappings = provider:br-provider
    local_ip = OVERLAY_INTERFACE_IP_ADDRESS
    
    [agent]
    tunnel_types = vxlan
    l2_population = true
    
    [securitygroup]
    firewall_driver = iptables_hybrid
    

    OVERLAY_INTERFACE_IP_ADDRESS 替换为处理自助服务网络 VXLAN 覆盖的接口的 IP 地址。

  8. 启动以下服务

    • Open vSwitch 代理

    • 第 3 层代理

计算节点

无更改。

验证服务操作

  1. 获取管理项目凭据。

  2. 验证代理的存在和操作。

    $ openstack network agent list
    +--------------------------------------+--------------------+----------+-------------------+-------+-------+---------------------------+
    | ID                                   | Agent Type         | Host     | Availability Zone | Alive | State | Binary                    |
    +--------------------------------------+--------------------+----------+-------------------+-------+-------+---------------------------+
    | 1236bbcb-e0ba-48a9-80fc-81202ca4fa51 | Metadata agent     | compute2 | None              | True  | UP    | neutron-metadata-agent    |
    | 457d6898-b373-4bb3-b41f-59345dcfb5c5 | Open vSwitch agent | compute2 | None              | True  | UP    | neutron-openvswitch-agent |
    | 71f15e84-bc47-4c2a-b9fb-317840b2d753 | DHCP agent         | compute2 | nova              | True  | UP    | neutron-dhcp-agent        |
    | 8805b962-de95-4e40-bdc2-7a0add7521e8 | L3 agent           | network1 | nova              | True  | UP    | neutron-l3-agent          |
    | a33cac5a-0266-48f6-9cac-4cef4f8b0358 | Open vSwitch agent | network1 | None              | True  | UP    | neutron-openvswitch-agent |
    | a6c69690-e7f7-4e56-9831-1282753e5007 | Metadata agent     | compute1 | None              | True  | UP    | neutron-metadata-agent    |
    | af11f22f-a9f4-404f-9fd8-cd7ad55c0f68 | DHCP agent         | compute1 | nova              | True  | UP    | neutron-dhcp-agent        |
    | bcfc977b-ec0e-4ba9-be62-9489b4b0e6f1 | Open vSwitch agent | compute1 | None              | True  | UP    | neutron-openvswitch-agent |
    | 7f00d759-f2c9-494a-9fbf-fd9118104d03 | Open vSwitch agent | network2 | None              | True  | UP    | neutron-openvswitch-agent |
    | b28d8818-9e32-4888-930b-29addbdd2ef9 | L3 agent           | network2 | nova              | True  | UP    | neutron-l3-agent          |
    +--------------------------------------+--------------------+----------+-------------------+-------+-------+---------------------------+
    

创建初始网络

与自助服务部署示例类似,此配置支持多个 VXLAN 自助服务网络。启用高可用性后,所有其他路由器都使用 VRRP。以下过程创建一个额外的自助服务网络和路由器。Networking 服务还支持将高可用性添加到现有的路由器。但是,该过程需要管理性地禁用并启用每个路由器,这会暂时中断使用该路由器上接口的自助服务网络的网络连接。

  1. 获取常规(非管理)项目凭据。

  2. 创建一个自助服务网络。

    $ openstack network create selfservice2
    +-------------------------+--------------+
    | Field                   | Value        |
    +-------------------------+--------------+
    | admin_state_up          | UP           |
    | mtu                     | 1450         |
    | name                    | selfservice2 |
    | port_security_enabled   | True         |
    | router:external         | Internal     |
    | shared                  | False        |
    | status                  | ACTIVE       |
    +-------------------------+--------------+
    
  3. 在自助服务网络上创建一个 IPv4 子网。

    $ openstack subnet create --subnet-range 198.51.100.0/24 \
      --network selfservice2 --dns-nameserver 8.8.4.4 selfservice2-v4
    +-------------------+------------------------------+
    | Field             | Value                        |
    +-------------------+------------------------------+
    | allocation_pools  | 198.51.100.2-198.51.100.254  |
    | cidr              | 198.51.100.0/24              |
    | dns_nameservers   | 8.8.4.4                      |
    | enable_dhcp       | True                         |
    | gateway_ip        | 198.51.100.1                 |
    | ip_version        | 4                            |
    | name              | selfservice2-v4              |
    +-------------------+------------------------------+
    
  4. 在自助服务网络上创建一个 IPv6 子网。

    $ openstack subnet create --subnet-range fd00:198:51:100::/64 --ip-version 6 \
      --ipv6-ra-mode slaac --ipv6-address-mode slaac --network selfservice2 \
      --dns-nameserver 2001:4860:4860::8844 selfservice2-v6
    +-------------------+--------------------------------------------------------+
    | Field             | Value                                                  |
    +-------------------+--------------------------------------------------------+
    | allocation_pools  | fd00:198:51:100::2-fd00:198:51:100:ffff:ffff:ffff:ffff |
    | cidr              | fd00:198:51:100::/64                                   |
    | dns_nameservers   | 2001:4860:4860::8844                                   |
    | enable_dhcp       | True                                                   |
    | gateway_ip        | fd00:198:51:100::1                                     |
    | ip_version        | 6                                                      |
    | ipv6_address_mode | slaac                                                  |
    | ipv6_ra_mode      | slaac                                                  |
    | name              | selfservice2-v6                                        |
    +-------------------+--------------------------------------------------------+
    
  5. 创建一个路由器。

    $ openstack router create router2
    +-----------------------+---------+
    | Field                 | Value   |
    +-----------------------+---------+
    | admin_state_up        | UP      |
    | name                  | router2 |
    | status                | ACTIVE  |
    +-----------------------+---------+
    
  6. 将 IPv4 和 IPv6 子网作为接口添加到路由器。

    $ openstack router add subnet router2 selfservice2-v4
    $ openstack router add subnet router2 selfservice2-v6
    

    注意

    这些命令不提供任何输出。

  7. 将提供商网络作为路由器的网关添加。

    $ openstack router set --external-gateway provider1 router2
    

验证网络操作

  1. 获取管理项目凭据。

  2. 验证处理 VRRP *心跳* 流量的内部高可用性网络的创建。

    $ openstack network list
    +--------------------------------------+----------------------------------------------------+--------------------------------------+
    | ID                                   | Name                                               | Subnets                              |
    +--------------------------------------+----------------------------------------------------+--------------------------------------+
    | 1b8519c1-59c4-415c-9da2-a67d53c68455 | HA network tenant f986edf55ae945e2bef3cb4bfd589928 | 6843314a-1e76-4cc9-94f5-c64b7a39364a |
    +--------------------------------------+----------------------------------------------------+--------------------------------------+
    
  3. 在每个网络节点上,验证是否创建了具有相同 ID 的 qrouter 命名空间。

    网络节点 1

    # ip netns
    qrouter-b6206312-878e-497c-8ef7-eb384f8add96
    

    网络节点 2

    # ip netns
    qrouter-b6206312-878e-497c-8ef7-eb384f8add96
    

    注意

    由于在启用 VRRP 之前创建,因此 Open vSwitch: 自助服务网络 中的路由器 1 的命名空间应仅出现在网络节点 1 上。

  4. 在每个网络节点上,显示 qrouter 命名空间中接口的 IP 地址。除 VRRP 接口外,只有属于主路由器实例的一个命名空间包含接口上的 IP 地址。

    网络节点 1

    # ip netns exec qrouter-b6206312-878e-497c-8ef7-eb384f8add96 ip addr show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
        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
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    2: ha-eb820380-40@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:78:ba:99 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 169.254.192.1/18 brd 169.254.255.255 scope global ha-eb820380-40
           valid_lft forever preferred_lft forever
        inet 169.254.0.1/24 scope global ha-eb820380-40
           valid_lft forever preferred_lft forever
        inet6 fe80::f816:3eff:fe78:ba99/64 scope link
           valid_lft forever preferred_lft forever
    3: qr-da3504ad-ba@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:dc:8e:a8 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 198.51.100.1/24 scope global qr-da3504ad-ba
           valid_lft forever preferred_lft forever
        inet6 fe80::f816:3eff:fedc:8ea8/64 scope link
           valid_lft forever preferred_lft forever
    4: qr-442e36eb-fc@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:ee:c8:41 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fd00:198:51:100::1/64 scope global nodad
           valid_lft forever preferred_lft forever
        inet6 fe80::f816:3eff:feee:c841/64 scope link
           valid_lft forever preferred_lft forever
    5: qg-33fedbc5-43@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:03:1a:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 203.0.113.21/24 scope global qg-33fedbc5-43
           valid_lft forever preferred_lft forever
        inet6 fd00:203:0:113::21/64 scope global nodad
           valid_lft forever preferred_lft forever
        inet6 fe80::f816:3eff:fe03:1af6/64 scope link
           valid_lft forever preferred_lft forever
    

    网络节点 2

    # ip netns exec qrouter-b6206312-878e-497c-8ef7-eb384f8add96 ip addr show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
        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
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    2: ha-7a7ce184-36@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:16:59:84 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet 169.254.192.2/18 brd 169.254.255.255 scope global ha-7a7ce184-36
           valid_lft forever preferred_lft forever
        inet6 fe80::f816:3eff:fe16:5984/64 scope link
           valid_lft forever preferred_lft forever
    3: qr-da3504ad-ba@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:dc:8e:a8 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    4: qr-442e36eb-fc@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000
    5: qg-33fedbc5-43@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
        link/ether fa:16:3e:03:1a:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    

    注意

    主路由器可能位于网络节点 2 上。

  5. 启动一个具有附加自助服务网络接口的实例。例如,使用 flavor ID 1 的 CirrOS 镜像。

    $ openstack server create --flavor 1 --image cirros --nic net-id=NETWORK_ID selfservice-instance2
    

    NETWORK_ID 替换为附加自助服务网络的 ID。

  6. 确定实例的 IPv4 和 IPv6 地址。

    $ openstack server list
    +--------------------------------------+-----------------------+--------+----------------------------------------------------------------+--------+---------+
    | ID                                   | Name                  | Status | Networks                                                       | Image  | Flavor  |
    +--------------------------------------+-----------------------+--------+----------------------------------------------------------------+--------+---------+
    | bde64b00-77ae-41b9-b19a-cd8e378d9f8b | selfservice-instance2 | ACTIVE | selfservice2=fd00:198:51:100:f816:3eff:fe71:e93e, 198.51.100.4 | cirros | m1.tiny |
    +--------------------------------------+-----------------------+--------+----------------------------------------------------------------+--------+---------+
    
  7. 在提供商网络上创建一个浮动 IPv4 地址。

    $ openstack floating ip create provider1
    +-------------+--------------------------------------+
    | Field       | Value                                |
    +-------------+--------------------------------------+
    | fixed_ip    | None                                 |
    | id          | 0174056a-fa56-4403-b1ea-b5151a31191f |
    | instance_id | None                                 |
    | ip          | 203.0.113.17                         |
    | pool        | provider1                            |
    +-------------+--------------------------------------+
    
  8. 将浮动 IPv4 地址与实例关联。

    $ openstack server add floating ip selfservice-instance2 203.0.113.17
    

    注意

    此命令不会产生任何输出。

验证故障转移操作

  1. 开始持续 ping 实例的浮动 IPv4 地址和 IPv6 地址。在执行接下来的三个步骤时,您应该看到最少(如果有的话)的连接中断到实例。

  2. 在具有主路由器的网络节点上,管理性地禁用覆盖网络接口。

  3. 在另一个网络节点上,通过注意将 IP 地址添加到 qrouter 命名空间中的接口来验证备份路由器是否提升为主路由器。

  4. 在步骤 2 中的原始网络节点上,管理性地启用覆盖网络接口。请注意,主路由器仍然位于步骤 3 中的网络节点上。

Keepalived VRRP 健康检查

可以通过一个 bash 脚本自动监控您的 keepalived 实例的运行状况,该脚本会验证与所有可用和配置的网关地址的连接。如果连接丢失,则主路由器将被重新安排到另一个节点。

如果所有路由器同时失去连接,则选择新主路由器的过程将以轮询方式重复,直到一个或多个路由器的连接恢复为止。

要启用此功能,请编辑 l3_agent.ini 文件

ha_vrrp_health_check_interval = 30

其中 ha_vrrp_health_check_interval 指示应以秒为单位运行健康检查的频率。默认值为 0,表示不应运行检查。

网络流量流

此高可用性机制只是增强了 Open vSwitch: 自助服务网络,如果主路由器发生故障,则将第 3 层服务故障转移到另一个路由器。因此,您可以参考 自助服务网络流量流程 以了解正常操作。