前言
這篇我會從頭開始來過,要把原本前幾篇的 VM destroy 主要是要與上一篇環境做區隔,為的是要讓按照教學做,但是做爛不知道該怎麼處理的朋友另一個可以參考的方向。
Halt & Destroy VM
首先按下 Ctrl+D 登出 root 跟 Ubuntu 回到 Host 之後用 vagrant 指令關掉並且殺掉 VM
$ [host] vagrant halt
==> default: Attempting graceful shutdown of VM...
$ [host] vagrant destroy
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...
在這之後我們要先對 Vagrantfile 做一個調整,因為 Vagrant 登入預設是 Headless mode 靠 SSH 登入進去控制,但是我們將 Network Interface 加入 OVS bridge 會造成網路中斷 SSH 因此會不能用,因此這次不要使用 Headless mode,將 GUI 設為 True 即可。
重新啟動並登入另一個全新的 VM
這時候會有一個 Virtualbox 所開啟的 VM 視窗和原本的 Console ,先不需要去管 Virtualbox 所開啟的視窗,我們先透過原本的 Console 做一些設定。更改 root 密碼,原因是等一下會透過 Virtualbox 的視窗登入,又 Ubuntu 16.04之後已經沒有預設 Ubunut 的 root 密碼,所以我們先自己設定。
$ [host] vagrant up
$ [host] vagrant ssh$ [guest] sudo passwd root
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
操作概要(六步驟)
跟前一篇一樣,在詳細進入每個操作步驟之前,會先把全面性的概要操作方法列出來,才不會有種見樹不見林的感覺。
- 建立 OVS Bridge 名稱 ovsbr0
- 將 enp0s3 network interface 加入 OVS 的 port (此時 SSH 會中斷使用,切勿直接在 Vagrant ssh 操作,這邊會有一個 workaround)
- 移除 enp0s3 的網路設定,並設定 OVS Bridge ovsbr0 用 DHCP 來拿到 IP address
- 產生兩個 Containers 來當 Hosts
- 透過 ovs-docker/pipework 工具將 Containers attach 上 OVS Bridges
- 最後很重要 attach 進去 Containers 設定 Routing table 的 Default Gateway
SSH 進去 VM 之後 Network Stack 如圖一所示,第一步我們要透過 ovs-vsctl 指令來建立 OVS Bridge (記得要在 root 的身分)
$ sudo -s
$ ovs-vsctl add-br ovsbr0 #Create OVS bridge
$ ovs-vsctl show #Show bridge information
1054844d-7b25-4ec1-be12-2069fac0c03b
Bridge "ovsbr0"
Port "ovsbr0"
Interface "ovsbr0"
type: internal
ovs_version: "2.5.2"
在這個時候,我們的 Network Stack 如圖二所示,在這個時候我們還保持跟前一篇一樣的架構跟步驟。
第二步,因為將 enp0s3 network interface 加入 OVS 的 port 會造成網路中斷SSH 因此而不能用,這裡要透過剛剛啟動的 Virtualbox 視窗來控制 VM ,還記得剛剛有設定 Ubuntu 的 root password ,這裡務必要使用 root 及方才設定的 root password 在 Virtualbox的視窗登入之後再將 enp0s3 加入 OVS 的 port ! 可以透過 ovs-vsctl show 來看 enp0s3 有沒有被加入。
$ ovs-vsctl add-port ovsbr0 enp0s3
$ ovs-vsctl show #Show bridge information
1054844d-7b25-4ec1-be12-2069fac0c03b
Bridge "ovsbr0"
Port "ovsbr0"
Interface "ovsbr0"
type: internal
Port "enp0s3"
Interface "enp0s3"
ovs_version: "2.5.2"
此時沒有意外的話,網路會中斷可以試著 ping 外部網路,會發現不通。這時候 Network Stack 變成像圖三所示。很明顯的 IP Stack 現在那條線路已經接到 OVS bridge上所以網路暫時不通,我們現在嘗試著將封包從 OVS bridge forward 給 IP Stack。
第三步,來設定 OVS bridge ovsbr0 的 IP address,這樣一來封包會進去 ovsbr0 並透過 Bridge 的機制(L2 Switching 也就是 OpenFlow 的 NORMAL action)轉發到 IP Stack。首先清掉 enp0s3 上的網路設定,其次透過 dhclient獲取 OVS bridge ovsbr0 的 IP address 並另用 ifconfig 看看是否被分配到 IP,最後我們來確認一下 routing table 請記得 Gateway IP 等一下會用到,我們的Gateway IP 是 10.0.2.2。
$ ifconfig enp0s3 0 #remove enp0s3 configuration
$ dhclient ovsbr0
$ ifconfig ovsbr0
ubuntu@ubuntu-xenial:~$ ifconfig ovsbr0
ovsbr0 Link encap:Ethernet HWaddr fe:30:97:7b:d9:42
inet addr:10.0.2.16 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::fc30:97ff:fe7b:d942/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:57 errors:0 dropped:11 overruns:0 frame:0
TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:6741 (6.7 KB) TX bytes:6709 (6.7 KB)$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.2.2 0.0.0.0 UG 0 0 0 ovsbr0
10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 ovsbr0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
到這邊我們可以暫別 Virtualbox 的難用視窗,透過 Terminal 直接在使用 Vagrant ssh 連線回去,並用 root 登入。視窗就先擺著不需要把他關掉。此時我們的 Network Stack會變成如圖四所示。紅色的箭頭線是邏輯的表示網路可以連通。
$ vagrant ssh #Back to VM through SSH
$ sudo -i #Login as root
第四步,產生兩個 Containers 來當作 Hosts,跟上一篇一樣透過 docker 指令,加入兩個 containers
$ docker pull busybox$ docker run --name=container1 --cap-add=NET_ADMIN --net='none' -itd busybox /bin/sh$ docker run --name=container2 --cap-add=NET_ADMIN --net='none' -itd busybox /bin/sh
幾個 options 可以看上一篇或是不了解可以去查 docker 官方指南。
第五步,透過 ovs-docker 工具將 Containers attach 上 OVS Bridges,這邊選用的工具是 ovs-docker,特別注意我們這邊 IP 選的範圍刻意挑在跟 Gateway 10.0.2.2 同一個網段。
$ ovs-docker add-port ovsbr0 eth0 container1 --ipaddress=10.0.2.10/24$ ovs-docker add-port ovsbr0 eth0 container2 --ipaddress=10.0.2.20/24
第六步,attach 進去 containers 設定,每一個container 的 routing table 的 default gateway 還記得前面在 ubuntu 裡面查到的 gateway IP 是 10.0.2.2 透過 tmux 開起一個 session 進去 container
$ docker attach d5475514cada
$ / ifconfig eth0
eth0 Link encap:Ethernet HWaddr 7A:73:01:04:26:5C
inet addr:10.0.2.10 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)$ / route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
這時候我們用 route -n 會看到少了 default gateway,透過 route add 將default gateway 加回去。然後 ping 看看外部就會發現可以通了。
/ $ route add default gw 10.0.2.2
/ $ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.0.2.2 0.0.0.0 UG 0 0 0 eth0
10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
/ $ ping www.google.com
PING www.google.com (108.177.97.106): 56 data bytes
64 bytes from 108.177.97.106: seq=0 ttl=43 time=127.659 ms
64 bytes from 108.177.97.106: seq=1 ttl=43 time=6.647 ms
64 bytes from 108.177.97.106: seq=2 ttl=43 time=6.512 ms
64 bytes from 108.177.97.106: seq=3 ttl=43 time=6.653 ms
此時 Network Stack 會變成如圖五所示,這個時候就成功的打造出一個 vSwitch 在內部每個 containers 都會透過這個 vSwitch 去做封包轉發,在加上 SDN Controller 就是一套完整 虛擬的「真實 SDN 網路」。
結語
最後我想認真看完這幾篇的朋友們,不知道有沒有什麼問題?可以直接留言在下面問。目前大家看到的都是只有一個 VM 未來我會用 Multiple VMs 來做 GRE Tunneling 和 VXLAN 的環境,對 GRE 或 VXLAN 有興趣也可以一起討論。
此外有收到一些朋友在詢問,是不是可以把 OVS 底層抽換 DPDK ?
事實上官方就有教學指引,重編譯加入 OVS 絕對沒問題,OVS 會需要重新編譯,再帶入 DPDK 的參數重編一次就可以,但其實講雖然簡單,做沒那麼容易有機會在另外發幾篇重編譯 OVS 的文章讓大家參考。
認真地說這個環境可以嘗試運用到商業佈署上,透過 Docker 的特性和 SDN 的彈性絕對可以創造出無限的可能,歡迎業界朋友對於佈署有任何客制化的問題不方便公開說,可以私底下來信來問我的 Email 很好找到:)。