1. 程式人生 > >深入理解openstack網路架構(2)----Basic Use Cases

深入理解openstack網路架構(2)----Basic Use Cases

在上一篇文章中,我們瞭解了幾個網路元件,如openvswitch/network namespace/Linux bridges/veth pairs。這篇文章中,我們將用3個簡單的use case,展示這些基本網路元件如何以工作從而實現openstack的SDN方案。
在這些use case中,我們會了解整個網路配置和他們如何一起執行。use case如下:

  1. 建立網路——我們建立網路時,發生了什麼。如何建立多個隔離的網路。
  2. 建立虛擬機器——一旦我們有了網路,我們可以建立虛擬機器並將其接入網路。
  3. 虛擬機器的DHCP請求——opensack可以自動為虛擬機器配置IP。通過openstack neutron控制的DHCP服務完成。我們來了解這個服務如何執行,DHCP請求和迴應是什麼樣子的?

這篇文章中,我們會展示網路連線的原理,我們會了解網路包如何從A到B。我們先了解已經完成的網路配置是什麼樣子的?然後我們討論這些網路配置是如何以及何時建立的?我個人認為,通過例子和具體實踐看到真實的網路介面如何工作以及如何將他們連線起來是非常有價值的。然後,一切真相大白,我們知道網路連線如何工作,在後邊的文章中,我將進一步解釋neutron如何配置這些元件,從而提供這樣的網路連線能力。

我推薦在你自己的環境上嘗試這些例子或者使用Oracle Openstack Tech Preview。完全理解這些網路場景,對我們調查openstack環境中的網路問題非常有幫助。

Use case #1: Create Network

建立network的操作非常簡單。我們可以使用GUI或者命令列完成。openstack的網路僅供建立該網路的租戶使用。當然如果這個網路是“shared”,它也可以被其他所有租戶使用。一個網路可以有多個subnets,但是為了演示目的和簡單,我們僅為每一個network建立一個subnet。通過命令列建立network: 

# neutron net-create net1

Created a new network:

+---------------------------+--------------------------------------+

| Field                     | Value                                |

+---------------------------+--------------------------------------+

| admin_state_up            | True                                 |

| id                        | 5f833617-6179-4797-b7c0-7d420d84040c |

| name                      | net1                                 |

| provider:network_type     | vlan                                 |

| provider:physical_network | default                              |

| provider:segmentation_id  | 1000                                 |

| shared                    | False                                |

| status                    | ACTIVE                               |

| subnets                   |                                      |

| tenant_id                 | 9796e5145ee546508939cd49ad59d51f     |

+---------------------------+--------------------------------------+

為這個network建立subnet::
# neutron subnet-create net1 10.10.10.0/24

Created a new subnet:

+------------------+------------------------------------------------+

| Field            | Value                                          |

+------------------+------------------------------------------------+

| allocation_pools | {"start": "10.10.10.2", "end": "10.10.10.254"} |

| cidr             | 10.10.10.0/24                                  |

| dns_nameservers  |                                                |

| enable_dhcp      | True                                           |

| gateway_ip       | 10.10.10.1                                     |

| host_routes      |                                                |

| id               | 2d7a0a58-0674-439a-ad23-d6471aaae9bc           |

| ip_version       | 4                                              |

| name             |                                                |

| network_id       | 5f833617-6179-4797-b7c0-7d420d84040c           |

| tenant_id        | 9796e5145ee546508939cd49ad59d51f               |

+------------------+------------------------------------------------+


現在我們有了一個network和subnet,網路拓撲像這樣:


horizon_network

現在讓我們深入看下到底發生了什麼?在控制節點,我們一個新的namespace被建立: 

# ip netns list

qdhcp-5f833617-6179-4797-b7c0-7d420d84040c


這個namespace的名字是qdhcp- (參見上邊),讓我們深入namespace中看看有什麼?

# ip netns exec qdhcp-5f833617-6179-4797-b7c0-7d420d84040c ip addr

