Ocata上的Floating IP折騰記

背景

最近有個(gè)需求,需要把公網(wǎng)IP映射到虛擬機(jī)上。需求其實(shí)很簡(jiǎn)單,利用Neutron的原生FloatingIP功能就能解決,但是真正解決的時(shí)候還是耗了不少時(shí)間。大家都是知道公有云和私有云最本質(zhì)的區(qū)別不是虛擬化,也不是存儲(chǔ),而是網(wǎng)絡(luò)。公有云的網(wǎng)絡(luò)龐大而復(fù)雜,如何把公網(wǎng)IP正確的映射到用戶的虛擬機(jī)上,背后還是包含了眾多的網(wǎng)絡(luò)技術(shù)。對(duì)于大部分利用OpenStack搭建私有云的企業(yè),一般采用Flat和Vlan的組網(wǎng)模型,網(wǎng)關(guān)都在物理交換機(jī)上,很少利用L3-agent來做VRouter。所以網(wǎng)絡(luò)相對(duì)簡(jiǎn)單,排查起來也比較容易。我的也是基于Vlan的組網(wǎng)架構(gòu),在此基礎(chǔ)上創(chuàng)建VRouter來綁定FloatingIP。

經(jīng)過這兩天的折騰,終于把公網(wǎng)IP映射到虛擬機(jī)上,中途遇到不少坑,有自身原因也有OS本身的坑,總之沒有想象中的容易。

Tips:先聲明下Neutron的組網(wǎng)架構(gòu)不一致,最終效果也不一樣,本文內(nèi)容不做任何保證

操作

在操作之前簡(jiǎn)單介紹下我的環(huán)境,1臺(tái)控制+網(wǎng)絡(luò)節(jié)點(diǎn),9臺(tái)計(jì)算節(jié)點(diǎn)。由于映射公網(wǎng)IP地址需求比較少,L3-agent就只部署到網(wǎng)絡(luò)節(jié)點(diǎn)上。

網(wǎng)絡(luò)節(jié)點(diǎn)網(wǎng)卡分配如下:

網(wǎng)卡 IP 類型 用途
em1 10.17.64.1 普通 管理網(wǎng),Ceph PublicNet
em2 External Net Flat 公網(wǎng)
em3 Privite Net Vlan 虛擬機(jī)網(wǎng)絡(luò)
em4 10.17.70.1 普通 Ceph ClusterNet

Neutron支持的服務(wù)如下:

[DEFAULT]
service_plugins=neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2,router,metering,firewall,neutron.services.qos.qos_plugin.QoSPlugin

[service_providers]
service_provider=LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
service_provider=FIREWALL:Iptables:neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver:default

這里面包括LBAAS,F(xiàn)WAAS,ROUTER和QOS等特性。

ml2_conf.ini

ml2沒什么的改的,只需要在加載ml2驅(qū)動(dòng)的時(shí)候包含vlan和falt就可以了,在這里配置

[ml2]
type_drivers = vlan,flat

還需要定義一下flat的網(wǎng)絡(luò)類型

[ml2_type_flat]
flat_networks = external
l3_agent.ini

l3的坑多,最開始我用的默認(rèn)配置,結(jié)果出現(xiàn)一些摸不著頭腦的問題,例如下面這樣。

1. VRouter綁定的Port網(wǎng)卡qg-xxxxqr-xxxx都橋接在br-int

# ovs-vsctl show

···
Bridge br-int 
        Controller "tcp:127.0.0.1:6633"
            is_connected: true
        fail_mode: secure
        Port br-int
            Interface br-int
                type: internal
        Port "tapc68839ea-5f"
            tag: 1
            Interface "tapc68839ea-5f"
                type: internal
        Port "int-br-bo8eb174"
            Interface "int-br-bo8eb174"
                type: patch
                options: {peer="phy-br-bo8eb174"}
        Port "qg-c40e9517-79"
            Interface "qg-c40e9517-79"
                type: internal
        Port "qr-2ee3d6b2-2c"
            tag: 1
            Interface "qr-2ee3d6b2-2c"
                type: internal
···

結(jié)果發(fā)現(xiàn)一個(gè)隱藏的坑是external_network_bridge默認(rèn)配置項(xiàng)是空的,這導(dǎo)致router綁定都port都放在br-int下。

解決也很簡(jiǎn)單,如下配置就好了。

[DEFAULT]
external_network_bridge = br-ex

2. Router防火墻

由于開啟了防火墻,還要需要在L3的擴(kuò)展里面加上fwaas,如下:

[AGENT]
extensions=fwaas
虛擬Router

1. 創(chuàng)建NetWork

$ neutron net-create --provider:physical_network external --provider:network_type flat  --router:external=True --shared true external

2. 創(chuàng)建Subnet

tips:在公網(wǎng)IP資源稀缺情況下sunbet不要開啟dhcp,避免不必要的浪費(fèi)。

$ neutron subnet-create  --allocation-pool start=<公網(wǎng)起始IP>,end=<公網(wǎng)結(jié)束IP> --gateway <公網(wǎng)網(wǎng)關(guān)> --disable-dhcp PublicNetwork <公網(wǎng)CIDR>

3. 創(chuàng)建Router

$ neutron router-create  router

4. 設(shè)置Router網(wǎng)關(guān)

$ neutron router-gateway-set  ROUTER EXTERNAL-NET

這里external網(wǎng)絡(luò)可以綁定固定ip,只需要引入--fixed-ip subnet_id=SUBNET,ip_address=IP_ADDR就可以了。

5. Router綁定內(nèi)網(wǎng)Port

$ neutron router-interface-add  ROUTER PRIVETE-NET

完成以上工作就能在網(wǎng)絡(luò)節(jié)點(diǎn)的ovs和namespace中看到vrouter的信息了。

$ ip netns exec qdhcp-ade96f26-fbdd-4c6d-b705-069994609d1b ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
52: qg-c40e9517-79: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether fa:16:3e:75:64:72 brd ff:ff:ff:ff:ff:ff
    inet < External Gateway >/26 brd < External Boardcast > scope global qg-c40e9517-79   # < External Gateway > router綁定的一個(gè)公網(wǎng)ip,用于做SNAT
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe75:6472/64 scope link
       valid_lft forever preferred_lft forever
53: qr-2ee3d6b2-2c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether fa:16:3e:72:b8:41 brd ff:ff:ff:ff:ff:ff
    inet < Privetnet Gateway >/23 brd < Privetnet Boardcast > scope global qr-2ee3d6b2-2c    # < Privite Gateway > 內(nèi)網(wǎng)物理機(jī)網(wǎng)絡(luò)的一個(gè)網(wǎng)關(guān)
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe72:b841/64 scope link
       valid_lft forever preferred_lft forever
       
$ ip netns exec qdhcp-ade96f26-fbdd-4c6d-b705-069994609d1b ip r
default via < 公網(wǎng)網(wǎng)關(guān) > dev qg-c40e9517-79
浮動(dòng)IP

1. 創(chuàng)建浮動(dòng)IP

$ neutron floatingip-create EXTERNAL-NET

也可以手動(dòng)創(chuàng)建固定IP的,加入--fixed-ip-address參數(shù)即可。

2. 綁定浮動(dòng)IP到虛擬機(jī)

$ neutron floatingip-associate FLOATINGIP_ID VM_PORT

綁定成功后在Router的命名空間里面可以看到以下內(nèi)容:

$ ip netns exec qrouter-7d233b38-fca8-44c0-9752-9350589a0af1 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
52: qg-c40e9517-79: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether fa:16:3e:75:64:72 brd ff:ff:ff:ff:ff:ff
    inet < External Gateway >/26 brd < External Boradcast > scope global qg-c40e9517-79
       valid_lft forever preferred_lft forever
    inet < Floating IP >/32 brd < Floating Boradcast > scope global qg-c40e9517-79
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe75:6472/64 scope link
       valid_lft forever preferred_lft forever