1: lo:  mtu 65536 qdisc noqueue state UNKNOWN

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

    inet 127.0.0.1/8 scope host lo

    inet6 ::1/128 scope host

       valid_lft forever preferred_lft forever

12: tap26c9b807-7c:  mtu 1500 qdisc noqueue state UNKNOWN

    link/ether fa:16:3e:1d:5c:81 brd ff:ff:ff:ff:ff:ff

    inet 10.10.10.3/24 brd 10.10.10.255 scope global tap26c9b807-7c

    inet6 fe80::f816:3eff:fe1d:5c81/64 scope link

       valid_lft forever preferred_lft forever


我們發下在namespace下有兩個網路介面,一個是loop裝置,另一個叫“tap26c9b807-7c”。這個介面設定了IP地址10.10.10.3,他會接收dhcp請求(後邊會講)。接下來我們來跟蹤下“tap26c9b807-7c”的網路連線性。我們從OVS上看下這個介面所連線的OVS網橋"br-int"。

# ovs-vsctl show
8a069c7c-ea05-4375-93e2-b9fc9e4b3ca1
    Bridge "br-eth2"
        Port "br-eth2"
            Interface "br-eth2"
                type: internal
        Port "eth2"
            Interface "eth2"
        Port "phy-br-eth2"
            Interface "phy-br-eth2"
    Bridge br-ex
        Port br-ex
            Interface br-ex
                type: internal
    Bridge br-int
        Port "int-br-eth2"
            Interface "int-br-eth2"
        Port "tap26c9b807-7c"
            tag: 1
            Interface "tap26c9b807-7c"
                type: internal
        Port br-int
            Interface br-int
                type: internal
    ovs_version: "1.11.0"

由上可知,veth pair的兩端“int-br-eth2” 和 "phy-br-eth2",這個veth pari連線兩個OVS網橋"br-eth2"和"br-int"。上一篇文章中,我們解釋過如何通過ethtool命令檢視veth pairs的兩端。就如下邊的例子:

# ethtool -S int-br-eth2
NIC statistics:
     peer_ifindex: 10
.
.
 
#ip link
.
.
10: phy-br-eth2:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
.
.

注意“phy-br-eth2”連線到網橋"br-eth2",這個網橋的一個網口是物理網絡卡eth2。這意味著我們建立的網路建立了一個連線到了物理網絡卡eth2的namespace。eth2所在的虛擬機器網路會連線所有的虛擬機器的。

關於網路隔離:

Openstack支援建立多個隔離的網路,也可以使用多種機制完成網路間的彼此隔離。這些隔離機制包括VLANs/VxLANs/GRE tunnels,這個在我們部署openstack環境時配置。本文中我們選擇了VLANs。當使用VLAN標籤作為隔離機制,Neutron會從預定義好的VLAN池中選擇一個VLAN標籤,並分配給一個新建立的network。通過分配VLAN標籤給network,Neutron允許在一個物理網絡卡上建立多個隔離的網路。與其他的平臺的最大的區別是,使用者不需要負責管理VLAN如何分配給networks。Neutron會負責管理分配VLAN標籤,並負責回收。在我們的例子中,net1使用VLAN標籤1000,這意味著連線到該網路的虛擬機器,發出的包會被打上VLAN標籤1000然後傳送到物理網路中。對namespace也是同樣的,如果我們希望namespace連線到某個特定網路,我們需要確保這個namespace發出的/接收的包被正確的打上了標籤。

在上邊的例子中,namespace中的網路介面“tap26c9b807-7c”被分配了VLAN標籤1。如果我們從OVS觀察下,會發現VLAN1會被改為VLAN1000,當包進入eth2所在的uxniji網路。反之亦然。我們通過OVS的dump-flows命令可以看到進入虛擬機器網路的網路包在br-eth2上進行了VLAN標籤的修改:

#  ovs-ofctl dump-flows br-eth2
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=18669.401s, table=0, n_packets=857, n_bytes=163350, idle_age=25, priority=4,in_port=2,dl_vlan=1 actions=mod_vlan_vid:1000,NORMAL
 cookie=0x0, duration=165108.226s, table=0, n_packets=14, n_bytes=1000, idle_age=5343, hard_age=65534, priority=2,in_port=2 actions=drop
 cookie=0x0, duration=165109.813s, table=0, n_packets=1671, n_bytes=213304, idle_age=25, hard_age=65534, priority=1 actions=NORMAL


從網路介面到namespace我們看到VLAN標籤的修改如下:

#  ovs-ofctl dump-flows br-int
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=18690.876s, table=0, n_packets=1610, n_bytes=210752, idle_age=1, priority=3,in_port=1,dl_vlan=1000 actions=mod_vlan_vid:1,NORMAL
 cookie=0x0, duration=165130.01s, table=0, n_packets=75, n_bytes=3686, idle_age=4212, hard_age=65534, priority=2,in_port=1 actions=drop
 cookie=0x0, duration=165131.96s, table=0, n_packets=863, n_bytes=160727, idle_age=1, hard_age=65534, priority=1 actions=NORMAL

總之,當用戶建立network,neutrong會建立一個namespace,這個namespace通過OVS連線到虛擬機器網路。OVS還負責namespace與虛擬機器網路之間VLAN標籤的修改。現在,讓我們看下建立虛擬機器時,發生了什麼?虛擬機器是怎麼連線到虛擬機器網路的?

Use case #2: Launch a VM

從Horizon或者命令列建立並啟動一個虛擬機器,下圖是從Horzion建立的例子:

launch-instance


掛載網路並啟動虛擬機器:

attach-network
一旦虛擬機器啟動並執行,我們發下nova支援給虛擬機器繫結IP:

# nova list
+--------------------------------------+--------------+--------+------------+-------------+-----------------+
| ID                                   | Name         | Status | Task State | Power State | Networks        |
+--------------------------------------+--------------+--------+------------+-------------+-----------------+
| 3707ac87-4f5d-4349-b7ed-3a673f55e5e1 | Oracle Linux | ACTIVE | None       | Running     | net1=10.10.10.2 |
+--------------------------------------+--------------+--------+------------+-------------+-----------------+

nova list命令顯示虛擬機器在執行中,並被分配了IP 10.10.10.2。我們通過虛擬機器定義檔案,檢視下虛擬機器與虛擬機器網路之間的連線性。虛擬機器的配置檔案在目錄/var/lib/nova/instances//下可以找到。通過檢視虛擬機器定義檔案,libvirt.xml,我們可以看到虛擬機器連線到網路介面“tap53903a95-82”,這個網路介面連線到了Linux網橋 “qbr53903a95-82”:

<interface type="bridge">
      <mac address="fa:16:3e:fe:c7:87"/>
      <source bridge="qbr53903a95-82"/>
      <target dev="tap53903a95-82"/>
    </interface>

通過brctl檢視網橋資訊如下:
# brctl show
bridge name     bridge id               STP enabled     interfaces
qbr53903a95-82          8000.7e7f3282b836       no              qvb53903a95-82
                                                        tap53903a95-82

網橋有兩個網路介面,一個連線到虛擬機器(“tap53903a95-82 “),另一個( “qvb53903a95-82”)連線到OVS網橋”br-int"。

 # ovs-vsctl show
83c42f80-77e9-46c8-8560-7697d76de51c
    Bridge "br-eth2"
        Port "br-eth2"
            Interface "br-eth2"
                type: internal
        Port "eth2"
            Interface "eth2"
        Port "phy-br-eth2"
            Interface "phy-br-eth2"
    Bridge br-int
        Port br-int
            Interface br-int
                type: internal
        Port "int-br-eth2"
            Interface "int-br-eth2"
        Port "qvb53903a95-82"
            tag: 3
            Interface "qvb53903a95-82"
    ovs_version: "1.11.0"