53: qr-2ee3d6b2-2c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether fa:16:3e:72:b8:41 brd ff:ff:ff:ff:ff:ff
    inet < Privetnet Gateway >/23 brd < Privetnet Boardcast > scope global qr-2ee3d6b2-2c
       valid_lft forever preferred_lft forever
    inet6 fe80::f816:3eff:fe72:b841/64 scope link
       valid_lft forever preferred_lft forever

這里看到其實(shí)Floating IP是被綁定到qg-xxxx網(wǎng)卡上。我們都知道,浮動(dòng)IP是通過DNAT轉(zhuǎn)發(fā)到虛擬機(jī)實(shí)際的IP上。

接下來就看看iptables的規(guī)則

$ ip netns exec qrouter-7d233b38-fca8-44c0-9752-9350589a0af1 iptables -t nat -S

# Floating IP 出口流量的DNAT規(guī)則,
-A neutron-l3-agent-OUTPUT -d < Floating IP >/32 -j DNAT --to-destination < VM IP >

# 進(jìn)出qg-c40e9517-79網(wǎng)卡、狀態(tài)非NDAT的流量都通過
-A neutron-l3-agent-POSTROUTING ! -i qg-c40e9517-79 ! -o qg-c40e9517-79 -m conntrack ! --ctstate DNAT -j ACCEPT

# metadata的轉(zhuǎn)發(fā)流量,丟到本地9697端口處理
-A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697

# Floating IP 入口流量的DNAT規(guī)則,
-A neutron-l3-agent-PREROUTING -d < Floating IP >/32 -j DNAT --to-destination < VM IP >

# 接管虛擬機(jī)SNAT規(guī)則
-A neutron-l3-agent-float-snat -s < VM IP >/32 -j SNAT --to-source < External Gateway >

-A neutron-l3-agent-snat -j neutron-l3-agent-float-snat

# Privenetwork的SNAT規(guī)則
-A neutron-l3-agent-snat -o qg-c40e9517-79 -j SNAT --to-source < External Gateway >
-A neutron-l3-agent-snat -m mark ! --mark 0x2/0xffff -m conntrack --ctstate DNAT -j SNAT --to-source < External Gateway >
-A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat

折騰的地方

如果這樣就解決了,那也太簡(jiǎn)單,這篇文章也沒任何意義。

Floating IP不通

剛開始我以為綁定好Floating IP后,就能通過公網(wǎng)登錄虛擬機(jī)。不!其實(shí)是不通的。

問題的表象是:

1. 本地ping不通公網(wǎng)的< Floating IP >

2. 本地能ping通< External Gateway >

3. 在Router的NS里面也ping不通< Floating IP >

4. 在Router的NS里面能ping通公網(wǎng)的物理網(wǎng)關(guān)

1. 剛開始以為是ovs的創(chuàng)建的port問題,于是手動(dòng)通過ovs創(chuàng)建一個(gè)網(wǎng)卡綁定公網(wǎng)ip,發(fā)現(xiàn)問題不在于此。

過程如下:

# 創(chuàng)建ovs port
$ ovs-vsctl add-port br-ex test -- set interface test type=internal

# 創(chuàng)建測(cè)試namespaces
$ ip netns add teset
$ ip link set test netns test
$ ip netns exec test ip link set test up

# 配置公網(wǎng)ip和路由
$ ip addr add < 公網(wǎng)IP01/cidr > dev test 
$ ip router add default via < 公網(wǎng)網(wǎng)關(guān) > dev test 
$ ip addr add < 公網(wǎng)IP02>/32 dev test 

結(jié)果發(fā)現(xiàn)配置在test網(wǎng)卡上的公網(wǎng)IP01公網(wǎng)IP02都能在本地ping通,說明問題不在ovs的端口創(chuàng)建上。

2. 防火墻

在防火墻上創(chuàng)建了icmp的規(guī)則,仍然不通。

3. Router的iptables

我在這里清空了VRouter NS里的nat表,發(fā)現(xiàn)本地能夠ping通< Floating IP >了,說明本地到VRouter的ovs端口的鏈路是正常的,問題應(yīng)該出在轉(zhuǎn)發(fā)上。
于是恢復(fù)nat表規(guī)則,果然< Floating IP >又ping不通了。

4. 虛擬機(jī)抓包

在物理機(jī)上抓虛擬機(jī)網(wǎng)卡,發(fā)現(xiàn)ping < Floating IP >。虛擬機(jī)能夠響應(yīng)icmp請(qǐng)求。

18:45:42.098339 fa:16:3e:72:b8:41 > fa:16:3e:40:79:61, ethertype IPv4 (0x0800), length 98: <<本地公網(wǎng)ip>> > << 虛擬機(jī)ip >>: ICMP echo request, id 47876, seq 2, length 64
18:45:42.098554 fa:16:3e:40:79:61 > 48:7a:da:f6:ce:27, ethertype IPv4 (0x0800), length 98: << 虛擬機(jī)ip >> > <<本地公網(wǎng)ip>>: ICMP echo reply, id 47876, seq 2, length 64

這里看到了虛擬機(jī)reply了icmp的請(qǐng)求,但是我本地ping并沒有回包,說明問題出在了網(wǎng)關(guān)上。

5. 重置網(wǎng)關(guān)

問題已經(jīng)清楚了,虛擬機(jī)在回包的時(shí)候發(fā)到物理交換機(jī)的網(wǎng)關(guān)了,VRouter沒有收到回包,當(dāng)然ping不通了。解決這個(gè)問題比較簡(jiǎn)單。

在虛擬機(jī)里面把默認(rèn)網(wǎng)關(guān)指向router里的< Privetnet Gateway >,這個(gè)時(shí)候在本地到Floating IP的鏈路就通了。也可以通過ssh < Floating IP >登錄到虛擬機(jī)。

虛擬機(jī)內(nèi)網(wǎng)不通

雖然能夠通過Floating IP訪問虛擬機(jī)了,但是之前虛擬機(jī)的默認(rèn)網(wǎng)關(guān)在物理機(jī)交換機(jī)上,是和公司內(nèi)網(wǎng)打通的。由于虛擬機(jī)改了默認(rèn)網(wǎng)關(guān)到虛擬機(jī)路由器,而VRouter里面默認(rèn)網(wǎng)關(guān)是< 公網(wǎng)網(wǎng)關(guān) >,所以此時(shí)虛擬機(jī)網(wǎng)絡(luò)不通。
剛開始我有兩個(gè)解決思路是:

1. 通過iptables標(biāo)識(shí)來源報(bào)文,通過標(biāo)識(shí)轉(zhuǎn)發(fā)流量

  • 在虛擬機(jī)iptables的mangle表中INPUT chains里添加一個(gè)mark,不是內(nèi)網(wǎng)的cidr的報(bào)文通過是set-mark 10

  • 在虛擬機(jī)iptables的nat表中OUTPUT chins里匹配mark 10的報(bào)文,如果匹配這forward到< Privetnet Gateway >

這個(gè)方法開始我覺得理論上是可行的,但一直沒測(cè)試成功,便放棄了。

2. 通過snat隱藏公網(wǎng)ip

  • 在router命名空間的iptables里,將來源公網(wǎng)地址SNAT成< Privetnet Gateway >

這個(gè)方法可行,但是這樣對(duì)虛擬機(jī)來說就隱藏了來源的公網(wǎng)地址,這不符合我的需求,放棄了。

正確的解決思路

上面兩個(gè)方法我一開始就想多了,其實(shí)簡(jiǎn)單點(diǎn),直接通過路由方式就能滿足需求,但是需要引入人工配置,不太方便。

  • 在router的namespace里面創(chuàng)建靜態(tài)路由,匹配目的地址是內(nèi)網(wǎng)的,轉(zhuǎn)發(fā)到物理機(jī)的網(wǎng)關(guān)上。
neutron router-update router --routes type=dict list=true destination=< 內(nèi)網(wǎng)CIDR >,nexthop=< 物理交換機(jī)網(wǎng)關(guān) >

這樣虛擬機(jī)到內(nèi)網(wǎng)環(huán)境就通了,但是內(nèi)網(wǎng)到虛擬機(jī)仍然不通。

  • 將靜態(tài)路由配置在虛擬機(jī)里