我們之前看過,OVS網橋“br-int"連線到"br-eth2",通過veth pair(int-br-eth2,phy-br-eth2 ),br-eth2連線到物理網絡卡eth2。整個流入如下:
VM  ->  tap53903a95-82 (virtual interface)  ->  qbr53903a95-82 (Linux bridge)  ->  qvb53903a95-82 (interface connected from Linux bridge to OVS bridge br-int)  ->  int-br-eth2 (veth one end)  ->  phy-br-eth2 (veth the other end)  ->  eth2 physical interface.

與虛擬機器相連的Linux bridage主要用於基於Iptables的安全組設定。安全組用於對虛擬機器的網路隔離進行增強,由於iptables不能用於OVS網橋,因此我們使用了Linux網橋。後邊我們會看到Linux網橋的規則設定。

VLAN tags:我們在第一個use case中提到過,net1使用VLAN標籤1000,通過OVS我們看到qvo41f1ebcf-7c使用VLAN標籤3。VLAN標籤從3到1000的轉換在OVS中完成,通過br-eth2中實現。 總結如下,虛擬機器通過一組網路裝置連入虛擬機器網路。虛擬機器和網路之間,VLAN標籤被修改。

Use case #3: Serving a DHCP request coming from the virtual machine

之前的use case中,我們看到了一個叫dhcp-的namespace和虛擬機器,兩者最終連線到物理網路eth2。他們都會被打上VLAN標籤1000。我們看到該namespace中的網路介面使用IP 10.10.10.3。因為虛擬機器和namespace彼此連線並在相同子網,因此可以ping到對方。如下圖,虛擬機器中網路介面被分配了IP 10.10.10.2,我們嘗試ping namespace中的網路介面的IP:
vm-console

namespace與虛擬機器之間連通,並且可以互相ping通,對於定位問題非常有用。我們可以從虛擬機器ping通namespace,可以使用tcpdump或其他工具定位網路中斷問題。

dnsmasq --no-hosts --no-resolv --strict-order --bind-interfaces --interface=tap26c9b807-7c --except-interface=lo --pid-file=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/pid --dhcp-hostsfile=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/host --dhcp-optsfile=/var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/opts --leasefile-ro --dhcp-range=tag0,10.10.10.0,static,120s --dhcp-lease-max=256 --conf-file= --domain=openstacklocal


DHCP服務在namespace中連線到了一個tap介面(“--interface=tap26c9b807-7c”),從hosts檔案我們可以看到:

# cat  /var/lib/neutron/dhcp/5f833617-6179-4797-b7c0-7d420d84040c/host
fa:16:3e:fe:c7:87,host-10-10-10-2.openstacklocal,10.10.10.2

之前的console輸出可以看到虛擬機器MAC為fa:16:3e:fe:c7:87 。這個mac地址與IP 10.10.10.2 關聯,當包含該MAC的DHCP請求到達,dnsmasq返回10.10.10.2。在這個初始過程(可以重啟網路服務觸發)中從namespace中看,可以看到如下的DHCP請求:
# ip netns exec qdhcp-5f833617-6179-4797-b7c0-7d420d84040c tcpdump -n
19:27:12.191280 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from fa:16:3e:fe:c7:87, length 310
19:27:12.191666 IP 10.10.10.3.bootps > 10.10.10.2.bootpc: BOOTP/DHCP, Reply, length 325

總之,DHCP服務由dnsmasq提供,這個服務由Neutron配置,監聽在DHCP namespace中的網路介面上。Neutron還配置dnsmasq中的MAC/IP對映關係,所以當DHCP請求時會受到分配給它的IP。

總結

本文,我們基於之前講解的各種網路元件,分析了三種use case下網路如何連通的。這些use cases對了解整個網路棧以及瞭解虛擬機器/計算節點/DHCP namespace直接如何連通很有幫助。
根據我們的分析,我們確信啟動虛擬機器、虛擬機發出DHCP請求、虛擬機器收到正確的IP後這個網路按照我們預想的工作。我們看到一個包經過一長串路徑最終到達目的地,如果這一切成功,意味著這些元件功能正常。
下一篇文章中,我們會學習更復雜的neutron服務並分析他們如何工作。