vm $ ip router add < 內(nèi)網(wǎng)CIDR > via < 物理交換機(jī)網(wǎng)關(guān) > dev eth0

這樣虛擬機(jī)的內(nèi)網(wǎng)就打通了,同時(shí)公網(wǎng)的訪問就通過默認(rèn)的VRouter出去。

至此,虛擬機(jī)內(nèi)網(wǎng)和公網(wǎng)的網(wǎng)絡(luò)就打通了。

總結(jié)

這么蛋疼的網(wǎng)絡(luò)結(jié)構(gòu)主要原因是二層的網(wǎng)關(guān)引入了物理交換機(jī),造成VRouter綁定虛擬機(jī)網(wǎng)絡(luò)時(shí)不能夠充當(dāng)網(wǎng)關(guān)角色。

這個(gè)問題困擾我兩臺(tái),其實(shí)總結(jié)了下,有兩點(diǎn)需要人工干預(yù):

  1. 將虛擬機(jī)默認(rèn)網(wǎng)關(guān)指向VRouter
  2. 將虛擬機(jī)內(nèi)網(wǎng)路由到物理交換機(jī)網(wǎng)關(guān)

感想

由于在未引入DVR時(shí),Neutron的南北流量是通過網(wǎng)絡(luò)節(jié)點(diǎn)的router出去的,在大流量的情況下會(huì)成為瓶頸,所以在開始做OpenStack網(wǎng)絡(luò)規(guī)劃的時(shí)候就沒有考慮采用L3-Agent,這導(dǎo)致后來在做Floating IP的時(shí)候給自己挖了坑。

其實(shí)說白了,還是要看自己公司的網(wǎng)絡(luò)需求和網(wǎng)絡(luò)的運(yùn)維成本。

  • 如果只是將虛擬機(jī)接入公司內(nèi)部二層網(wǎng)絡(luò),采用ml2 vlan + 物理網(wǎng)關(guān)的方案是可以行。這種方案不好的地方就是在有上層的訪問策略需要人在交換機(jī)或路由器上配置,運(yùn)維成本高,但是優(yōu)點(diǎn)是簡(jiǎn)單。

  • 虛擬機(jī)網(wǎng)關(guān)采用l3 router也是可行的,代價(jià)是純軟件的router轉(zhuǎn)發(fā)效率沒有物理交換機(jī)高,同時(shí)會(huì)引入DVR和HA來解決南北向流量和高可用的問題,配置,架構(gòu)比較復(fù)雜。優(yōu)點(diǎn)也很明顯,運(yùn)維成本低,而且所有內(nèi)部網(wǎng)絡(luò)可控,Neutron提供豐富的上層訪問策略來限制網(wǎng)絡(luò),解放了人在交換機(jī)上的操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 第一章 OpenStack基礎(chǔ) OpenStack管理的資源及提供的服務(wù)OpenStack做為一個(gè)操作系統(tǒng),...
    sgt_tiger閱讀 13,054評(píng)論 4 72
  • 0 01、網(wǎng)絡(luò)管理的五大功能(包括每項(xiàng)功能的具體情況) 1.配置管理:ISO定義的管理功能域中,配置管理包括視圖管...
    哈熝少主閱讀 3,253評(píng)論 1 20
  • 練車 1.1開車前檢查 水,電,油。 1.1.1冷卻液,不足時(shí)要加滿,右邊備用,左邊刮水器。水管是否漏水。 1.1...
    育心經(jīng)典麗謙之家鐘永平閱讀 232評(píng)論 0 1
  • 此刻是6:10。我已經(jīng)起來喝了一杯溫蜂蜜水、準(zhǔn)備完煮粥,坐在電腦前開始碼字了。這是第一次,早起,心無旁騖的打開電腦...
    紅色的靴子閱讀 5,758評(píng)論 4 2
  • 背景 最近為了扛 DDoS 攻擊,從移動(dòng)公司申請(qǐng)了一臺(tái)服務(wù)器,移動(dòng)公司免費(fèi)提供流量清洗功能。但由于沒有備案,移動(dòng)公...
    onizuka_jp閱讀 480評(píng)論 0 0